dsh-deeppilot 0.6.0 → 0.6.2
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/COMPATIBILITY.md +4 -4
- package/PRIVACY.md +23 -1
- package/README.md +19 -19
- package/README.zh-CN.md +17 -17
- package/lib/client.js +31 -6
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +102 -2
- package/lib/index.js +785 -23
- package/lib/index.js.map +1 -1
- package/package.json +16 -16
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["record","cryptoSign","http2Connect","fsConstants","httpsRequest"],"sources":["../src/device-auth.ts","../src/token.ts","../src/connection-policy.ts","../src/connection.ts","../src/host-api.ts","../src/document-payload.ts","../src/host-event-projection.ts","../src/host-bridge.ts","../src/dsh012-remote-interactions.ts","../src/dsh012-api-proxy.ts","../src/report-service.ts","../src/report-wire.ts","../src/report-remote.ts","../src/relay-url.ts","../src/relay-test.ts","../src/apns.ts","../src/relay-client.ts","../src/funnel-policy.ts","../src/remote-supervisor.ts","../src/local-address.ts","../src/update-check.ts","../src/local-policy.ts","../src/config.ts","../src/phone-http.ts","../src/auth-rate-limit.ts","../src/push-policy.ts","../src/phone-server.ts","../src/index.ts"],"sourcesContent":["import {\n createHash,\n createPublicKey,\n randomBytes,\n timingSafeEqual,\n verify,\n type KeyObject,\n} from 'node:crypto'\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\nexport function getPairingCodeTtlMs(): number {\n return Number(process.env.DEEPPILOT_PAIRING_TTL_MS) || 5 * 60_000\n}\nexport const AUTH_CHALLENGE_TTL_MS = 30_000\n\nexport const DEVICE_SCOPES = [\n 'sessions.read',\n 'prompt.send',\n 'sessions.manage',\n 'interactions.respond',\n 'notifications.register',\n] as const\n\nexport type DeviceScope = (typeof DEVICE_SCOPES)[number]\n\nexport const DEFAULT_DEVICE_SCOPES: readonly DeviceScope[] = DEVICE_SCOPES\n\nexport interface PairingGrant {\n code: string\n expiresAt: number\n audience?: string\n}\n\nexport async function loadOrCreateHostAudience(path: string): Promise<string> {\n try {\n const existing = (await readFile(path, 'utf8')).trim()\n if (/^deeppilot:[A-Za-z0-9_-]{22}$/.test(existing)) return existing\n throw new Error(`host audience is malformed at ${path}`)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n const audience = 'deeppilot:' + randomBytes(16).toString('base64url')\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, audience + '\\n', { mode: 0o600 })\n return audience\n}\n\nexport interface AuthChallenge {\n nonce: string\n audience: string\n issuedAt: number\n expiresAt: number\n}\n\nexport interface AuthProofFields extends AuthChallenge {\n deviceId: string\n deviceName: string\n appVersion: string\n resumeCursor?: number\n}\n\nfunction b64urlText(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64url')\n}\n\n/**\n * Cross-language signature input. Text fields are base64url encoded before\n * joining so names cannot create ambiguous separators. Decimal timestamps\n * and cursor values are finite integers, or `-` when the cursor is absent.\n */\nexport function canonicalAuthChallenge(fields: AuthProofFields): Buffer {\n const cursor = fields.resumeCursor === undefined ? '-' : String(fields.resumeCursor)\n return Buffer.from([\n 'deeppilot-auth-v2',\n `device-id:${b64urlText(fields.deviceId)}`,\n `nonce:${fields.nonce}`,\n `audience:${b64urlText(fields.audience)}`,\n `issued-at:${fields.issuedAt}`,\n `expires-at:${fields.expiresAt}`,\n `device-name:${b64urlText(fields.deviceName)}`,\n `app-version:${b64urlText(fields.appVersion)}`,\n `resume-cursor:${cursor}`,\n ].join('\\n'), 'utf8')\n}\n\n/** Accept only an uncompressed ANSI X9.63 P-256 public key (65 bytes). */\nexport function parseP256PublicKey(encoded: string): { key: KeyObject; raw: Buffer } {\n const raw = Buffer.from(encoded, 'base64url')\n if (raw.length !== 65 || raw[0] !== 0x04) {\n throw new TypeError('publicKey must be an uncompressed P-256 X9.63 key')\n }\n // SubjectPublicKeyInfo prefix for id-ecPublicKey / prime256v1 followed by\n // the 65-byte uncompressed point.\n const spkiPrefix = Buffer.from('3059301306072a8648ce3d020106082a8648ce3d030107034200', 'hex')\n const key = createPublicKey({ key: Buffer.concat([spkiPrefix, raw]), format: 'der', type: 'spki' })\n if (key.asymmetricKeyType !== 'ec' || key.asymmetricKeyDetails?.namedCurve !== 'prime256v1') {\n throw new TypeError('publicKey must use P-256')\n }\n return { key, raw }\n}\n\nexport function deviceIdForPublicKey(publicKey: string): string {\n const { raw } = parseP256PublicKey(publicKey)\n return createHash('sha256').update(raw).digest('base64url')\n}\n\nexport function fingerprintForPublicKey(publicKey: string): string {\n const { raw } = parseP256PublicKey(publicKey)\n return createHash('sha256').update(raw).digest('hex')\n}\n\nexport function verifyAuthProof(publicKey: string, fields: AuthProofFields, signature: string): boolean {\n try {\n const { key } = parseP256PublicKey(publicKey)\n const der = Buffer.from(signature, 'base64url')\n if (der.length < 64 || der.length > 80) return false\n return verify('sha256', canonicalAuthChallenge(fields), key, der)\n } catch {\n return false\n }\n}\n\nexport function normalizeDeviceScopes(value: unknown): DeviceScope[] {\n if (!Array.isArray(value)) return [...DEFAULT_DEVICE_SCOPES]\n const allowed = new Set<string>(DEVICE_SCOPES)\n return [...new Set(value.filter((scope): scope is DeviceScope => typeof scope === 'string' && allowed.has(scope)))]\n}\n\n/** One active, single-use pairing grant per plugin runtime. */\nexport class PairingCodeManager {\n private active: PairingGrant | null = null\n\n issue(now = Date.now()): PairingGrant {\n const grant = {\n code: randomBytes(24).toString('base64url'),\n expiresAt: now + getPairingCodeTtlMs(),\n }\n this.active = grant\n return { ...grant }\n }\n\n consume(presented: string, now = Date.now()): boolean {\n const active = this.active\n if (active === null || now > active.expiresAt) {\n this.active = null\n return false\n }\n const expected = Buffer.from(active.code)\n const actual = Buffer.from(presented)\n const matches = expected.length === actual.length && timingSafeEqual(expected, actual)\n if (matches) this.active = null\n return matches\n }\n\n invalidate(): void {\n this.active = null\n }\n}\n\nexport function createAuthChallenge(audience: string, now = Date.now()): AuthChallenge {\n return {\n nonce: randomBytes(24).toString('base64url'),\n audience,\n issuedAt: now,\n expiresAt: now + AUTH_CHALLENGE_TTL_MS,\n }\n}\n","import { randomBytes } from 'node:crypto'\nimport { access, chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, resolve } from 'node:path'\nimport {\n deviceIdForPublicKey,\n fingerprintForPublicKey,\n normalizeDeviceScopes,\n type DeviceScope,\n} from './device-auth.ts'\n\n/** Expand a leading ~ using the process home directory. */\nexport function expandHome(p: string): string {\n if (p === '~') return homedir()\n if (p.startsWith('~/')) return resolve(homedir(), p.slice(2))\n return p\n}\n\nfunction dshDataRoot(): string {\n const dshHome = process.env.DSH_HOME\n if (dshHome && dshHome.trim().length > 0) return resolve(dshHome.trim())\n return resolve(homedir(), '.dsh')\n}\n\n/** DeepPilot data directory: under $DSH_HOME when set, else ~/.dsh. */\nexport function bridgeDataDir(): string {\n return resolve(dshDataRoot(), 'deeppilot')\n}\n\n/** Create or repair the canonical secret-bearing directory as owner-only. */\nexport async function ensurePrivateBridgeDataDir(): Promise<string> {\n const target = bridgeDataDir()\n await mkdir(target, { recursive: true, mode: 0o700 })\n await chmod(target, 0o700)\n return target\n}\n\n/**\n * Move the pre-DeepPilot data directory as one atomic directory rename.\n * Existing canonical data always wins; secrets are never merged or replaced.\n */\nexport async function migrateLegacyBridgeDataDir(): Promise<string | null> {\n const target = bridgeDataDir()\n try {\n await access(target)\n return null\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n\n const legacy = resolve(dshDataRoot(), 'pocket-bridge')\n try {\n await rename(legacy, target)\n return legacy\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null\n throw error\n }\n}\n\nexport type ApnsEnvironment = 'development' | 'production'\n\n/** Per-device APNs registration (F-9 离线推送). The raw token never leaves the registry file. */\nexport interface DeviceApnsInfo {\n /** Hex device token, lowercased, 32–512 chars. */\n token: string\n environment: ApnsEnvironment\n updatedAt: number\n /** Per-category opt-out mirror; absent keys mean enabled. */\n categories?: Record<string, boolean>\n}\n\nexport interface DeviceRecord {\n deviceId: string\n deviceName: string\n appVersion: string\n /** Uncompressed P-256 X9.63 public key, base64url encoded. */\n publicKey?: string\n /** SHA-256 fingerprint of publicKey, hex encoded for local display. */\n fingerprint?: string\n scopes?: DeviceScope[]\n revokedAt?: number\n firstSeenTs: number\n lastSeenTs: number\n apns?: DeviceApnsInfo\n}\n\n/** Hex shape of an APNs device token as delivered by iOS (usually 64 chars). */\nconst APNS_TOKEN_PATTERN = /^[0-9a-f]{32,512}$/\n\nexport function isValidApnsToken(token: unknown): token is string {\n return typeof token === 'string' && APNS_TOKEN_PATTERN.test(token)\n}\n\n/** Registry row cap: hello spam with fresh ids must not grow the file forever. */\nexport const MAX_DEVICES = 64\n\n/**\n * Paired-device registry persisted as one JSON document. Whole-document\n * writes (serialized, never interleaved); a corrupt file falls back to an\n * empty registry rather than failing the plugin.\n */\nexport class DeviceStore {\n private devices = new Map<string, DeviceRecord>()\n private flushTail: Promise<void> = Promise.resolve()\n\n private constructor(private readonly filePath: string) {}\n\n static async load(filePath: string): Promise<DeviceStore> {\n const store = new DeviceStore(filePath)\n try {\n const raw = JSON.parse(await readFile(expandHome(filePath), 'utf8')) as {\n devices?: DeviceRecord[]\n }\n for (const rec of raw.devices ?? []) {\n if (typeof rec.deviceId === 'string') store.devices.set(rec.deviceId, rec)\n }\n } catch (error) {\n const code = (error as NodeJS.ErrnoException)?.code\n if (code === 'ENOENT') {\n // First run on this home: nothing registered yet — normal.\n } else {\n // A truncated/corrupt registry silently wiping pairings and push\n // registrations would be indistinguishable from \"never registered\".\n // Make data loss loud so the cause (crash mid-write, disk, …) shows.\n console.log('[deeppilot] device registry unreadable, starting empty: ' + String(error))\n }\n }\n return store\n }\n\n /** Register one public key after a valid, single-use pairing grant. */\n register(\n record: { publicKey: string; deviceName: string; appVersion: string; scopes?: unknown },\n now: number,\n ): DeviceRecord {\n const deviceId = deviceIdForPublicKey(record.publicKey)\n const existing = this.devices.get(deviceId)\n if (!existing && this.devices.size >= MAX_DEVICES) {\n throw new Error('device registry is full')\n }\n const next: DeviceRecord = {\n deviceId,\n deviceName: record.deviceName,\n appVersion: record.appVersion,\n publicKey: record.publicKey,\n fingerprint: fingerprintForPublicKey(record.publicKey),\n scopes: normalizeDeviceScopes(record.scopes),\n firstSeenTs: existing?.firstSeenTs ?? now,\n lastSeenTs: now,\n ...(existing?.apns ? { apns: existing.apns } : {}),\n }\n this.devices.set(deviceId, next)\n void this.flush()\n return structuredClone(next)\n }\n\n /** Return an active cryptographic identity. */\n authorized(deviceId: string): DeviceRecord | undefined {\n const record = this.devices.get(deviceId)\n if (!record?.publicKey || record.revokedAt !== undefined) return undefined\n return record\n }\n\n markAuthenticated(deviceId: string, deviceName: string, appVersion: string, now: number): void {\n const record = this.authorized(deviceId)\n if (!record) return\n record.deviceName = deviceName || record.deviceName\n record.appVersion = appVersion || record.appVersion\n record.lastSeenTs = now\n void this.flush()\n }\n\n revoke(deviceId: string, now: number): boolean {\n const record = this.devices.get(deviceId)\n if (!record || record.revokedAt !== undefined) return false\n record.revokedAt = now\n delete record.apns\n void this.flush()\n return true\n }\n\n setScopes(deviceId: string, scopes: unknown): DeviceScope[] | null {\n const record = this.authorized(deviceId)\n if (!record) return null\n record.scopes = normalizeDeviceScopes(scopes)\n void this.flush()\n return [...record.scopes]\n }\n\n list(): DeviceRecord[] {\n return [...this.devices.values()].map((record) => structuredClone(record))\n }\n\n /**\n * Store (or refresh) the APNs registration of a paired device. Idempotent:\n * an unchanged registration does not rewrite the registry file, so the\n * app's re-register-on-every-handshake policy stays write-quiet.\n */\n setPushToken(\n deviceId: string,\n token: string,\n environment: ApnsEnvironment,\n categories: Record<string, boolean> | undefined,\n now: number,\n ): void {\n const normalized = token.toLowerCase()\n if (!isValidApnsToken(normalized)) return\n const record = this.authorized(deviceId)\n if (!record) return\n const next: DeviceApnsInfo = { token: normalized, environment, updatedAt: now }\n if (categories && typeof categories === 'object') {\n const clean: Record<string, boolean> = {}\n for (const [key, value] of Object.entries(categories)) {\n if (/^[a-z.]{1,64}$/.test(key) && typeof value === 'boolean') clean[key] = value\n }\n if (Object.keys(clean).length > 0) next.categories = clean\n }\n const current = record.apns\n if (\n current &&\n current.token === next.token &&\n current.environment === next.environment &&\n JSON.stringify(current.categories ?? {}) === JSON.stringify(next.categories ?? {})\n ) {\n return\n }\n record.apns = next\n void this.flush()\n }\n\n /** Drop a device's APNs registration (APNs reported the token unregistered). */\n clearPushToken(deviceId: string): void {\n const record = this.devices.get(deviceId)\n if (!record?.apns) return\n delete record.apns\n void this.flush()\n }\n\n /** Serialized so concurrent touches can never interleave half-written JSON. */\n private flush(): Promise<void> {\n const next = this.flushTail.then(() => this.writeFile())\n this.flushTail = next.catch(() => {\n // best-effort persistence; the bridge still works without it\n })\n return next\n }\n\n /** Resolves once every queued registry write has landed (test support). */\n async drain(): Promise<void> {\n await this.flushTail\n }\n\n private async writeFile(): Promise<void> {\n const full = expandHome(this.filePath)\n const body = JSON.stringify(\n { version: 2, devices: this.list() },\n null,\n 2,\n )\n try {\n await mkdir(dirname(full), { recursive: true })\n // Atomic replace: a restart mid-write previously left a truncated JSON\n // behind, which load() treats as corrupt and drops ENTIRELY — losing\n // pairings and push registrations on every unlucky shutdown.\n const temp = `${full}.${randomBytes(6).toString('hex')}.tmp`\n await writeFile(temp, body + '\\n', { mode: 0o600 })\n await rename(temp, full)\n } catch {\n // best-effort persistence; the bridge still works without it\n }\n }\n}\n","import type { DeviceScope } from './device-auth.ts'\n\nexport const AUTH_TIMEOUT_MS = 35_000\nexport const MAX_OUTBOUND_BUFFER_BYTES = 4 * 1024 * 1024\n/**\n * Pre-auth frame cap. The 64 MiB cap on a fully authenticated socket exists\n * to support multi-MB image attachments; before hello the only legal frames\n * are c2s.ping and c2s.auth.prove, neither of which can legitimately exceed\n * a few KB. Capping unauthenticated frames at 64 KiB keeps an anonymous TCP\n * peer from forcing expensive JSON.parse work on a 64 MiB payload inside\n * the 5-second auth window.\n */\nexport const PRE_AUTH_FRAME_BYTES = 64 * 1024\nexport const IMAGE_MEDIA_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp', 'image/gif'])\nexport const MAX_PROMPT_IMAGES = 4\nexport const MAX_BASE64_CHARS_PER_IMAGE = 8 * 1024 * 1024\nexport const MAX_PROMPT_DOCUMENTS = 4\nexport const MAX_DOCUMENT_TEXT_CHARS = 256 * 1024\nexport const MAX_DOCUMENT_NAME_CHARS = 180\nexport const MAX_DOCUMENT_MEDIA_TYPE_CHARS = 120\n/** Bounds a single prompt's text; the frame itself is capped by ws maxPayload. */\nexport const MAX_PROMPT_TEXT_CHARS = 256 * 1024\n// Client-supplied identity fields land in logs and devices-v2.json — keep them\n// short and free of control characters so they can neither flood the registry\n// nor forge log lines.\nexport const MAX_DEVICE_ID_CHARS = 128\nexport const MAX_DEVICE_NAME_CHARS = 64\nexport const MAX_APP_VERSION_CHARS = 32\n\nexport function sanitizeDeviceField(value: unknown, maxChars: number): string {\n const raw = typeof value === 'string' ? value : String(value ?? '')\n return raw.replace(/[\\u0000-\\u001f\\u007f]/g, ' ').trim().slice(0, maxChars)\n}\n\nexport function requiredScope(type: string): DeviceScope | undefined {\n if (type === 'c2s.ping' || type === 'c2s.resume') return undefined\n if (type === 'c2s.session.sendPrompt') return 'prompt.send'\n if (type === 'c2s.approval.respond' || type === 'c2s.question.respond') return 'interactions.respond'\n if (type === 'c2s.push.register') return 'notifications.register'\n if (\n type === 'c2s.workspace.create' ||\n type === 'c2s.session.create' ||\n type === 'c2s.session.rename' ||\n type === 'c2s.session.archive' ||\n type === 'c2s.session.cancel' ||\n type === 'c2s.session.selectModel'\n ) return 'sessions.manage'\n if (type.startsWith('c2s.')) return 'sessions.read'\n return undefined\n}\n\nexport function sanitizeImageName(value: string): string {\n return value.replace(/[\\u0000-\\u001F\\u007F]/g, '').trim().slice(0, 120)\n}\n\nexport function sanitizeDocumentField(value: string, maxChars: number): string {\n return value.replace(/[\\u0000-\\u001F\\u007F]/g, ' ').trim().slice(0, maxChars)\n}\n\nexport const ERROR_CODES = {\n E_AUTH: 'device proof missing or invalid',\n E_FORBIDDEN: 'device scope does not allow this operation',\n E_PROTOCOL: 'unknown type or malformed payload',\n E_NOT_FOUND: 'session or request not found',\n E_BUSY: 'session is busy',\n E_UNSUPPORTED: 'protocol version or capability unsupported',\n E_INTERNAL: 'internal error',\n} as const\n\n/** Error code for a failed approval/question response outcome. */\nexport function pendingResponseErrorCode(reason: 'not-pending' | 'bad-response' | 'transport'): keyof typeof ERROR_CODES {\n switch (reason) {\n case 'not-pending': return 'E_NOT_FOUND'\n // The host refused the answer batch (shape/labels mismatch) — a client\n // payload problem, not a missing pending request.\n case 'bad-response': return 'E_PROTOCOL'\n case 'transport': return 'E_INTERNAL'\n }\n}\n\n/** Human-readable failure detail; `question not pending` must only ever mean\n * \"nothing pending\", never \"the host rejected the answer\". */\nexport function pendingResponseMessage(\n kind: 'approval' | 'question',\n reason: 'not-pending' | 'bad-response' | 'transport',\n): string {\n switch (reason) {\n case 'not-pending': return kind + ' not pending'\n case 'bad-response': return kind + ' answer rejected by host: answer does not match the asked questions'\n case 'transport': return 'host connection failed while answering ' + kind\n }\n}\n\nexport function managementErrorCode(\n kind: 'unsupported' | 'not-found' | 'busy' | 'invalid' | 'internal',\n): keyof typeof ERROR_CODES {\n switch (kind) {\n case 'unsupported': return 'E_UNSUPPORTED'\n case 'not-found': return 'E_NOT_FOUND'\n case 'busy': return 'E_BUSY'\n case 'invalid': return 'E_PROTOCOL'\n case 'internal': return 'E_INTERNAL'\n }\n}\n","import type { WebSocket } from 'ws'\nimport {\n PROTOCOL_VERSION,\n} from './protocol.ts'\nimport type { AuthProofPayload, Envelope } from './protocol.ts'\nimport type { BridgeSink, HostBridge } from './host-bridge.ts'\nimport type { DeviceStore, ApnsEnvironment } from './token.ts'\nimport { isValidApnsToken } from './token.ts'\nimport {\n createAuthChallenge,\n verifyAuthProof,\n type AuthChallenge,\n type DeviceScope,\n} from './device-auth.ts'\nimport {\n AUTH_TIMEOUT_MS,\n ERROR_CODES,\n IMAGE_MEDIA_TYPES,\n MAX_APP_VERSION_CHARS,\n MAX_BASE64_CHARS_PER_IMAGE,\n MAX_DOCUMENT_MEDIA_TYPE_CHARS,\n MAX_DOCUMENT_NAME_CHARS,\n MAX_DOCUMENT_TEXT_CHARS,\n MAX_DEVICE_ID_CHARS,\n MAX_DEVICE_NAME_CHARS,\n MAX_OUTBOUND_BUFFER_BYTES,\n MAX_PROMPT_IMAGES,\n MAX_PROMPT_DOCUMENTS,\n MAX_PROMPT_TEXT_CHARS,\n PRE_AUTH_FRAME_BYTES,\n managementErrorCode,\n pendingResponseErrorCode,\n pendingResponseMessage,\n sanitizeDeviceField,\n sanitizeImageName,\n sanitizeDocumentField,\n requiredScope,\n} from './connection-policy.ts'\n\nexport {\n AUTH_TIMEOUT_MS,\n MAX_OUTBOUND_BUFFER_BYTES,\n PRE_AUTH_FRAME_BYTES,\n} from './connection-policy.ts'\n\n\nexport interface ConnectionStateDeps {\n bridge: HostBridge\n devices: DeviceStore\n serverVersion: string\n /** Stable Host identity included in every signed challenge. */\n audience: string\n debug?: boolean\n log: (message: string) => void\n /** Called once when the socket closes (cleanly or not). */\n onClosed?: (connection: BridgeConnection) => void\n /** Releases an unauthenticated connection slot and updates failure state. */\n onAuthenticationSettled?: (ok: boolean, reason: 'success' | 'invalid-proof' | 'timeout' | 'closed') => void\n /** Emits a privacy-preserving audit event after a valid hello. */\n onDeviceAuthenticated?: (deviceId: string) => void\n /**\n * Zero-touch push enrollment: fired when a distributed app presents the\n * distributor's shared enrollKey during c2s.push.register. May perform the\n * relay round-trip; the register handler awaits it before evaluating push\n * readiness, so the very first registration can switch the feature on.\n */\n onPushEnrollKey?: (enrollKey: string) => Promise<void> | void\n}\n\n\n/**\n * One connected phone. Implements BridgeSink so the HostBridge can push\n * projected frames and replays. Every socket starts anonymous, receives one\n * server challenge, and must prove possession of a registered P-256 key.\n */\nexport class BridgeConnection implements BridgeSink {\n private authenticated = false\n private authenticationSettled = false\n private closed = false\n private helloTimer: NodeJS.Timeout | undefined\n private readonly openSessions = new Set<string>()\n /**\n * Realtime events that arrive while a session's history snapshot is in\n * flight. The wire contract requires tail first; sending these immediately\n * lets the later tail roll the client back over messages it just rendered.\n */\n private readonly openingSessionEvents = new Map<string, Array<{\n type: string\n payload: unknown\n seq?: number\n }>>()\n /** Sanitized device identity from hello; needed for push registration. */\n private deviceId: string | undefined\n private scopes = new Set<DeviceScope>()\n private readonly authChallenge: AuthChallenge\n\n constructor(\n private readonly ws: WebSocket,\n private readonly deps: ConnectionStateDeps,\n ) {\n this.authChallenge = createAuthChallenge(deps.audience)\n ws.on('message', (data) => {\n void this.onMessage(String(data))\n })\n ws.on('close', () => {\n this.onClose()\n deps.onClosed?.(this)\n })\n ws.on('error', () => {\n /* close follows */\n })\n this.helloTimer = setTimeout(() => {\n if (!this.authenticated) {\n this.settleAuthentication(false, 'timeout')\n this.close(4402, 'auth timeout')\n }\n }, AUTH_TIMEOUT_MS)\n this.helloTimer.unref()\n this.send('s2c.auth.challenge', this.authChallenge)\n }\n\n /** Hard-drop the socket (server-side stale sweep). */\n terminate(): void {\n this.ws.terminate()\n }\n\n /** Protocol-compliant idle timeout: let the peer observe a normal 1001 close. */\n closeIdle(): void {\n this.close(1001, 'idle timeout')\n }\n\n /** Announce an orderly plugin/data-plane shutdown before closing the socket. */\n closeForServerStop(): void {\n this.fail(undefined, 'E_INTERNAL', 'server stopping')\n this.close(1001, 'server stopping')\n }\n\n /** Used by dependency-lifecycle cleanup to avoid closing a replacement bridge. */\n isAttachedTo(bridge: HostBridge): boolean {\n return this.deps.bridge === bridge\n }\n\n /** Device identity once hello succeeded; undefined before that. */\n get connectedDeviceId(): string | undefined {\n return this.authenticated ? this.deviceId : undefined\n }\n\n // ---------- BridgeSink ----------\n\n push(type: string, payload: unknown, seq?: number): void {\n if (type === 's2c.session.event') {\n const sessionId = (payload as { sessionId?: unknown } | undefined)?.sessionId\n if (typeof sessionId === 'string') {\n const buffered = this.openingSessionEvents.get(sessionId)\n if (buffered) {\n buffered.push({ type, payload, ...(seq !== undefined ? { seq } : {}) })\n return\n }\n }\n }\n if (this.deps.debug === true) this.deps.log('push ' + type + ' seq=' + String(seq))\n this.send(type, payload, undefined, seq)\n }\n\n replay(entries: Array<{ seq: number; type: string; payload: unknown }>): void {\n for (const entry of entries) this.push(entry.type, entry.payload, entry.seq)\n }\n\n replayDone(): void {\n this.push('s2c.resume.done', {})\n }\n\n resync(): void {\n this.push('s2c.resync', { reason: 'gap' })\n }\n\n lastCursor(): number {\n return this.deps.bridge.currentCursor()\n }\n\n // ---------- lifecycle ----------\n\n private onClose(): void {\n if (this.closed) return\n this.closed = true\n if (!this.authenticationSettled) this.settleAuthentication(false, 'closed')\n if (this.helloTimer !== undefined) clearTimeout(this.helloTimer)\n for (const id of this.openSessions) {\n this.deps.bridge.markSinkClosed(this, id)\n }\n this.openSessions.clear()\n this.openingSessionEvents.clear()\n this.deps.bridge.dropSinkSessions(this)\n if (this.authenticated) this.deps.bridge.removeSink(this)\n }\n\n private settleAuthentication(ok: boolean, reason: 'success' | 'invalid-proof' | 'timeout' | 'closed'): void {\n if (this.authenticationSettled) return\n this.authenticationSettled = true\n this.deps.onAuthenticationSettled?.(ok, reason)\n }\n\n private close(code: number, reason: string): void {\n if (this.closed) return\n try {\n this.ws.close(code, reason)\n } catch {\n this.ws.terminate()\n }\n }\n\n private send(type: string, payload: unknown, id?: string, seq?: number): void {\n const envelope: Envelope = {\n v: PROTOCOL_VERSION,\n type,\n ts: Date.now(),\n ...(id !== undefined ? { id } : {}),\n ...(seq !== undefined ? { seq } : {}),\n payload,\n }\n if (this.ws.readyState !== this.ws.OPEN) return\n if (this.ws.bufferedAmount > MAX_OUTBOUND_BUFFER_BYTES) {\n this.close(1013, 'client too slow')\n return\n }\n this.ws.send(JSON.stringify(envelope))\n }\n\n private fail(id: string | undefined, code: keyof typeof ERROR_CODES, message: string): void {\n this.send('s2c.error', { code, message }, id)\n }\n\n // ---------- dispatch ----------\n\n private lastActivity = Date.now()\n\n /** True when no inbound frame arrived within maxIdleMs. */\n isStale(now: number, maxIdleMs: number): boolean {\n return now - this.lastActivity > maxIdleMs\n }\n\n private async onMessage(raw: string): Promise<void> {\n this.lastActivity = Date.now()\n // Cheap length guard before the JSON parse: pre-auth frames are tiny\n // (hello/ping), so anything over 64 KiB is either junk or an attempt\n // to make us spend CPU before the auth deadline. Reject without\n // trying to parse, so the cost is just the length check.\n if (!this.authenticated && raw.length > PRE_AUTH_FRAME_BYTES) {\n this.close(1009, 'pre-auth frame too large')\n return\n }\n let env: Envelope\n try {\n env = JSON.parse(raw) as Envelope\n } catch {\n this.fail(undefined, 'E_PROTOCOL', 'frame is not valid JSON')\n return\n }\n if (env.v !== PROTOCOL_VERSION) {\n this.fail(env.id, 'E_UNSUPPORTED', 'unsupported protocol version')\n this.close(4500, 'protocol version mismatch')\n return\n }\n if (!this.authenticated) {\n if (env.type === 'c2s.ping') {\n this.send('s2c.pong', { serverTime: Date.now() }, env.id)\n return\n }\n if (env.type === 'c2s.auth.prove') {\n await this.prove(env)\n return\n }\n this.fail(env.id, 'E_PROTOCOL', 'authenticate first')\n return\n }\n const required = requiredScope(env.type)\n if (required !== undefined && !this.scopes.has(required)) {\n this.fail(env.id, 'E_FORBIDDEN', `scope ${required} required`)\n return\n }\n switch (env.type) {\n case 'c2s.ping': {\n this.send('s2c.pong', { serverTime: Date.now() }, env.id)\n return\n }\n case 'c2s.sessions.list': {\n this.send('s2c.sessions.snapshot', { full: true, sessions: this.deps.bridge.listSessions() }, env.id)\n return\n }\n case 'c2s.pending.list': {\n this.send('s2c.pending.snapshot', this.deps.bridge.pendingSnapshot(), env.id)\n return\n }\n case 'c2s.workspaces.list': {\n if (!this.deps.bridge.capabilities.projectSelection) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'project selection unavailable on this host version')\n }\n const result = await this.deps.bridge.listWorkspaces()\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.workspaces.snapshot', { workspaces: result.value }, env.id)\n return\n }\n case 'c2s.directory.list': {\n const p = env.payload as { path?: unknown } | undefined\n if (p?.path !== undefined && typeof p.path !== 'string') {\n return this.fail(env.id, 'E_PROTOCOL', 'path must be a string')\n }\n const result = await this.deps.bridge.listDirectory(p?.path as string | undefined)\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.directory.listing', result.value, env.id)\n return\n }\n case 'c2s.directory.pick': {\n const result = await this.deps.bridge.pickDirectory()\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.directory.picked', { path: result.value }, env.id)\n return\n }\n case 'c2s.workspace.create': {\n const p = env.payload as { path?: unknown } | undefined\n const path = typeof p?.path === 'string' ? p.path.trim() : ''\n if (!path) return this.fail(env.id, 'E_PROTOCOL', 'non-empty path required')\n if (!this.deps.bridge.capabilities.projectSelection) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'project selection unavailable on this host version')\n }\n const result = await this.deps.bridge.createWorkspace(path)\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.workspace.created', result.value, env.id)\n return\n }\n case 'c2s.session.open': {\n const p = env.payload as { sessionId?: string; tailCount?: number }\n if (!p?.sessionId || typeof p.sessionId !== 'string') return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n const sessionId = p.sessionId\n const bufferedEvents: Array<{ type: string; payload: unknown; seq?: number }> = []\n this.openingSessionEvents.set(sessionId, bufferedEvents)\n const ok = await this.deps.bridge.openSession(this, sessionId, p.tailCount ?? 100)\n if (!ok) {\n if (this.openingSessionEvents.get(sessionId) === bufferedEvents) {\n this.openingSessionEvents.delete(sessionId)\n }\n return this.fail(env.id, 'E_NOT_FOUND', 'session history unavailable')\n }\n // A concurrent close or replacement open invalidates this attempt.\n // Its tail has already been sent, but it must not reactivate realtime\n // delivery after the user left the screen.\n if (this.openingSessionEvents.get(sessionId) !== bufferedEvents) return\n this.openSessions.add(sessionId)\n this.deps.bridge.markSinkOpen(this, sessionId)\n this.openingSessionEvents.delete(sessionId)\n for (const frame of bufferedEvents) {\n this.push(frame.type, frame.payload, frame.seq)\n }\n return\n }\n case 'c2s.session.close': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n this.openingSessionEvents.delete(p.sessionId)\n this.openSessions.delete(p.sessionId)\n this.deps.bridge.markSinkClosed(this, p.sessionId)\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.session.create': {\n const p = env.payload as { workspaceId?: unknown; cwd?: unknown } | undefined\n const workspaceId = typeof p?.workspaceId === 'string' ? p.workspaceId.trim() : ''\n const cwd = typeof p?.cwd === 'string' ? p.cwd.trim() : ''\n if (workspaceId && cwd) return this.fail(env.id, 'E_PROTOCOL', 'workspaceId and cwd are mutually exclusive')\n const newId = await this.deps.bridge.createSession({\n ...(workspaceId ? { workspaceId } : {}),\n ...(cwd ? { cwd } : {}),\n })\n if (!newId) return this.fail(env.id, 'E_INTERNAL', 'session create failed')\n this.send('s2c.ack', { sessionId: newId }, env.id)\n return\n }\n case 'c2s.session.rename': {\n const p = env.payload as { sessionId?: string; title?: string }\n const title = typeof p?.title === 'string' ? p.title.trim() : ''\n if (!p?.sessionId || title.length === 0) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and non-empty title required')\n }\n if (!this.deps.bridge.capabilities.sessionManagement) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'session management unavailable on this host version')\n }\n const result = await this.deps.bridge.renameSession(p.sessionId, title)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.renamed', { sessionId: p.sessionId, title: result.value }, env.id)\n return\n }\n case 'c2s.session.archive': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n if (!this.deps.bridge.capabilities.sessionManagement) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'session management unavailable on this host version')\n }\n const result = await this.deps.bridge.archiveSession(p.sessionId)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.archived', { sessionId: p.sessionId }, env.id)\n return\n }\n case 'c2s.session.cancel': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n const result = await this.deps.bridge.cancelSession(p.sessionId)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.ack', { sessionId: p.sessionId }, env.id)\n return\n }\n case 'c2s.session.history': {\n const p = env.payload as { sessionId?: string; beforeSeq?: number; limit?: number }\n if (!p?.sessionId || typeof p.beforeSeq !== 'number') {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and beforeSeq required')\n }\n const page = await this.deps.bridge.historyPage(p.sessionId, p.beforeSeq, Math.min(p.limit ?? 100, 500))\n if (!page) return this.fail(env.id, 'E_NOT_FOUND', 'history unavailable')\n this.send('s2c.history.page', page, env.id)\n return\n }\n case 'c2s.session.attachment': {\n const p = env.payload as { sessionId?: string; attachmentId?: string }\n if (!p?.sessionId || typeof p.attachmentId !== 'string' || p.attachmentId.length === 0) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and attachmentId required')\n }\n const image = await this.deps.bridge.attachmentData(p.sessionId, p.attachmentId)\n if (!image) return this.fail(env.id, 'E_NOT_FOUND', 'attachment unavailable')\n this.send('s2c.ack', image, env.id)\n return\n }\n case 'c2s.session.models': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n if (!this.deps.bridge.capabilities.models) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'model selection unavailable on this host version')\n }\n const result = await this.deps.bridge.sessionModels(p.sessionId)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'unavailable' ? 'E_NOT_FOUND'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.models', { sessionId: p.sessionId, ...result.value }, env.id)\n return\n }\n case 'c2s.session.selectModel': {\n const p = env.payload as {\n sessionId?: string\n provider?: string\n model?: string\n reasoningEffort?: string\n }\n if (!p?.sessionId || !p.provider?.trim() || !p.model?.trim()) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId, provider and model required')\n }\n if (!this.deps.bridge.capabilities.models) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'model selection unavailable on this host version')\n }\n const result = await this.deps.bridge.selectSessionModel(p.sessionId, {\n provider: p.provider.trim(),\n model: p.model.trim(),\n ...(p.reasoningEffort?.trim() ? { reasoningEffort: p.reasoningEffort.trim() } : {}),\n })\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'unavailable' ? 'E_NOT_FOUND'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.modelSelected', { sessionId: p.sessionId, selected: result.value }, env.id)\n return\n }\n case 'c2s.session.sendPrompt': {\n const p = env.payload as {\n sessionId?: string\n text?: string\n images?: Array<{ mediaType?: string; data?: string; name?: string }>\n documents?: Array<{ mediaType?: string; name?: string; text?: string; truncated?: boolean }>\n }\n const text = typeof p?.text === 'string' ? p.text : ''\n const rawImages = Array.isArray(p?.images) ? p.images : []\n const rawDocuments = Array.isArray(p?.documents) ? p.documents : []\n if (!p?.sessionId || (text.trim().length === 0 && rawImages.length === 0 && rawDocuments.length === 0)) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and prompt content required')\n }\n if (text.length > MAX_PROMPT_TEXT_CHARS) {\n return this.fail(env.id, 'E_PROTOCOL', 'prompt text too long')\n }\n if (rawImages.length > MAX_PROMPT_IMAGES) {\n return this.fail(env.id, 'E_PROTOCOL', 'too many images')\n }\n if (rawDocuments.length > MAX_PROMPT_DOCUMENTS || rawImages.length + rawDocuments.length > MAX_PROMPT_IMAGES) {\n return this.fail(env.id, 'E_PROTOCOL', 'too many prompt attachments')\n }\n const images: Array<{\n mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'\n data: string\n name?: string\n }> = []\n for (const image of rawImages) {\n if (!IMAGE_MEDIA_TYPES.has(String(image?.mediaType)) ||\n typeof image?.data !== 'string' || image.data.length === 0 ||\n image.data.length > MAX_BASE64_CHARS_PER_IMAGE) {\n return this.fail(env.id, 'E_PROTOCOL', 'invalid image attachment')\n }\n images.push({\n mediaType: image.mediaType as 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif',\n data: image.data,\n ...(typeof image.name === 'string' && sanitizeImageName(image.name).length > 0\n ? { name: sanitizeImageName(image.name) }\n : {}),\n })\n }\n const documents: Array<{ mediaType: string; name: string; text: string; truncated?: boolean }> = []\n for (const document of rawDocuments) {\n if (typeof document?.name !== 'string' || typeof document?.mediaType !== 'string' ||\n typeof document?.text !== 'string' || document.text.length === 0 ||\n document.text.length > MAX_DOCUMENT_TEXT_CHARS) {\n return this.fail(env.id, 'E_PROTOCOL', 'invalid document attachment')\n }\n const name = sanitizeDocumentField(document.name, MAX_DOCUMENT_NAME_CHARS)\n const mediaType = sanitizeDocumentField(document.mediaType, MAX_DOCUMENT_MEDIA_TYPE_CHARS).toLowerCase()\n if (!name || !mediaType || mediaType.startsWith('image/')) {\n return this.fail(env.id, 'E_PROTOCOL', 'invalid document attachment')\n }\n documents.push({ name, mediaType, text: document.text, ...(document.truncated === true ? { truncated: true } : {}) })\n }\n const userSeq = await this.deps.bridge.sendPrompt(p.sessionId, text, images, documents)\n if (!userSeq.ok) return this.fail(env.id, managementErrorCode(userSeq.kind), userSeq.message)\n this.send('s2c.ack', { userSeq: userSeq.value }, env.id)\n return\n }\n case 'c2s.approval.respond': {\n const p = env.payload as { requestId?: string; decision?: string; reason?: string }\n if (!p?.requestId || (p.decision !== 'allow' && p.decision !== 'deny')) {\n return this.fail(env.id, 'E_PROTOCOL', 'requestId and decision required')\n }\n // The optional deny reason must reach the host so the\n // model learns why its tool call was refused.\n const outcome = await this.deps.bridge.respondApproval(\n p.requestId,\n p.decision,\n typeof p.reason === 'string' ? p.reason : undefined,\n )\n if (!outcome.ok) return this.fail(env.id, pendingResponseErrorCode(outcome.reason), pendingResponseMessage('approval', outcome.reason))\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.question.respond': {\n const p = env.payload as { requestId?: string; answers?: unknown }\n if (!p?.requestId || !Array.isArray(p.answers)) {\n return this.fail(env.id, 'E_PROTOCOL', 'requestId and answers required')\n }\n const outcome = await this.deps.bridge.respondQuestion(p.requestId, p.answers)\n if (!outcome.ok) return this.fail(env.id, pendingResponseErrorCode(outcome.reason), pendingResponseMessage('question', outcome.reason))\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.push.register': {\n const p = env.payload as { deviceToken?: unknown; environment?: unknown; categories?: unknown; enrollKey?: unknown }\n const token = typeof p?.deviceToken === 'string' ? p.deviceToken.trim() : ''\n if (!isValidApnsToken(token)) {\n return this.fail(env.id, 'E_PROTOCOL', 'hex deviceToken (32-512 chars) required')\n }\n const environment: ApnsEnvironment = p?.environment === 'production' ? 'production' : 'development'\n const categories = typeof p?.categories === 'object' && p.categories !== null\n ? p.categories as Record<string, boolean>\n : undefined\n if (!this.deviceId || !this.authenticated) {\n return this.fail(env.id, 'E_PROTOCOL', 'authenticate first')\n }\n // Zero-touch enrollment MUST run before the capability gate: a fresh,\n // unconfigured bridge receives its first register precisely when push\n // is not yet enabled, and the key itself flips relay mode on. The\n // relay round-trip is awaited so readiness reflects reality.\n if (typeof p?.enrollKey === 'string') {\n const enrollKey = p.enrollKey.trim().replace(/[^\\x20-\\x7e]/g, '').slice(0, 128)\n if (enrollKey.length >= 8 && enrollKey.length <= 128) {\n await this.deps.onPushEnrollKey?.(enrollKey)\n }\n }\n // Store the registration BEFORE the readiness gate: if push is still\n // mid-bootstrap (or the relay is temporarily down), the token is\n // already on file for when it recovers — no extra register needed.\n this.deps.devices.setPushToken(this.deviceId, token, environment, categories, Date.now())\n if (!this.deps.bridge.capabilities.push) {\n if (this.deps.debug === true) this.deps.log('push register held: bridge not ready')\n return this.fail(env.id, 'E_UNSUPPORTED', 'push is not configured on this bridge')\n }\n if (this.deps.debug === true) {\n this.deps.log('push token registered env=' + environment)\n }\n // `enabled` lets the app flip its local capability immediately instead\n // of waiting for the next handshake.\n this.send('s2c.ack', { enabled: true }, env.id)\n return\n }\n default:\n this.fail(env.id, 'E_PROTOCOL', 'unknown type: ' + env.type)\n }\n }\n\n private async prove(env: Envelope): Promise<void> {\n const p = (env.payload ?? {}) as Partial<AuthProofPayload>\n if (!p.deviceId) {\n this.fail(env.id, 'E_PROTOCOL', 'deviceId required')\n this.close(4403, 'deviceId required')\n return\n }\n const deviceId = sanitizeDeviceField(p.deviceId, MAX_DEVICE_ID_CHARS)\n if (!deviceId) {\n this.fail(env.id, 'E_PROTOCOL', 'deviceId required')\n this.close(4403, 'deviceId required')\n return\n }\n const deviceName = sanitizeDeviceField(p.deviceName, MAX_DEVICE_NAME_CHARS) || 'unknown'\n const appVersion = sanitizeDeviceField(p.appVersion, MAX_APP_VERSION_CHARS) || 'unknown'\n const challenge = this.authChallenge\n const record = this.deps.devices.authorized(deviceId)\n const resumeCursor = typeof p.resumeCursor === 'number' && Number.isInteger(p.resumeCursor) && p.resumeCursor >= 0\n ? p.resumeCursor\n : undefined\n const challengeMatches = p.nonce === challenge.nonce &&\n p.audience === challenge.audience &&\n p.issuedAt === challenge.issuedAt &&\n p.expiresAt === challenge.expiresAt &&\n Date.now() <= challenge.expiresAt\n const proofValid = record?.publicKey !== undefined && typeof p.signature === 'string' && challengeMatches &&\n verifyAuthProof(record.publicKey, {\n deviceId,\n deviceName,\n appVersion,\n resumeCursor,\n ...challenge,\n }, p.signature)\n if (!proofValid || record === undefined) {\n this.fail(env.id, 'E_AUTH', 'device proof missing or invalid')\n this.settleAuthentication(false, 'invalid-proof')\n this.close(4401, 'invalid device proof')\n return\n }\n this.settleAuthentication(true, 'success')\n this.authenticated = true\n this.deviceId = deviceId\n this.scopes = new Set(record.scopes ?? [])\n if (this.helloTimer !== undefined) clearTimeout(this.helloTimer)\n this.deps.devices.markAuthenticated(deviceId, deviceName, appVersion, Date.now())\n this.deps.onDeviceAuthenticated?.(deviceId)\n\n const cursor = resumeCursor\n const canResume = cursor !== undefined && this.deps.bridge.canResumeFrom(cursor)\n // Welcome strictly precedes any replayed pushes.\n this.send('s2c.welcome', {\n protocolVersion: PROTOCOL_VERSION,\n serverVersion: this.deps.serverVersion,\n deviceId,\n scopes: [...this.scopes],\n capabilities: this.deps.bridge.capabilities,\n cursor: this.deps.bridge.currentCursor(),\n resumed: canResume,\n }, env.id)\n this.deps.bridge.addSink(this)\n if (cursor !== undefined) {\n if (canResume) {\n this.deps.bridge.resumeFrom(cursor, this)\n } else {\n this.resync()\n }\n }\n }\n}\n","import type { PushNotification } from './protocol.ts'\n\n/* Minimal structural faces over the host apiProxy service. The real types\n * live in @deepseek-ai/dsh-host-apiproxy; keeping them structural lets this\n * plugin compile and degrade independently of host package versions. */\n\ninterface RpcOk<T> { ok: true; value: T }\ninterface RpcErr { ok: false; error: { code: string; message?: string } }\ntype RpcResult<T> = RpcOk<T> | RpcErr\n\ninterface RpcRequestLike<T> { rpcId?: string; payload?: T }\ninterface RpcResponseLike<T> { result?: RpcResult<T> }\n\ninterface SessionsApiLike {\n list(req?: RpcRequestLike<{ cursor?: string }>): Promise<RpcResponseLike<{ items: PhoneSessionRow[] }>>\n history(req: RpcRequestLike<{ sessionId: string; beforeSeq?: number; maxMessages?: number }>):\n Promise<RpcResponseLike<HistoryResult>>\n prompt(req: RpcRequestLike<PromptArgs>): Promise<RpcResponseLike<{ accepted: true }>>\n create(req: RpcRequestLike<{ workspaceId?: string; cwd?: string; agentPreset?: string }>): Promise<RpcResponseLike<{ sessionId: string; agentPreset?: string }>>\n models?(req: RpcRequestLike<{ sessionId: string }>): Promise<RpcResponseLike<HostSessionModels>>\n selectModel?(req: RpcRequestLike<{\n sessionId: string\n provider: string\n model: string\n reasoningEffort?: string\n }>): Promise<RpcResponseLike<{ selected: HostModelSelection }>>\n rename?(req: RpcRequestLike<{ sessionId: string; title: string }>):\n Promise<RpcResponseLike<{ title: string; seq: number }>>\n cancel?(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<Record<string, unknown> | undefined>>\n /** Reads one durable image back after the host verifies the session log references its id. */\n attachment?(req: RpcRequestLike<{ sessionId: string; attachmentId: string }>):\n Promise<RpcResponseLike<{ attachment: { mediaType?: string }; data: string }>>\n}\n\ninterface WorkspaceApiLike {\n list?(req: RpcRequestLike<Record<string, never>>):\n Promise<RpcResponseLike<{ items: WorkspaceViewLike[]; archivedSessionIds: string[] }>>\n create?(req: RpcRequestLike<{ path: string }>):\n Promise<RpcResponseLike<{ workspace: WorkspaceViewLike; created: boolean }>>\n archiveSession?(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ archivedSessionIds: string[] }>>\n}\n\ninterface HostApiLike {\n listDirectory?(req: RpcRequestLike<{ path?: string }>, signal?: AbortSignal):\n Promise<RpcResponseLike<DirectoryListingLike>>\n pickDirectory?(req: RpcRequestLike<Record<string, never>>, signal?: AbortSignal):\n Promise<RpcResponseLike<{ path: string | null }>>\n}\n\nexport interface WorkspaceViewLike {\n workspaceId: string\n path: string\n title: string\n sessionIds: string[]\n createdAt?: string\n updatedAt?: string\n}\n\nexport interface DirectoryEntryLike {\n name: string\n path: string\n hidden: boolean\n}\n\nexport interface DirectoryListingLike {\n path: string\n home: string\n crumbs: DirectoryEntryLike[]\n entries: DirectoryEntryLike[]\n truncated: boolean\n}\n\nexport interface HostModelSelection {\n provider: string\n model: string\n reasoningEffort?: string\n}\n\nexport interface HostSessionModels {\n current: HostModelSelection\n routable: boolean\n groups: Array<{\n id: string\n name: string\n models: Array<{\n id: string\n name: string\n description?: string\n reasoning?: {\n efforts: Array<{ id: string; name: string; description?: string }>\n defaultEffort?: string\n }\n }>\n }>\n failures: Array<{ id: string; name: string; message: string }>\n}\n\nexport type ModelBridgeResult<T> =\n | { ok: true; value: T }\n | { ok: false; kind: 'unsupported' | 'not-found' | 'busy' | 'unavailable' | 'internal'; message: string }\n\nexport type SessionManagementResult<T> =\n | { ok: true; value: T }\n | { ok: false; kind: 'unsupported' | 'not-found' | 'busy' | 'invalid' | 'internal'; message: string }\n\nexport interface PromptArgs {\n sessionId: string\n mode: 'queue' | 'steer'\n content: Array<\n | { type: 'text'; text: string }\n | { type: 'image'; mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; data: string; name?: string }\n >\n clientTimeZone?: string\n}\n\nexport interface PhoneSessionRow {\n sessionId: string\n updatedAt: number\n running: boolean\n /** Host marks never-prompted sessions as blank; informational only — the\n * summary projects them as idle (see toSummary) so phones can send. */\n blank?: boolean\n cwd?: string\n origin?: string\n parentSessionId?: string\n projections?: { asOfSeq?: number; values?: Record<string, unknown> }\n}\n\n/**\n * Subagent sessions are host-internal workers of a parent conversation.\n * They must never surface on the phone: not in the project/session list,\n * and not as turn-completion pushes for a session the device cannot open.\n */\nexport function isSubagentRow(row: PhoneSessionRow): boolean {\n return row.origin === 'subagent' ||\n (typeof row.parentSessionId === 'string' && row.parentSessionId.length > 0);\n}\n\nexport interface HistoryResult {\n events: Array<{ event: SessionEventLike; view?: unknown }>\n hasMore: boolean\n projections?: { values?: Record<string, unknown> }\n}\n\nexport interface SessionEventLike {\n type: string\n seq: number\n time?: number\n data?: unknown\n}\n\nexport interface MuxFrameLike {\n type: string\n rpcId?: string\n payload?: any\n sessionId?: string\n event?: SessionEventLike\n key?: string\n value?: unknown\n approvalId?: string\n toolName?: string\n reason?: string\n questions?: unknown\n questionRpcId?: string\n running?: boolean\n}\n\n/**\n * apiProxy stream items are server-request envelopes: the frame lives in\n * `payload`, while the stable request id used to answer approval/question\n * waits lives beside it. Flattening only `payload` loses that id and makes\n * both interactions silently disappear.\n */\nexport interface ApiStreamItemLike {\n rpcId?: string\n payload: MuxFrameLike\n}\n\nexport function unwrapStreamItem(item: MuxFrameLike | ApiStreamItemLike): MuxFrameLike {\n const nested = item.payload\n if (nested && typeof nested === 'object' && typeof nested.type === 'string') {\n // The envelope id identifies the server request that must be answered.\n // Preserve it even if a future nested payload happens to carry another id.\n return item.rpcId ? { ...nested, rpcId: item.rpcId } : nested\n }\n return item as MuxFrameLike\n}\n\nexport interface ApiProxyLike {\n sessions: SessionsApiLike\n workspace?: WorkspaceApiLike\n host?: HostApiLike\n respond(message: { type: 'client-response'; rpcId: string; result: RpcResult<unknown> }):\n Promise<{ accepted: boolean; reason?: string }>\n events: {\n mux(req: RpcRequestLike<Record<string, never>>, signal: AbortSignal): AsyncIterable<MuxFrameLike | ApiStreamItemLike>\n host(req: RpcRequestLike<Record<string, never>>, signal: AbortSignal): AsyncIterable<MuxFrameLike | ApiStreamItemLike>\n }\n}\n\n/**\n * Outcome of answering a pending approval/question. The host distinguishes\n * \"never/no longer pending\" from \"payload rejected\", and collapsing both into\n * a boolean made every rejection read as `question not pending` on the phone.\n */\nexport type PendingResponseOutcome =\n | { ok: true }\n | { ok: false; reason: 'not-pending' | 'bad-response' | 'transport' }\n\n/** Downward sink every connected phone registers (one per WebSocket). */\nexport interface BridgeSink {\n push(type: string, payload: unknown, seq?: number): void\n lastCursor(): number\n replay(entries: Array<{ seq: number; type: string; payload: unknown }>): void\n replayDone(): void\n resync(): void\n}\n\n/**\n * Offline push fan-out (F-9 离线推送). The bridge forwards every\n * notification-worthy event here; the outlet decides which paired devices\n * (token holders without a live socket) receive an APNs delivery.\n */\nexport interface PushOutlet {\n fanOut(notification: PushNotification): void\n /**\n * Whether offline push is currently configured and usable. Drives the\n * welcome capability bit: advertising push while no APNs credentials are\n * loaded would make clients suppress their own local banners and lose\n * notifications entirely.\n */\n isAvailable(): boolean\n}\n","export interface PromptDocument {\n name: string\n mediaType: string\n text: string\n truncated?: boolean\n}\n\ninterface DocumentMarker {\n v: 1\n name: string\n mediaType: string\n truncated?: boolean\n}\n\nconst PREFIX = '[DeepPilot document:'\nconst SUFFIX = ']'\n\n/**\n * DSH 0.1.2 has durable image attachments but no generic file content block.\n * Documents therefore travel as a bounded, explicitly-labelled text block.\n * The marker lets the canonical phone row recover an attachment chip without\n * exposing the complete document body as ordinary user-authored bubble text.\n */\nexport function documentPromptBlock(document: PromptDocument): string {\n const marker: DocumentMarker = {\n v: 1,\n name: document.name,\n mediaType: document.mediaType,\n ...(document.truncated ? { truncated: true } : {}),\n }\n const encoded = Buffer.from(JSON.stringify(marker), 'utf8').toString('base64url')\n return `${PREFIX}${encoded}${SUFFIX}\\nAttached document: ${document.name}\\n\\n${document.text}`\n}\n\nexport function projectedDocument(text: string): PromptDocument | undefined {\n if (!text.startsWith(PREFIX)) return undefined\n const end = text.indexOf(SUFFIX, PREFIX.length)\n if (end < 0) return undefined\n try {\n const decoded = JSON.parse(Buffer.from(text.slice(PREFIX.length, end), 'base64url').toString('utf8')) as Partial<DocumentMarker>\n if (decoded.v !== 1 || typeof decoded.name !== 'string' || typeof decoded.mediaType !== 'string') return undefined\n if (!decoded.name.trim() || !decoded.mediaType.trim()) return undefined\n return {\n name: decoded.name,\n mediaType: decoded.mediaType,\n text: text.slice(end + SUFFIX.length).replace(/^\\nAttached document:[^\\n]*\\n\\n/, ''),\n ...(decoded.truncated === true ? { truncated: true } : {}),\n }\n } catch {\n return undefined\n }\n}\n","import type { MessageProjection, SessionEventKind } from './protocol.ts'\nimport type { SessionEventLike } from './host-api.ts'\nimport { projectedDocument } from './document-payload.ts'\n\nexport const MAX_MESSAGE_PROJECTION_BYTES = 256 * 1024\n/// Aggregate message-array budget for one tail/history frame. The complete\n/// envelope stays below the legacy iOS 1 MB decoder cap with ample metadata\n/// headroom, while each individual projection keeps its 256 KB allowance.\nexport const MAX_SESSION_PAGE_MESSAGES_BYTES = 900 * 1024\n\n/** One durable host event sequence becomes exactly one phone message row.\n * Keep the last projection when a host history response repeats an event. */\nexport function canonicalSessionMessages(messages: MessageProjection[]): MessageProjection[] {\n const bySequence = new Map<number, MessageProjection>()\n for (const message of messages) bySequence.set(message.seq, message)\n return [...bySequence.values()].sort((a, b) => a.seq - b.seq)\n}\n\nexport function limitSessionPageMessages(messages: MessageProjection[]): {\n messages: MessageProjection[]\n dropped: number\n} {\n const canonical = canonicalSessionMessages(messages)\n let bytes = 2 // JSON array brackets\n const kept: MessageProjection[] = []\n for (let index = canonical.length - 1; index >= 0; index -= 1) {\n const message = canonical[index]!\n const candidateBytes = jsonBytes(message) + (kept.length > 0 ? 1 : 0)\n if (bytes + candidateBytes > MAX_SESSION_PAGE_MESSAGES_BYTES) break\n kept.unshift(message)\n bytes += candidateBytes\n }\n return { messages: kept, dropped: canonical.length - kept.length }\n}\n\nexport function projectEvent(sessionId: string, event: SessionEventLike): { kind: SessionEventKind; data: Record<string, unknown> } | null {\n switch (event.type) {\n case 'turn/start':\n return { kind: 'turn.start', data: {} };\n case 'turn/end': {\n const data = event.data as { reason?: { kind?: string } } | undefined;\n return { kind: 'turn.end', data: { ok: data?.reason?.kind === 'completed' } };\n }\n case 'user/message':\n return {\n kind: 'message.final',\n data: { ...limitMessageProjection({\n seq: event.seq,\n role: userRoleOf(event.data),\n text: messageText(event.data),\n ...attachmentProjection(event.data),\n ...(contextProjectionOf(event.data)),\n ts: tsOf(event),\n }) },\n };\n case 'assistant/chunk': {\n if (chunkTypeOf(event.data) === 'reasoning-delta') {\n return { kind: 'thinking.delta', data: limitRealtimeText({ text: chunkText(event.data), ts: tsOf(event) }) };\n }\n return { kind: 'message.delta', data: limitRealtimeText({ text: chunkText(event.data), ts: tsOf(event) }) };\n }\n case 'assistant/message': {\n const text = messageText(event.data);\n const thinking = messageThinking(event.data);\n // Pure-reasoning or tool-only steps carry no visible answer; emitting\n // them produced empty bubbles on the phone.\n if (!text.trim() && !thinking.trim()) return null;\n return {\n kind: 'message.final',\n data: { ...limitMessageProjection({ seq: event.seq, role: 'assistant', text, ...(thinking ? { thinking } : {}), ts: tsOf(event) }) },\n };\n }\n case 'tool/call': {\n const data = event.data as { name?: string; arguments?: string; callId?: string } | undefined;\n return {\n kind: 'tool.start',\n data: {\n seq: event.seq,\n role: 'tool',\n tool: {\n name: String(data?.name ?? 'tool'),\n state: 'running',\n summary: summarizeArgs(data?.arguments),\n // Echo the invocation id so clients can pair the later result with\n // this exact row instead of guessing.\n ...(data?.callId ? { callId: String(data.callId) } : {}),\n },\n ts: tsOf(event)\n }\n };\n }\n case 'tool/result': {\n const data = event.data as { callId?: string; error?: unknown } | undefined;\n return {\n kind: 'tool.end',\n data: {\n seq: event.seq,\n role: 'tool',\n ok: !event.data || data?.error === undefined,\n // The seq above identifies this result event; callId is what ties it\n // back to the originating tool/call row on the client.\n ...(data?.callId ? { callId: String(data.callId) } : {}),\n ts: tsOf(event)\n }\n };\n }\n default:\n return null;\n }\n}\n\nfunction tsOf(event: SessionEventLike): number {\n return typeof event.time === 'number' ? event.time : Date.now();\n}\n\n// ---------- user-role source classification ----------\n//\n// The DSH host logs every model-visible user-role message as `user/message`,\n// but only some of them are human prompts: synthetic `agent.inject()` context\n// (runtime-context snapshots, background-job notices, workspace instructions,\n// skill content, …) rides the same event type. The durable message carries a\n// `source` whose `kind` tells them apart, and the host's own trajectory view\n// renders only `source.kind === 'user'` as a human prompt — everything else is\n// injected context. The bridge mirrors that classification so the phone can\n// keep the two apart instead of guessing from text shapes.\n\n/** Read the durable message source off one user/message payload. Handles both\n * bare-message payloads and older `{message: {...}}` wrappers; undefined when\n * the shape carries no readable source (legacy hosts). */\nfunction userMessageSource(data: unknown): Record<string, unknown> | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const obj = data as { source?: unknown; message?: { source?: unknown } };\n if (obj.source && typeof obj.source === 'object') {\n return obj.source as Record<string, unknown>;\n }\n if (obj.message && typeof obj.message === 'object' &&\n obj.message.source && typeof obj.message.source === 'object') {\n return obj.message.source as Record<string, unknown>;\n }\n return undefined;\n}\n\n/** Wire role for one user/message payload. A payload without any readable\n * source degrades to 'user' so history written by older hosts stays visible;\n * a present source follows the host's own trajectory rule — anything whose\n * `kind` is not 'user' is injected context and projects as 'system'. */\nfunction userRoleOf(data: unknown): 'user' | 'system' {\n const source = userMessageSource(data);\n if (!source) return 'user';\n return source.kind === 'user' ? 'user' : 'system';\n}\n\n/** Producer name of one injected-context source, mirroring how the DSH client\n * runtime derives its trajectory label: plugin name, skill name, instruction\n * paths, session-reference labels, or the raw kind as fallback. */\nfunction contextLabelOf(source: Record<string, unknown>): string | undefined {\n const kind = typeof source.kind === 'string' ? source.kind : '';\n const joined = (member: string): string | undefined => {\n const list = source[member];\n if (!Array.isArray(list)) return undefined;\n const names = list.flatMap((entry) => {\n if (!entry || typeof entry !== 'object') return [];\n const record = entry as Record<string, unknown>;\n return [typeof record.label === 'string' ? record.label :\n (typeof record.path === 'string' ? record.path : '')];\n }).filter((name) => name.length > 0);\n return names.length > 0 ? names.join(', ') : undefined;\n };\n switch (kind) {\n case 'session-reference':\n return joined('references') ?? (kind || undefined);\n case 'agent-instructions':\n return joined('changes') ?? (kind || undefined);\n case 'plugin':\n return typeof source.plugin === 'string' && source.plugin.length > 0 ? source.plugin : kind || undefined;\n case 'skill-invocation':\n return typeof source.name === 'string' && source.name.length > 0 ? source.name : kind || undefined;\n default:\n return kind || undefined;\n }\n}\n\n/** Semantic ContextForm declared by the producer ('snapshot', 'notice', …);\n * anything unrecognized stays undefined so clients render it opaque. */\nfunction contextFormOf(source: Record<string, unknown>): string | undefined {\n if (typeof source.form !== 'string' || source.form.length === 0) return undefined;\n // Same known-vocabulary guard as the host's trajectory UI.\n const known = ['instructions', 'catalog', 'snapshot', 'notice', 'relay', 'recall'];\n return known.includes(source.form) ? source.form : undefined;\n}\n\n/** Optional `context` metadata for one system row; {} on user rows. */\nfunction contextProjectionOf(data: unknown): { context?: { label?: string; form?: string } } {\n if (userRoleOf(data) !== 'system') return {};\n const source = userMessageSource(data);\n if (!source) return {};\n const label = contextLabelOf(source);\n const form = contextFormOf(source);\n if (!label && !form) return {};\n return { context: { ...(label ? { label } : {}), ...(form ? { form } : {}) } };\n}\n\n/** Extract plain text from user/assistant message payloads across shapes. */\nexport function messageText(data: unknown): string {\n if (typeof data === 'string') return data;\n if (!data || typeof data !== 'object') return '';\n const obj = data as { content?: unknown; text?: unknown; message?: unknown };\n if (typeof obj.text === 'string') return obj.text;\n // Session events wrap the message: {turn, step, message: {role, content}}\n if (obj.message && typeof obj.message === 'object') return messageText(obj.message);\n return contentText(obj.content);\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content.map(part => {\n if (typeof part === 'string') return part;\n if (part && typeof part === 'object') {\n const piece = part as { type?: string; text?: string };\n if (piece.type === 'text' && typeof piece.text === 'string') {\n return projectedDocument(piece.text) ? '' : piece.text\n }\n }\n return '';\n }).join('');\n }\n return '';\n}\n\nfunction messageAttachments(data: unknown): Array<{\n kind: 'image' | 'document'\n name?: string\n mediaType?: string\n attachmentId?: string\n width?: number\n height?: number\n truncated?: boolean\n}> {\n if (!data || typeof data !== 'object') return [];\n const obj = data as { content?: unknown; message?: unknown };\n if (obj.message && typeof obj.message === 'object') return messageAttachments(obj.message);\n if (!Array.isArray(obj.content)) return [];\n const attachments: Array<{\n kind: 'image' | 'document'\n name?: string\n mediaType?: string\n attachmentId?: string\n width?: number\n height?: number\n truncated?: boolean\n }> = []\n for (const part of obj.content) {\n if (!part || typeof part !== 'object') continue\n // The host normalizes uploaded bytes into an ImageAttachmentRef\n // (attachmentId/mediaType/bytes/width/height...); the id is what clients\n // need to read the image back through c2s.session.attachment.\n const block = part as {\n type?: string\n text?: unknown\n attachment?: {\n name?: unknown\n mediaType?: unknown\n attachmentId?: unknown\n width?: unknown\n height?: unknown\n }\n };\n if (block.type === 'text' && typeof block.text === 'string') {\n const document = projectedDocument(block.text)\n if (document) {\n attachments.push({\n kind: 'document',\n name: document.name,\n mediaType: document.mediaType,\n ...(document.truncated ? { truncated: true } : {}),\n })\n }\n continue\n }\n if (block.type !== 'image' || !block.attachment) continue\n const attachmentId = typeof block.attachment.attachmentId === 'string' && block.attachment.attachmentId.length > 0\n ? block.attachment.attachmentId\n : undefined;\n const width = typeof block.attachment.width === 'number' && Number.isFinite(block.attachment.width)\n ? block.attachment.width\n : undefined;\n const height = typeof block.attachment.height === 'number' && Number.isFinite(block.attachment.height)\n ? block.attachment.height\n : undefined;\n attachments.push({\n kind: 'image',\n ...(typeof block.attachment.name === 'string' ? { name: block.attachment.name } : {}),\n ...(typeof block.attachment.mediaType === 'string' ? { mediaType: block.attachment.mediaType } : {}),\n ...(attachmentId ? { attachmentId } : {}),\n ...(width !== undefined ? { width } : {}),\n ...(height !== undefined ? { height } : {}),\n })\n }\n return attachments\n}\n\nfunction attachmentProjection(data: unknown): { attachments?: ReturnType<typeof messageAttachments> } {\n const attachments = messageAttachments(data);\n return attachments.length > 0 ? { attachments } : {};\n}\n\n/** Extract reasoning (\"thinking\") text from assistant message payloads. */\nfunction messageThinking(data: unknown): string {\n if (!data || typeof data !== 'object') return '';\n const obj = data as { content?: unknown; message?: unknown };\n // Session events wrap the message: {turn, step, message: {role, content}}\n if (obj.message && typeof obj.message === 'object') return messageThinking(obj.message);\n return reasoningContent(obj.content);\n}\n\nfunction reasoningContent(content: unknown): string {\n if (!Array.isArray(content)) return '';\n return content.map(part => {\n if (part && typeof part === 'object') {\n const piece = part as { type?: string; text?: string };\n if (piece.type === 'reasoning' && typeof piece.text === 'string') return piece.text;\n }\n return '';\n }).join('');\n}\n\n/** Stream chunk type of an assistant/chunk payload ('' when unwrapped). */\nfunction chunkTypeOf(data: unknown): string {\n if (!data || typeof data !== 'object') return '';\n const obj = data as { chunk?: unknown };\n if (obj.chunk && typeof obj.chunk === 'object') {\n return String((obj.chunk as { type?: unknown }).type ?? '');\n }\n // Unwrapped payloads carry plain text deltas.\n return 'text-delta';\n}\n\nfunction chunkText(data: unknown): string {\n if (!data || typeof data !== 'object') return '';\n // StreamChunk shape: {turn, step, chunk: {type: 'text-delta'|'reasoning-delta', text}}\n const obj = data as { chunk?: unknown };\n if (obj.chunk && typeof obj.chunk === 'object') {\n const inner = obj.chunk as { type?: string; text?: string };\n if ((inner.type === 'text-delta' || inner.type === 'reasoning-delta') && typeof inner.text === 'string') {\n return inner.text;\n }\n return '';\n }\n const direct = data as { text?: unknown };\n return typeof direct.text === 'string' ? direct.text : '';\n}\n\nfunction summarizeArgs(raw: unknown): string {\n if (typeof raw !== 'string' || raw.length === 0) return '';\n try {\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n const parts: string[] = [];\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value === 'string') parts.push(key + '=' + truncate(value.replace(/\\s+/g, ' '), 60));\n }\n return truncate(parts.join(' '), 90);\n } catch {\n return truncate(raw, 90);\n }\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : text.slice(0, max - 1) + '…';\n}\n\nexport function projectHistory(events: Array<{ event: SessionEventLike; view?: unknown }>): MessageProjection[] {\n const messages: MessageProjection[] = [];\n const toolByCall = new Map<string, MessageProjection>();\n for (const entry of events) {\n const event = entry.event;\n const base = { seq: event.seq, ts: tsOf(event) };\n switch (event.type) {\n case 'user/message':\n messages.push({\n ...base,\n role: userRoleOf(event.data),\n text: messageText(event.data),\n ...attachmentProjection(event.data),\n ...(contextProjectionOf(event.data)),\n });\n break;\n case 'assistant/message': {\n const text = messageText(event.data);\n const thinking = messageThinking(event.data);\n if (!text.trim() && !thinking.trim()) break;\n messages.push({ ...base, role: 'assistant', text, ...(thinking ? { thinking } : {}) });\n break;\n }\n case 'tool/call': {\n const data = event.data as { name?: string; arguments?: string; callId?: string } | undefined;\n const row: MessageProjection = {\n ...base,\n role: 'tool',\n tool: { name: String(data?.name ?? 'tool'), state: 'running', summary: summarizeArgs(data?.arguments) },\n };\n messages.push(row);\n if (data?.callId) toolByCall.set(String(data.callId), row);\n break;\n }\n case 'tool/result': {\n const data = event.data as { callId?: string; message?: { content?: unknown }; error?: unknown } | undefined;\n const callId = data?.callId ? String(data.callId) : undefined;\n const target = callId ? toolByCall.get(callId) : undefined;\n const failed = data?.error !== undefined;\n const summary = failed ? '失败' : summarizeResult(data?.message?.content);\n if (target?.tool) {\n target.tool = { ...target.tool, state: failed ? 'error' : 'ok', summary };\n } else {\n messages.push({ ...base, role: 'tool', tool: { name: 'result', state: failed ? 'error' : 'ok', summary } });\n }\n break;\n }\n default:\n break;\n }\n }\n return canonicalSessionMessages(messages.map(limitMessageProjection));\n}\n\n/**\n * Enforce PROTOCOL.md's per-message 256 KB ceiling by UTF-8 JSON byte size.\n * Keep structural identity and attachment references intact; progressively\n * shorten human-readable fields until the serialized projection fits.\n */\nexport function limitMessageProjection(message: MessageProjection): MessageProjection {\n if (jsonBytes(message) <= MAX_MESSAGE_PROJECTION_BYTES) return message\n const next: MessageProjection = {\n ...message,\n ...(message.tool ? {\n tool: {\n ...message.tool,\n name: truncateUtf8(message.tool.name, 4 * 1024),\n summary: truncateUtf8(message.tool.summary, 64 * 1024),\n },\n } : {}),\n ...(message.attachments ? {\n attachments: message.attachments.slice(0, 16).map((attachment) => ({\n ...attachment,\n ...(attachment.name ? { name: truncateUtf8(attachment.name, 4 * 1024) } : {}),\n ...(attachment.mediaType ? { mediaType: truncateUtf8(attachment.mediaType, 256) } : {}),\n ...(attachment.attachmentId ? { attachmentId: truncateUtf8(attachment.attachmentId, 4 * 1024) } : {}),\n })),\n } : {}),\n ...(message.context ? {\n context: {\n ...(message.context.label ? { label: truncateUtf8(message.context.label, 8 * 1024) } : {}),\n ...(message.context.form ? { form: truncateUtf8(message.context.form, 256) } : {}),\n },\n } : {}),\n truncated: true,\n }\n\n const textFields: Array<{\n get: () => string\n set: (value: string) => void\n }> = []\n if (typeof next.text === 'string') textFields.push({\n get: () => next.text ?? '',\n set: (value) => { next.text = value },\n })\n if (typeof next.thinking === 'string') textFields.push({\n get: () => next.thinking ?? '',\n set: (value) => { next.thinking = value },\n })\n if (next.tool) textFields.push({\n get: () => next.tool?.summary ?? '',\n set: (value) => { if (next.tool) next.tool.summary = value },\n })\n if (next.context?.label) textFields.push({\n get: () => next.context?.label ?? '',\n set: (value) => { if (next.context) next.context.label = value },\n })\n\n while (jsonBytes(next) > MAX_MESSAGE_PROJECTION_BYTES) {\n const largest = textFields\n .map((field) => ({ field, bytes: Buffer.byteLength(field.get(), 'utf8') }))\n .sort((a, b) => b.bytes - a.bytes)[0]\n if (largest && largest.bytes > 0) {\n largest.field.set(truncateUtf8(largest.field.get(), Math.floor(largest.bytes / 2)))\n continue\n }\n if (next.attachments && next.attachments.length > 0) {\n next.attachments = next.attachments.slice(0, -1)\n continue\n }\n break\n }\n return next\n}\n\nfunction limitRealtimeText(data: { text: string; ts: number }): Record<string, unknown> {\n if (jsonBytes(data) <= MAX_MESSAGE_PROJECTION_BYTES) return data\n let text = data.text\n const next: Record<string, unknown> = { ...data, truncated: true }\n while (jsonBytes(next) > MAX_MESSAGE_PROJECTION_BYTES && text.length > 0) {\n text = truncateUtf8(text, Math.floor(Buffer.byteLength(text, 'utf8') / 2))\n next.text = text\n }\n return next\n}\n\nfunction jsonBytes(value: unknown): number {\n return Buffer.byteLength(JSON.stringify(value), 'utf8')\n}\n\nfunction truncateUtf8(value: string, maxBytes: number): string {\n if (maxBytes <= 0) return ''\n if (Buffer.byteLength(value, 'utf8') <= maxBytes) return value\n let low = 0\n let high = value.length\n while (low < high) {\n const mid = Math.ceil((low + high) / 2)\n const candidate = value.slice(0, mid)\n if (Buffer.byteLength(candidate, 'utf8') <= maxBytes) low = mid\n else high = mid - 1\n }\n let end = low\n if (end > 0 && /[\\uD800-\\uDBFF]/.test(value[end - 1]!)) end -= 1\n return value.slice(0, end)\n}\n\nfunction summarizeResult(content: unknown): string {\n const text = contentText(content).replace(/\\s+/g, ' ').trim();\n return truncate(text, 90);\n}\n","import { randomUUID } from 'node:crypto'\nimport type { Envelope, MessageProjection, NotifyCategory, PendingSnapshotPayload, PushNotification, SessionEventKind, SessionSummary, SessionTodoItem, SessionTodoStatus } from './protocol.ts'\nimport {\n isSubagentRow,\n unwrapStreamItem,\n} from './host-api.ts'\nimport type {\n ApiProxyLike,\n BridgeSink,\n DirectoryListingLike,\n HostModelSelection,\n HostSessionModels,\n PendingResponseOutcome,\n PhoneSessionRow,\n PromptArgs,\n PushOutlet,\n SessionEventLike,\n SessionManagementResult,\n ModelBridgeResult,\n MuxFrameLike,\n WorkspaceViewLike,\n} from './host-api.ts'\nexport * from './host-api.ts'\nimport {\n MAX_MESSAGE_PROJECTION_BYTES,\n MAX_SESSION_PAGE_MESSAGES_BYTES,\n canonicalSessionMessages,\n limitMessageProjection,\n limitSessionPageMessages,\n messageText,\n projectEvent,\n projectHistory,\n} from './host-event-projection.ts'\nimport { documentPromptBlock, type PromptDocument } from './document-payload.ts'\n\nexport {\n MAX_MESSAGE_PROJECTION_BYTES,\n MAX_SESSION_PAGE_MESSAGES_BYTES,\n canonicalSessionMessages,\n limitMessageProjection,\n limitSessionPageMessages,\n projectEvent,\n projectHistory,\n} from './host-event-projection.ts'\n\ninterface PendingApproval {\n rpcId: string\n sessionId: string\n toolName: string\n reason: string\n}\n\ninterface PendingQuestion {\n rpcId: string\n sessionId: string\n questions: unknown\n}\n\nconst MAX_RING_DEFAULT = 2000;\n\n/**\n * Process-wide bridge state: session mirror, pending approvals/questions,\n * and the per-device replay ring. Consumes the in-process mux/host streams\n * and fans projected pushes out to every registered sink.\n */\nlet BRIDGE_SEQ = 0;\n\nexport class HostBridge {\n readonly id = ++BRIDGE_SEQ;\n private summaries = new Map<string, SessionSummary>()\n private approvals = new Map<string, PendingApproval>()\n private questions = new Map<string, PendingQuestion>()\n private archivedSessionIds = new Set<string>()\n private subagentSessionIds = new Set<string>()\n private sinks = new Set<BridgeSink>()\n private ring: Array<{ seq: number; type: string; payload: unknown }> = []\n private cursor = 0;\n private userReceiptSeq = 0;\n private abort = new AbortController();\n private started = false\n private disposed = false\n\n constructor(\n private readonly apiProxy: ApiProxyLike,\n private readonly historyBufferMax: number = MAX_RING_DEFAULT,\n ) {}\n\n private pushOutlet: PushOutlet | undefined;\n\n /**\n * Wire the offline-push fan-out. Present ⇒ welcome advertises the `push`\n * capability and notify-worthy events are mirrored to APNs.\n */\n setPushOutlet(outlet: PushOutlet | undefined): void {\n this.pushOutlet = outlet;\n }\n\n get capabilities() {\n return {\n historyPaging: true,\n replay: true,\n approvals: true,\n questions: true,\n pendingSnapshot: true,\n notifyAllCategories: true,\n models: typeof this.apiProxy.sessions.models === 'function' &&\n typeof this.apiProxy.sessions.selectModel === 'function',\n sessionManagement: typeof this.apiProxy.sessions.rename === 'function' &&\n typeof this.apiProxy.workspace?.archiveSession === 'function',\n projectSelection: typeof this.apiProxy.workspace?.list === 'function' &&\n typeof this.apiProxy.workspace?.create === 'function',\n push: this.pushOutlet?.isAvailable() === true,\n };\n }\n\n diagnostic(message: string): void {\n console.log('[deeppilot] ' + message);\n }\n\n currentCursor(): number {\n return this.cursor;\n }\n\n // ---------- sinks ----------\n\n addSink(sink: BridgeSink): void {\n this.sinks.add(sink);\n }\n\n removeSink(sink: BridgeSink): void {\n this.sinks.delete(sink);\n }\n\n /** Whether the ring still holds everything after the cursor. */\n canResumeFrom(cursor: number): boolean {\n const oldest = this.ring.length > 0 ? this.ring[0]!.seq : this.cursor + 1;\n // A cursor ahead of this process belongs to an older bridge lifetime.\n // Treat it as a gap instead of incorrectly claiming a successful resume.\n return cursor <= this.cursor && cursor + 1 >= oldest;\n }\n\n private sinkSessions = new Map<BridgeSink, Set<string>>();\n private lastAssistantText = new Map<string, string>();\n\n /** Mark a sink as actively viewing a session (suppresses its turn notifications). */\n markSinkOpen(sink: BridgeSink, sessionId: string): void {\n let set = this.sinkSessions.get(sink);\n if (!set) { set = new Set(); this.sinkSessions.set(sink, set); }\n set.add(sessionId);\n }\n\n markSinkClosed(sink: BridgeSink, sessionId: string): void {\n this.sinkSessions.get(sink)?.delete(sessionId);\n }\n\n dropSinkSessions(sink: BridgeSink): void {\n this.sinkSessions.delete(sink);\n }\n\n private isViewedBy(sink: BridgeSink, sessionId: string): boolean {\n return this.sinkSessions.get(sink)?.has(sessionId) ?? false;\n }\n\n /** F-9: when a notification-worthy event fires, mirror it to every\n * online device that is not currently viewing the session (the s2c.notify\n * frame counts toward the seq cursor and joins the replay ring per\n * PROTOCOL §6 + §7), then fan the same payload out to offline devices\n * holding an APNs token. */\n private emitNotify(args: {\n sessionId: string\n category: NotifyCategory\n title: string\n body: string\n notificationId: string\n }): void {\n if (this.subagentSessionIds.has(args.sessionId)) return;\n const body = args.body.length > 120 ? args.body.slice(0, 119) + '…' : args.body;\n this.record(\n 's2c.notify',\n {\n notificationId: args.notificationId,\n category: args.category,\n sessionId: args.sessionId,\n title: args.title,\n body,\n ts: Date.now(),\n },\n (sink) => this.isViewedBy(sink, args.sessionId),\n );\n this.fanOutPush({\n notificationId: args.notificationId,\n category: args.category,\n sessionId: args.sessionId,\n title: args.title,\n body,\n });\n }\n\n /** F-9: when a turn completes, notify every device not viewing the session. */\n private emitTurnCompletedNotify(sessionId: string, ok: boolean): void {\n if (this.subagentSessionIds.has(sessionId)) return;\n\n const row = this.summaries.get(sessionId);\n const title = ok ? '任务完成' : '任务异常结束';\n const body = this.lastAssistantText.get(sessionId) ?? row?.title ?? '';\n this.emitNotify({\n sessionId,\n category: ok ? 'turn.completed' : 'session.error',\n title,\n body,\n notificationId: 'n-' + (this.cursor + 1),\n });\n }\n\n /**\n * Mirror one notification-worthy event to offline devices. Fire-and-forget:\n * push failures must never block or break the WS data plane.\n */\n private fanOutPush(notification: PushNotification): void {\n try {\n this.pushOutlet?.fanOut(notification);\n } catch {\n // outlet misbehavior must not take down the bridge\n }\n }\n\n\n /** Remember the latest assistant text so notifications can quote it. */\n private captureAssistantText(sessionId: string, event: SessionEventLike): void {\n\n if (event.type !== 'assistant/message') return;\n\n const text = messageText(event.data).trim();\n\n if (text.length > 0) this.lastAssistantText.set(sessionId, text.slice(-160));\n }\n\n /**\n * Replay buffered pushes after the given cursor; false when the gap is\n * unrecoverable. Frames go to `target` only — replaying into every sink\n * duplicated the whole window onto devices that never asked for it.\n */\n resumeFrom(cursor: number, target?: BridgeSink): boolean {\n const oldest = this.ring.length > 0 ? this.ring[0]!.seq : this.cursor + 1;\n if (cursor + 1 < oldest) return false;\n const receivers = target !== undefined ? [target] : [...this.sinks];\n for (const entry of this.ring) {\n if (entry.seq > cursor) {\n for (const sink of receivers) sink.replay([entry]);\n }\n }\n for (const sink of receivers) sink.replayDone();\n return true;\n }\n\n private record(type: string, payload: unknown, except?: (sink: BridgeSink) => boolean): void {\n if (this.disposed) return\n this.cursor += 1;\n const entry = { seq: this.cursor, type, payload };\n this.ring.push(entry);\n if (this.ring.length > this.historyBufferMax) {\n this.ring.splice(0, this.ring.length - this.historyBufferMax);\n }\n for (const sink of this.sinks) {\n if (except && except(sink)) continue;\n sink.push(type, payload, entry.seq);\n }\n }\n\n\n // ---------- lifecycle ----------\n\n /** Start consuming host + mux streams. Idempotent; aborts on dispose(). */\n start(): void {\n if (this.started || this.disposed) return\n this.started = true\n void this.runHostStream();\n void this.runMuxStream();\n void this.refreshSummaries();\n }\n\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.abort.abort();\n this.sinks.clear();\n this.sinkSessions.clear();\n this.pushOutlet = undefined;\n }\n\n private async runHostStream(): Promise<void> {\n try {\n for await (const item of this.apiProxy.events.host({ rpcId: randomUUID() }, this.abort.signal)) {\n const frame = unwrapStreamItem(item);\n this.onHostFrame(frame);\n }\n } catch {\n // stream ended (dispose or host shutdown); bridges degrade to RPC-only\n }\n }\n\n private async runMuxStream(): Promise<void> {\n try {\n for await (const item of this.apiProxy.events.mux({ rpcId: randomUUID() }, this.abort.signal)) {\n const frame = unwrapStreamItem(item);\n this.onMuxFrame(frame);\n }\n } catch {\n // ditto\n }\n }\n\n private onHostFrame(frame: MuxFrameLike): void {\n switch (frame.type) {\n case 'host/session-added':\n case 'host/session-removed':\n case 'host/workspace-changed':\n case 'host/workspace-removed':\n case 'host/workspace-order-changed':\n void this.refreshSummaries();\n break;\n case 'host/archived-sessions-changed': {\n const archived = (frame as { archivedSessionIds?: unknown }).archivedSessionIds\n if (Array.isArray(archived)) {\n this.archivedSessionIds = new Set(archived.map(String))\n }\n void this.refreshSummaries();\n break;\n }\n case 'host/session-status': {\n const p = frame as { sessionId?: string; running?: boolean };\n const row = this.summaries.get(String(p.sessionId));\n if (row && typeof p?.running === 'boolean') {\n row.status = p.running ? 'running' : 'idle';\n this.pushSummary(row);\n }\n break;\n }\n default:\n break;\n }\n }\n\n private onMuxFrame(frame: MuxFrameLike): void {\n switch (frame.type) {\n case 'session/event': {\n const event = frame.event as SessionEventLike | undefined;\n const sessionId = String(frame.sessionId ?? '');\n if (!event || !sessionId) break;\n this.noteActivity(sessionId, event);\n this.captureAssistantText(sessionId, event);\n const projection = projectEvent(sessionId, event);\n if (projection) {\n this.record('s2c.session.event', { sessionId, kind: projection.kind, seq: event.seq, data: projection.data });\n }\n if (projection?.kind === 'turn.end') {\n this.emitTurnCompletedNotify(sessionId, projection.data.ok === true);\n }\n break;\n }\n case 'session/projection': {\n const p = frame as { sessionId?: string; key?: string; value?: unknown };\n if (!p.sessionId) break;\n this.applyProjection(p.sessionId, String(p.key ?? ''), p.value);\n break;\n }\n case 'approval/requested': {\n const p = frame as { sessionId?: string; approvalId?: string; toolName?: string; reason?: string };\n if (!p.approvalId || !frame.rpcId) break;\n const toolName = String(p.toolName ?? 'tool');\n const summary = String(p.reason ?? '');\n const sessionId = String(p.sessionId ?? '');\n this.approvals.set(p.approvalId, {\n rpcId: frame.rpcId,\n sessionId,\n toolName,\n reason: summary,\n });\n this.record('s2c.pending.approval', {\n requestId: p.approvalId,\n sessionId,\n toolName,\n summary,\n riskLevel: riskOf(toolName),\n });\n this.emitNotify({\n sessionId,\n category: 'approval.required',\n title: '需要批准',\n body: toolName + ': ' + summary,\n notificationId: 'apr-' + p.approvalId,\n });\n this.bumpPendingFlags(sessionId);\n break;\n }\n case 'approval/resolved': {\n const p = frame as { approvalId?: string };\n if (!p.approvalId) break;\n const pending = this.approvals.get(p.approvalId);\n this.approvals.delete(p.approvalId);\n this.record('s2c.pending.cleared', { requestId: p.approvalId });\n if (pending) this.bumpPendingFlags(pending.sessionId);\n break;\n }\n case 'question/requested': {\n const p = frame as { sessionId?: string; questions?: unknown };\n if (!frame.rpcId) break;\n const requestId = 'q-' + frame.rpcId;\n const sessionId = String(p?.sessionId ?? '');\n this.questions.set(requestId, { rpcId: frame.rpcId, sessionId, questions: p?.questions });\n this.record('s2c.pending.question', { requestId, sessionId, questions: p?.questions ?? [] });\n this.emitNotify({\n sessionId,\n category: 'question.asked',\n title: '有问题需要回答',\n body: firstQuestionText(p?.questions),\n notificationId: requestId,\n });\n this.bumpPendingFlags(sessionId);\n break;\n }\n case 'question/resolved': {\n const p = frame as { questionRpcId?: string };\n if (!p.questionRpcId) break;\n const requestId = 'q-' + p.questionRpcId;\n const pending = this.questions.get(requestId);\n this.questions.delete(requestId);\n this.record('s2c.pending.cleared', { requestId });\n if (pending) this.bumpPendingFlags(pending.sessionId);\n break;\n }\n default:\n break;\n }\n }\n\n\n // ---------- session mirror ----------\n\n async refreshSummaries(): Promise<void> {\n try {\n const response = await this.apiProxy.sessions.list({ rpcId: randomUUID(), payload: {} });\n if (!response.result || !response.result.ok) {\n this.diagnostic('sessions.list rejected: ' + JSON.stringify(response.result ?? null).slice(0, 200));\n return;\n }\n let workspaces: WorkspaceViewLike[] = []\n const workspaceList = this.apiProxy.workspace?.list\n if (typeof workspaceList === 'function') {\n const workspaceResponse = await workspaceList.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: {},\n })\n if (workspaceResponse.result?.ok) {\n workspaces = workspaceResponse.result.value.items ?? []\n this.archivedSessionIds = new Set(\n (workspaceResponse.result.value.archivedSessionIds ?? []).map(String),\n )\n }\n }\n const previousIds = new Set(this.summaries.keys())\n const workspaceBySession = new Map<string, WorkspaceViewLike>()\n for (const workspace of workspaces) {\n for (const sessionId of workspace.sessionIds ?? []) {\n workspaceBySession.set(String(sessionId), workspace)\n }\n }\n const next = new Map<string, SessionSummary>();\n const subagentIds = new Set<string>();\n for (const row of response.result.value.items ?? []) {\n if (this.archivedSessionIds.has(row.sessionId)) continue\n if (isSubagentRow(row)) {\n subagentIds.add(row.sessionId);\n continue;\n }\n next.set(row.sessionId, toSummary(row, this.approvals, this.questions, workspaceBySession.get(row.sessionId)));\n }\n this.subagentSessionIds = subagentIds;\n this.summaries = next;\n const removedIds = [...previousIds].filter((id) => !next.has(id))\n // sessions.list is authoritative. This also removes assistant snippets\n // captured for child/subagent event streams that never enter summaries.\n for (const id of this.lastAssistantText.keys()) {\n if (!next.has(id)) this.lastAssistantText.delete(id)\n }\n this.record('s2c.sessions.delta', { upserted: [...next.values()], removedIds });\n } catch {\n // apiProxy absent or transient failure; keep last mirror\n }\n }\n\n /** Cold sessions may lack a title projection; fall back to first user text. */\n private deriveTitleFallback(sessionId: string, messages: MessageProjection[]): void {\n const row = this.summaries.get(sessionId);\n if (!row || row.title.length > 0) return;\n const firstUser = messages.find(m => m.role === 'user' && (m.text ?? '').trim().length > 0);\n if (!firstUser) return;\n row.title = firstUser!.text!.replace(/\\s+/g, ' ').trim().slice(0, 60);\n this.pushSummary(row);\n }\n\n private noteActivity(sessionId: string, event?: SessionEventLike): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n // Recency must reflect USER-VISIBLE milestones only: a new prompt moves\n // a session to the top and a finished turn settles it into place. Token\n // chunks / tool calls / per-step assistant messages fire constantly while\n // an agent works; counting them made concurrently running sessions fight\n // over the top slot in every recency-sorted list.\n switch (event?.type) {\n case 'user/message':\n case 'turn/start':\n case 'turn/end':\n break;\n default:\n return;\n }\n row.lastActivityTs = Date.now();\n this.pushSummary(row);\n }\n\n private applyProjection(sessionId: string, key: string, value: unknown): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n if (key === 'title') {\n row.title = typeof value === 'string' ? value : '';\n } else if (key === 'todos') {\n const items = Array.isArray(value) ? value as Array<{ content?: unknown; status?: unknown }> : null;\n const sanitized = sanitizeTodoItems(items);\n row.todoItems = sanitized.length > 0 ? sanitized : null;\n row.todos = sanitized.length > 0\n ? { done: sanitized.filter(i => i.status === 'completed').length, total: sanitized.length }\n : null;\n } else if (key === 'sessionListMetadata') {\n const meta = value as { lastPromptAt?: number } | null;\n if (meta?.lastPromptAt) row.lastActivityTs = Math.max(row.lastActivityTs, meta.lastPromptAt);\n } else {\n return;\n }\n this.pushSummary(row);\n }\n\n private bumpPendingFlags(sessionId: string): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n let approval = false;\n for (const pending of this.approvals.values()) {\n if (pending.sessionId === sessionId) approval = true;\n }\n let question = false;\n for (const pending of this.questions.values()) {\n if (pending.sessionId === sessionId) question = true;\n }\n row.pendingApproval = approval;\n row.pendingQuestion = question;\n this.pushSummary(row);\n }\n\n private pushSummary(row: SessionSummary): void {\n this.record('s2c.sessions.delta', { upserted: [row], removedIds: [] });\n }\n\n listSessions(): SessionSummary[] {\n return [...this.summaries.values()].sort((a, b) => b.lastActivityTs - a.lastActivityTs);\n }\n\n /**\n * Complete transient interaction state. Unlike the replay ring, this remains\n * authoritative after a long disconnect and is rehydrated by apiProxy's mux\n * stream when the bridge itself restarts.\n */\n pendingSnapshot(): PendingSnapshotPayload {\n return {\n approvals: [...this.approvals.entries()].map(([requestId, pending]) => ({\n requestId,\n sessionId: pending.sessionId,\n toolName: pending.toolName,\n summary: pending.reason,\n riskLevel: riskOf(pending.toolName),\n })),\n questions: [...this.questions.entries()].map(([requestId, pending]) => ({\n requestId,\n sessionId: pending.sessionId,\n questions: Array.isArray(pending.questions)\n ? pending.questions as PendingSnapshotPayload['questions'][number]['questions']\n : [],\n })),\n };\n }\n\n // ---------- data operations ----------\n\n /** Tail history for an opened session; pushes s2c.session.tail to the sink. */\n async openSession(sink: BridgeSink, sessionId: string, tailCount: number): Promise<boolean> {\n try {\n const response = await this.apiProxy.sessions.history({\n rpcId: randomUUID(),\n payload: { sessionId, maxMessages: clampTail(tailCount) },\n });\n if (!response.result || !response.result.ok) return false;\n const result = response.result.value;\n const projected = projectHistory(result.events ?? []);\n const page = limitSessionPageMessages(projected);\n const messages = page.messages;\n const oldestSeq = messages.length > 0 ? messages[0]!.seq : 0;\n sink.push('s2c.session.tail', {\n sessionId,\n messages,\n oldestSeq,\n hasMore: Boolean(result.hasMore) || page.dropped > 0,\n });\n this.deriveTitleFallback(sessionId, messages);\n return true;\n } catch {\n return false;\n }\n }\n\n async historyPage(\n sessionId: string,\n beforeSeq: number,\n limit: number,\n ): Promise<{ sessionId: string; messages: MessageProjection[]; hasMore: boolean } | null> {\n try {\n const response = await this.apiProxy.sessions.history({\n rpcId: randomUUID(),\n payload: { sessionId, beforeSeq, maxMessages: clampTail(limit) },\n });\n if (!response.result || !response.result.ok) return null;\n const result = response.result.value;\n // Some host versions include the boundary event even though beforeSeq\n // is exclusive. Enforce the phone protocol here so a client can never\n // request and append the same page indefinitely.\n const projected = projectHistory(result.events ?? [])\n .filter((message) => message.seq < beforeSeq);\n const page = limitSessionPageMessages(projected);\n return {\n sessionId,\n messages: page.messages,\n // An empty exclusive page cannot advance beforeSeq. Advertising more\n // here would make the client request the same boundary forever.\n hasMore: page.messages.length > 0 && (Boolean(result.hasMore) || page.dropped > 0),\n };\n } catch {\n return null;\n }\n }\n\n /** Result of one attachment read-back for the phone. */\n async attachmentData(\n sessionId: string,\n attachmentId: string,\n ): Promise<{ mediaType?: string; data: string } | null> {\n const read = this.apiProxy.sessions.attachment\n if (typeof read !== 'function') return null;\n try {\n const response = await read.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId, attachmentId },\n });\n if (!response.result || !response.result.ok) return null;\n const data = response.result.value.data;\n if (typeof data !== 'string' || data.length === 0) return null;\n return {\n ...(typeof response.result.value.attachment?.mediaType === 'string'\n ? { mediaType: response.result.value.attachment.mediaType as string }\n : {}),\n data,\n };\n } catch {\n return null;\n }\n }\n\n async sessionModels(sessionId: string): Promise<ModelBridgeResult<HostSessionModels>> {\n const models = this.apiProxy.sessions.models\n if (typeof models !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'model catalog unavailable on this host version' }\n }\n try {\n const response = await models.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'model catalog returned no result' }\n if (!response.result.ok) return hostModelError(response.result.error)\n return { ok: true, value: projectSessionModels(response.result.value) }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async selectSessionModel(\n sessionId: string,\n selection: HostModelSelection,\n ): Promise<ModelBridgeResult<HostModelSelection>> {\n const selectModel = this.apiProxy.sessions.selectModel\n if (typeof selectModel !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'model selection unavailable on this host version' }\n }\n try {\n const response = await selectModel.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: {\n sessionId,\n provider: selection.provider,\n model: selection.model,\n ...(selection.reasoningEffort ? { reasoningEffort: selection.reasoningEffort } : {}),\n },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'model selection returned no result' }\n if (!response.result.ok) return hostModelError(response.result.error)\n return { ok: true, value: { ...response.result.value.selected } }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async renameSession(sessionId: string, title: string): Promise<SessionManagementResult<string>> {\n const rename = this.apiProxy.sessions.rename\n if (typeof rename !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session rename unavailable on this host version' }\n }\n try {\n const response = await rename.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId, title },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session rename returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n const acceptedTitle = String(response.result.value.title)\n const row = this.summaries.get(sessionId)\n if (row) {\n row.title = acceptedTitle\n this.pushSummary(row)\n }\n return { ok: true, value: acceptedTitle }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async archiveSession(sessionId: string): Promise<SessionManagementResult<true>> {\n const archive = this.apiProxy.workspace?.archiveSession\n if (typeof archive !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session archive unavailable on this host version' }\n }\n try {\n const response = await archive.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session archive returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n this.archivedSessionIds = new Set(\n (response.result.value.archivedSessionIds ?? []).map(String),\n )\n this.summaries.delete(sessionId)\n this.lastAssistantText.delete(sessionId)\n this.record('s2c.sessions.delta', { upserted: [], removedIds: [sessionId] })\n return { ok: true, value: true }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async cancelSession(sessionId: string): Promise<SessionManagementResult<true>> {\n const cancel = this.apiProxy.sessions.cancel\n if (typeof cancel !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session cancel unavailable on this host version' }\n }\n try {\n const response = await cancel.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session cancel returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: true }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async listWorkspaces(): Promise<SessionManagementResult<Array<{\n id: string; title: string; path: string; sessionIds: string[]\n }>>> {\n const list = this.apiProxy.workspace?.list\n if (typeof list !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'workspace list unavailable on this host version' }\n }\n try {\n const response = await list.call(this.apiProxy.workspace, { rpcId: randomUUID(), payload: {} })\n if (!response.result) return { ok: false, kind: 'internal', message: 'workspace list returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: (response.result.value.items ?? []).map(projectWorkspace) }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async createWorkspace(path: string): Promise<SessionManagementResult<{\n workspace: { id: string; title: string; path: string; sessionIds: string[] }; created: boolean\n }>> {\n const create = this.apiProxy.workspace?.create\n if (typeof create !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'workspace create unavailable on this host version' }\n }\n try {\n const response = await create.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: { path },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'workspace create returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n await this.refreshSummaries()\n return {\n ok: true,\n value: { workspace: projectWorkspace(response.result.value.workspace), created: response.result.value.created === true },\n }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async listDirectory(path?: string): Promise<SessionManagementResult<DirectoryListingLike>> {\n const list = this.apiProxy.host?.listDirectory\n if (typeof list !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'directory browsing unavailable on this host version' }\n }\n try {\n const response = await list.call(this.apiProxy.host, {\n rpcId: randomUUID(),\n payload: path && path.trim().length > 0 ? { path } : {},\n }, this.abort.signal)\n if (!response.result) return { ok: false, kind: 'internal', message: 'directory list returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: response.result.value }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async pickDirectory(): Promise<SessionManagementResult<string | null>> {\n const pick = this.apiProxy.host?.pickDirectory\n if (typeof pick !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'native directory picker unavailable on this host version' }\n }\n try {\n const response = await pick.call(this.apiProxy.host, {\n rpcId: randomUUID(),\n payload: {},\n }, this.abort.signal)\n if (!response.result) return { ok: false, kind: 'internal', message: 'directory picker returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: response.result.value.path }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n /** Create a fresh blank session in an existing workspace or legacy cwd. */\n async createSession(destination: { workspaceId?: string; cwd?: string } = {}): Promise<string | null> {\n try {\n const response = await this.apiProxy.sessions.create({\n rpcId: randomUUID(),\n payload: {\n ...(destination.workspaceId?.trim() ? { workspaceId: destination.workspaceId.trim() } : {}),\n ...(destination.cwd?.trim() ? { cwd: destination.cwd.trim() } : {}),\n },\n });\n if (!response.result || !response.result.ok) return null;\n const sessionId = response.result.value.sessionId;\n await this.refreshSummaries();\n return sessionId;\n } catch {\n return null;\n }\n }\n\n async sendPrompt(\n sessionId: string,\n text: string,\n images: Array<{ mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; data: string; name?: string }> = [],\n documents: PromptDocument[] = [],\n ): Promise<SessionManagementResult<number>> {\n try {\n const content: PromptArgs['content'] = [];\n if (text.trim().length > 0) content.push({ type: 'text', text });\n for (const image of images) content.push({ type: 'image', ...image });\n for (const document of documents) content.push({ type: 'text', text: documentPromptBlock(document) });\n const response = await this.apiProxy.sessions.prompt({\n rpcId: randomUUID(),\n payload: {\n sessionId,\n mode: 'queue',\n content,\n clientTimeZone: localTimeZone(),\n },\n });\n if (!response.result) return { ok: false, kind: 'internal', message: 'prompt returned no result' };\n // Preserve the host's error kind so the phone can tell \"retry later\"\n // (E_BUSY) from \"session is gone\" (E_NOT_FOUND) instead of mapping\n // every failure onto E_BUSY.\n if (!response.result.ok) return hostSessionManagementError(response.result.error);\n const row = this.summaries.get(sessionId);\n if (row) {\n row.lastActivityTs = Date.now();\n this.pushSummary(row);\n }\n this.userReceiptSeq += 1;\n return { ok: true, value: this.userReceiptSeq };\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) };\n }\n }\n\n\n async respondApproval(\n requestId: string,\n decision: 'allow' | 'deny',\n reason?: string,\n ): Promise<PendingResponseOutcome> {\n const pending = this.approvals.get(requestId);\n if (!pending) return { ok: false, reason: 'not-pending' };\n // Claim the pending entry before responding: a second phone (or a double\n // tap) must not fire another client-response for the same rpcId while the\n // resolved frame is still in flight.\n this.approvals.delete(requestId);\n const outcome = decision === 'allow' ? 'allowed-once' : 'rejected';\n const denialReason = typeof reason === 'string' ? reason.trim().slice(0, 500) : '';\n try {\n const receipt = await this.apiProxy.respond({\n type: 'client-response',\n rpcId: pending.rpcId,\n result: {\n ok: true,\n value: {\n sessionId: pending.sessionId,\n approvalId: requestId,\n outcome,\n // PROTOCOL v2: a deny may carry the user's explanation so the\n // model can adjust course instead of blindly retrying.\n ...(denialReason.length > 0 ? { reason: denialReason } : {}),\n },\n },\n });\n const accepted = Boolean(receipt?.accepted);\n if (!accepted) {\n const failure = receiptFailureReason(receipt);\n // Restore only what the user can retry: `not-pending` means the host\n // already settled the request, and restoring would strand a ghost\n // entry that no future resolved frame will ever clear.\n if (failure !== 'not-pending' && !this.approvals.has(requestId)) {\n this.approvals.set(requestId, pending);\n }\n return { ok: false, reason: failure };\n }\n // The claim above removed the entry, so the upcoming approval/resolved\n // frame finds nothing left to bump — refresh the summary flags here or\n // the session badge stays \"pending\" until an unrelated refresh.\n this.bumpPendingFlags(pending.sessionId);\n return { ok: true };\n } catch {\n // Transport-level failure: give the request back so the user can retry.\n if (!this.approvals.has(requestId)) this.approvals.set(requestId, pending);\n return { ok: false, reason: 'transport' };\n }\n }\n\n async respondQuestion(requestId: string, answers: unknown): Promise<PendingResponseOutcome> {\n const pending = this.questions.get(requestId);\n if (!pending) return { ok: false, reason: 'not-pending' };\n this.questions.delete(requestId);\n try {\n const receipt = await this.apiProxy.respond({\n type: 'client-response',\n rpcId: pending.rpcId,\n result: { ok: true, value: { sessionId: pending.sessionId, answer: { answers: normalizeAnswerItems(answers, pending.questions) } } },\n });\n const accepted = Boolean(receipt?.accepted);\n if (!accepted) {\n const failure = receiptFailureReason(receipt);\n // Same ghost-entry rule as approvals: `not-pending` is final, never\n // restore — the host has no record left to resolve against.\n if (failure !== 'not-pending' && !this.questions.has(requestId)) {\n this.questions.set(requestId, pending);\n }\n return { ok: false, reason: failure };\n }\n // Mirror the approval path: the claimed entry cannot bump flags when the\n // resolved frame arrives, so recompute them right after acceptance.\n this.bumpPendingFlags(pending.sessionId);\n return { ok: true };\n } catch {\n if (!this.questions.has(requestId)) this.questions.set(requestId, pending);\n return { ok: false, reason: 'transport' };\n }\n }\n}\n\n/**\n * The host validates question answers strictly (core dsh-user-questions via\n * apiProxy): a present-but-empty `custom` fails `matchesQuestions`, and a\n * single-select question rejects `custom` combined with a selection. Clients\n * may send lenient shapes (the phone historically always attached\n * `\"custom\": \"\"`, which made EVERY option-only answer fail), so normalize to\n * exactly what the host accepts before forwarding.\n */\nexport function normalizeAnswerItems(\n raw: unknown,\n questions?: unknown,\n): Array<{ id: string; selected: string[]; custom?: string }> {\n if (!Array.isArray(raw)) return [];\n const askedById = new Map<string, { multiSelect?: unknown }>();\n if (Array.isArray(questions)) {\n for (const q of questions) {\n if (typeof q === 'object' && q !== null && typeof (q as { id?: unknown }).id === 'string') {\n askedById.set((q as { id: string }).id, q as { multiSelect?: unknown });\n }\n }\n }\n const items: Array<{ id: string; selected: string[]; custom?: string }> = [];\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue;\n const r = entry as { id?: unknown; selected?: unknown; custom?: unknown };\n if (typeof r.id !== 'string') continue;\n // De-duplicate while preserving order; duplicate labels are rejected by the host.\n const selected = [...new Set(\n Array.isArray(r.selected) ? r.selected.filter((s): s is string => typeof s === 'string') : [],\n )];\n const customText = typeof r.custom === 'string' ? r.custom : '';\n let custom: string | undefined;\n if (customText.trim().length > 0) custom = customText;\n // A single-select answer must be either options or free text, never both.\n if (custom !== undefined && selected.length > 0 && askedById.get(r.id)?.multiSelect !== true) {\n custom = undefined;\n }\n items.push({ id: r.id, selected, ...(custom !== undefined ? { custom } : {}) });\n }\n return items;\n}\n\n/** Map an apiProxy respond receipt onto the failure vocabulary. */\nfunction receiptFailureReason(receipt: { accepted: boolean; reason?: string } | undefined):\n 'not-pending' | 'bad-response' {\n return receipt?.reason === 'not-pending' ? 'not-pending' : 'bad-response';\n}\n\n// ---------- projection helpers ----------\n\nfunction clampTail(n: number): number {\n if (!Number.isFinite(n)) return 100;\n return Math.max(10, Math.min(500, Math.floor(n)));\n}\n\nfunction localTimeZone(): string | undefined {\n try {\n return new Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction riskOf(toolName: string): 'read' | 'write' | 'destructive' {\n if (/bash|pwsh|terminal/.test(toolName)) return 'write';\n if (/edit|write|str_replace|create/.test(toolName)) return 'write';\n if (/delete|remove|kill/.test(toolName)) return 'destructive';\n return 'read';\n}\n\n/** First question's text for the push banner; the questions payload shape is\n * host-version dependent, so extract defensively. */\nexport function firstQuestionText(questions: unknown): string {\n if (!Array.isArray(questions) || questions.length === 0) return 'Agent 等待你的输入';\n const first = questions[0] as { question?: unknown } | undefined;\n const text = String(first?.question ?? '').trim();\n return text || 'Agent 等待你的输入';\n}\n\nconst TODO_STATUSES = new Set(['pending', 'in_progress', 'completed']);\n\n/** Validate a host todo projection once; progress counts and the full\n * checklist both derive from this sanitized list so they never disagree. */\nfunction sanitizeTodoItems(items: Array<{ content?: unknown; status?: unknown }> | null): SessionTodoItem[] {\n if (!items) return [];\n return items\n .map(i => ({ content: String(i.content ?? '').trim(), status: String(i.status ?? '') }))\n .filter(i => i.content.length > 0 && TODO_STATUSES.has(i.status))\n .slice(0, 100)\n .map(i => ({ content: i.content, status: i.status as SessionTodoStatus }));\n}\n\nfunction toSummary(\n row: PhoneSessionRow,\n approvals: Map<string, PendingApproval>,\n questions: Map<string, PendingQuestion>,\n workspace?: WorkspaceViewLike,\n): SessionSummary {\n const values = row.projections?.values ?? {};\n const todos = Array.isArray(values.todos) ? values.todos as Array<{ content?: unknown; status?: unknown }> : null;\n let pendingApproval = false;\n for (const pending of approvals.values()) {\n if (pending.sessionId === row.sessionId) pendingApproval = true;\n }\n let pendingQuestion = false;\n for (const pending of questions.values()) {\n if (pending.sessionId === row.sessionId) pendingQuestion = true;\n }\n const cwd = typeof row.cwd === 'string' ? row.cwd : '';\n const label = workspace?.title ?? (cwd ? cwd.split('/').filter(Boolean).pop() : undefined);\n const todoItems = sanitizeTodoItems(todos);\n return {\n id: row.sessionId,\n title: typeof values.title === 'string' ? values.title : '',\n // A blank session has never run a turn, and the running flag above\n // already covers the live case. Reporting `unknown` here made the phone\n // treat the composer as \"still syncing\" forever: nothing ever converges\n // the state back because the first prompt is exactly what the disabled\n // button cannot send. Idle is truthful for every non-running blank row.\n status: row.running ? 'running' : 'idle',\n lastActivityTs: Number(row.updatedAt ?? Date.now()),\n todos: todoItems.length > 0\n ? {\n done: todoItems.filter(i => i.status === 'completed').length,\n total: todoItems.length,\n }\n : null,\n todoItems: todoItems.length > 0 ? todoItems : null,\n pendingApproval,\n pendingQuestion,\n workspaceLabel: label ?? null,\n workspaceId: workspace?.workspaceId ?? null,\n workspacePath: workspace?.path ?? (cwd || null),\n };\n}\n\nfunction projectWorkspace(workspace: WorkspaceViewLike): {\n id: string; title: string; path: string; sessionIds: string[]\n} {\n return {\n id: String(workspace.workspaceId),\n title: String(workspace.title),\n path: String(workspace.path),\n sessionIds: (workspace.sessionIds ?? []).map(String),\n }\n}\n\n/** Project one raw session event into a protocol push, when it maps to one. */\n\nfunction hostModelError(error: { code: string; message?: string }): ModelBridgeResult<never> {\n const message = error.message ?? error.code\n switch (error.code) {\n case 'session-not-found':\n return { ok: false, kind: 'not-found', message }\n case 'agent-busy':\n case 'session-conflict':\n return { ok: false, kind: 'busy', message }\n case 'model-unavailable':\n return { ok: false, kind: 'unavailable', message }\n default:\n return { ok: false, kind: 'internal', message }\n }\n}\n\nfunction hostSessionManagementError(\n error: { code: string; message?: string },\n): SessionManagementResult<never> {\n const message = error.message ?? error.code\n switch (error.code) {\n case 'session-not-found':\n return { ok: false, kind: 'not-found', message }\n case 'agent-busy':\n case 'session-conflict':\n return { ok: false, kind: 'busy', message }\n case 'title-invalid':\n case 'workspace-invalid-path':\n case 'workspace-name-conflict':\n case 'directory-unreadable':\n case 'directory-exists':\n case 'directory-create-failed':\n return { ok: false, kind: 'invalid', message }\n case 'directory-picker-unavailable':\n return { ok: false, kind: 'unsupported', message }\n case 'workspace-not-found':\n return { ok: false, kind: 'not-found', message }\n default:\n return { ok: false, kind: 'internal', message }\n }\n}\n\nfunction projectSessionModels(value: HostSessionModels): HostSessionModels {\n return {\n current: {\n provider: String(value.current.provider),\n model: String(value.current.model),\n ...(value.current.reasoningEffort ? { reasoningEffort: String(value.current.reasoningEffort) } : {}),\n },\n routable: value.routable === true,\n groups: (value.groups ?? []).map((group) => ({\n id: String(group.id),\n name: String(group.name),\n models: (group.models ?? []).map((model) => ({\n id: String(model.id),\n name: String(model.name),\n ...(model.description ? { description: String(model.description) } : {}),\n ...(model.reasoning ? {\n reasoning: {\n efforts: (model.reasoning.efforts ?? []).map((effort) => ({\n id: String(effort.id),\n name: String(effort.name),\n ...(effort.description ? { description: String(effort.description) } : {}),\n })),\n ...(model.reasoning.defaultEffort\n ? { defaultEffort: String(model.reasoning.defaultEffort) }\n : {}),\n },\n } : {}),\n })),\n })),\n failures: (value.failures ?? []).map((failure) => ({\n id: String(failure.id),\n name: String(failure.name),\n message: String(failure.message),\n })),\n }\n}\n\n/** Project a history page (raw events) into MessageProjection rows. */\n","/**\n * Resident DSH 0.1.2-alpha.3 Remote Events client for phone interactions.\n *\n * The Host-side `approval/request` and `user-questions/request` events are\n * owned once by DSH API Remotes. API Gateway then fans each pending waterfall\n * out to every connected Client and settles the first result. DeepPilot joins\n * that official Client plane in-process instead of registering a competing\n * Host waterfall listener or replacing the official Web composer.\n */\nimport { Context } from '@deepseek-ai/cordis'\nimport * as Cordis from '@deepseek-ai/cordis'\n\ninterface FetchHandlerLike {\n fetch(request: Request): Promise<Response>\n}\n\ninterface HostConnectionLike {\n createSharedFetchHandler(channel: '/api'): FetchHandlerLike\n}\n\ninterface HostGatewayLike {\n wireStream: {\n open(endpoint: string, payload: unknown, signal: AbortSignal): Promise<AsyncIterable<unknown>>\n }\n}\n\ninterface ClientTransportHooksLike {\n fetch(input: URL, init: RequestInit): Promise<Response>\n openStream(endpoint: string, payload: unknown, signal: AbortSignal): AsyncIterable<unknown>\n ownsHost: true\n}\n\ninterface ClientRemoteLike {\n $on(event: string, listener: (this: Context, request: any, next: () => Promise<unknown>) => unknown): () => void\n}\n\ninterface ClientTypertLike {\n contexts: {\n registerClient(key: string, adapter: {\n identity(candidate: Context): string | undefined\n resolve(identity: string): Context\n }): () => void\n }\n}\n\ninterface ClientPluginModule {\n apply(ctx: Context): void\n}\n\nexport interface RemoteApprovalRequest {\n toolName?: string\n callId?: string\n reason?: string\n signal?: AbortSignal\n}\n\nexport interface RemoteQuestionRequest {\n questions?: unknown\n signal?: AbortSignal\n}\n\nexport interface Dsh012RemoteInteractionHandlers {\n approval(sessionId: string, request: RemoteApprovalRequest, next: () => Promise<unknown>): unknown\n question(sessionId: string, request: RemoteQuestionRequest, next: () => Promise<unknown>): unknown\n}\n\ntype TransportGlobal = typeof globalThis & {\n __DSH_TRANSPORT__?: ClientTransportHooksLike\n}\n\ninterface ClientBundleDefinition {\n id: string\n factory(require: (id: string) => unknown): unknown\n}\n\ntype ClientBundleWindow = {\n __ModuleLoader__: {\n load(definition: ClientBundleDefinition): void\n }\n}\n\ntype LoaderGlobal = {\n window?: ClientBundleWindow\n}\n\ninterface ClientFaces {\n typert: ClientPluginModule\n connection: ClientPluginModule\n gateway: ClientPluginModule\n}\n\nlet clientFaces: Promise<ClientFaces> | undefined\n\n/**\n * Load DSH's browser-distributed Client faces into a tiny Host-side module\n * table. Published `lib/client.js` files register with `window.__ModuleLoader__`\n * rather than exporting ESM values, so a normal Node import cannot consume\n * them. The shim runs only while the three official bundles register; their\n * apply functions then operate against a non-browser Cordis Context.\n */\nfunction pluginModule(value: unknown, specifier: string): ClientPluginModule {\n if (typeof value !== 'object' || value === null) throw new Error(`${specifier} Client bundle returned no exports`)\n const record = value as Record<string, unknown>\n if (typeof record.apply !== 'function') throw new Error(`${specifier} has no Client apply() export`)\n return value as unknown as ClientPluginModule\n}\n\nasync function loadClientFaces(): Promise<ClientFaces> {\n clientFaces ??= (async () => {\n const modules = new Map<string, unknown>([['@deepseek-ai/cordis', Cordis]])\n const loaderGlobal = globalThis as unknown as LoaderGlobal\n const previousWindow = loaderGlobal.window\n loaderGlobal.window = {\n __ModuleLoader__: {\n load: definition => {\n const exports = definition.factory((id) => {\n if (!modules.has(id)) throw new Error(`resident DSH Client cannot resolve ${JSON.stringify(id)}`)\n return modules.get(id)\n })\n modules.set(definition.id, exports)\n },\n },\n }\n try {\n // Use variable specifiers to preserve DSH's Host/Client TypeScript face\n // split; static imports would merge incompatible Context declarations.\n for (const specifier of [\n '@deepseek-ai/dsh-typert-registry/client',\n '@deepseek-ai/dsh-client-connection/client',\n '@deepseek-ai/dsh-api-gateway/client',\n ]) await import(specifier)\n } finally {\n if (previousWindow === undefined) delete loaderGlobal.window\n else loaderGlobal.window = previousWindow\n }\n return {\n typert: pluginModule(modules.get('@deepseek-ai/dsh-typert-registry'), '@deepseek-ai/dsh-typert-registry/client'),\n connection: pluginModule(modules.get('@deepseek-ai/dsh-client-connection'), '@deepseek-ai/dsh-client-connection/client'),\n gateway: pluginModule(modules.get('@deepseek-ai/dsh-api-gateway'), '@deepseek-ai/dsh-api-gateway/client'),\n }\n })()\n return clientFaces\n}\n\nconst agentScopeKey = Symbol('deeppilot.dsh-client.agent-scope')\n\ntype AgentContext = Context & { [agentScopeKey]?: string }\n\nfunction scopeOf(ctx: Context): string | undefined {\n return (ctx as AgentContext)[agentScopeKey]\n}\n\nfunction createAgentScope(ctx: Context, identity: string): Context {\n const fiber = ctx.plugin(function deeppilotAgentScope() {})\n return fiber.ctx.extend({\n [agentScopeKey]: identity,\n [Context.filter](listenerCtx: Context) {\n const listenerIdentity = scopeOf(listenerCtx)\n return listenerIdentity === undefined || listenerIdentity === identity\n },\n })\n}\n\nfunction inProcessStream(\n gateway: HostGatewayLike,\n endpoint: string,\n payload: unknown,\n signal: AbortSignal,\n): AsyncIterable<unknown> {\n return (async function* () {\n const source = await gateway.wireStream.open(endpoint, payload, signal)\n yield* source\n })()\n}\n\n/**\n * Start one headless official DSH Client backed by the Host's in-process\n * Connection and Gateway carriers.\n *\n * The returned disposer tears down the Remote Events generation, all pending\n * listeners, and every lazily minted Agent scope.\n */\nexport async function startDsh012RemoteInteractions(\n hostCtx: Context,\n handlers: Dsh012RemoteInteractionHandlers,\n): Promise<() => Promise<void>> {\n const connection = hostCtx.get('connection') as HostConnectionLike | undefined\n const gateway = hostCtx.get('typertGateway') as HostGatewayLike | undefined\n if (connection === undefined) throw new Error('dsh 0.1.2-alpha.3 Host connection is unavailable')\n if (gateway === undefined) throw new Error('dsh 0.1.2-alpha.3 typertGateway is unavailable')\n\n const faces = await loadClientFaces()\n\n const client = new Context()\n const fetchHandler = connection.createSharedFetchHandler('/api')\n const transport: ClientTransportHooksLike = {\n fetch: (input, init) => fetchHandler.fetch(new Request(input, init)),\n openStream: (endpoint, payload, signal) => inProcessStream(gateway, endpoint, payload, signal),\n ownsHost: true,\n }\n\n try {\n faces.typert.apply(client)\n\n // Client Connection reads this hook once during apply() and retains the\n // concrete functions. Restore the process global immediately afterward so\n // no unrelated Client composition inherits DeepPilot's carrier.\n const transportGlobal = globalThis as TransportGlobal\n const previousTransport = transportGlobal.__DSH_TRANSPORT__\n transportGlobal.__DSH_TRANSPORT__ = transport\n try {\n faces.connection.apply(client)\n } finally {\n if (previousTransport === undefined) delete transportGlobal.__DSH_TRANSPORT__\n else transportGlobal.__DSH_TRANSPORT__ = previousTransport\n }\n\n const typert = client.get('typert') as ClientTypertLike | undefined\n if (typert === undefined) throw new Error('resident DSH Client typert service was not installed')\n const scopes = new Map<string, Context>()\n typert.contexts.registerClient('agent', {\n identity: candidate => scopeOf(candidate),\n resolve: identity => {\n let scope = scopes.get(identity)\n if (scope === undefined) {\n scope = createAgentScope(client, identity)\n scopes.set(identity, scope)\n }\n return scope\n },\n })\n\n // The Gateway opens its Remote Events generation asynchronously. Register\n // both listeners immediately after apply so a replayed pending request is\n // claimed before the first stream item can be dispatched.\n faces.gateway.apply(client)\n const remote = client.get('remote') as ClientRemoteLike | undefined\n if (remote === undefined) throw new Error('resident DSH Client remote service was not installed')\n remote.$on('approval/request', function (request, next) {\n return handlers.approval(scopeOf(this) ?? '', request as RemoteApprovalRequest, next)\n })\n remote.$on('user-questions/request', function (request, next) {\n return handlers.question(scopeOf(this) ?? '', request as RemoteQuestionRequest, next)\n })\n\n return async () => {\n await client.fiber.dispose()\n }\n } catch (error) {\n await client.fiber.dispose()\n throw error\n }\n}\n","/**\n * Compatibility façade for the DSH 0.1.2 controller API.\n *\n * DeepPilot's phone protocol deliberately speaks one stable in-process\n * `apiProxy` vocabulary. Harness 0.1.2 removed that service in favor of\n * direct Session/Workspace controllers plus Gateway-backed Remote Events.\n * This adapter rebuilds the small subset the bridge needs from those public\n * controllers and joins the official Client interaction plane in-process,\n * keeping the phone protocol isolated from the Host API migration.\n */\nimport { randomUUID } from 'node:crypto'\nimport type { Context } from '@deepseek-ai/cordis'\nimport {\n startDsh012RemoteInteractions,\n type RemoteApprovalRequest,\n type RemoteQuestionRequest,\n} from './dsh012-remote-interactions.ts'\nimport { isSubagentRow } from './host-api.ts'\nimport { projectHistory } from './host-event-projection.ts'\nimport type {\n ApiProxyLike,\n DirectoryListingLike,\n HistoryResult,\n HostSessionModels,\n MuxFrameLike,\n PhoneSessionRow,\n WorkspaceViewLike,\n} from './host-api.ts'\n\ninterface RpcOk<T> { ok: true; value: T }\ninterface RpcErr { ok: false; error: { code: string; message?: string } }\ntype RpcResult<T> = RpcOk<T> | RpcErr\n\ninterface SessionControllerLike {\n list(request: { cursor?: string }, signal: AbortSignal): Promise<{ items: readonly unknown[] }>\n inspect(sessionId: string, signal?: AbortSignal): Promise<{ events: readonly unknown[] }>\n create(request: Record<string, unknown>): Promise<{ sessionId: string; agentPreset?: string }>\n modelCatalog(): Promise<unknown>\n selectModel(request: Record<string, unknown>): Promise<{ selected: { provider: string; model: string; reasoningEffort?: string } }>\n rename(request: { sessionId: string; title: string }): Promise<{ title: string; seq: number }>\n prompt(request: Record<string, unknown>, signal: AbortSignal): Promise<{ accepted: true }>\n attachment(request: { sessionId: string; attachmentId: string }): Promise<{ attachment: { mediaType?: string }; data: string }>\n cancel(request: { sessionId: string }): { accepted: true }\n}\n\ninterface WorkspaceControllerLike {\n create(request: { path: string }): Promise<{ workspace: unknown; created: boolean }>\n archiveSession(request: { sessionId: string }): Promise<{ archivedSessionIds: readonly string[] }>\n follow(signal: AbortSignal): AsyncIterable<{ type: string; value?: unknown }>\n}\n\ninterface DirectoryPickerControllerLike {\n list(path: string | undefined, signal: AbortSignal): Promise<DirectoryListingLike>\n pick(signal: AbortSignal): Promise<string | null>\n}\n\ninterface DeferredInteraction {\n resolve(value: unknown): void\n /** Convert the stable phone-protocol response into the 0.1.2 waterfall result. */\n map(value: unknown): unknown\n}\n\n/** Which DSH 0.1.2 first-answer-wins interaction a phone may surface. */\nexport type DshInteractionKind = 'approval' | 'question'\n\nexport interface Dsh012ApiProxyOptions {\n /**\n * Decide whether the resident DeepPilot Remote Client represents a usable\n * phone surface. Returning false delegates only this Client delivery; API\n * Gateway keeps the official Web delivery independent.\n */\n shouldSurfaceInteraction?: (kind: DshInteractionKind) => boolean\n}\n\n/** Direct-controller facade with the exact legacy shape HostBridge consumes. */\nexport class Dsh012ApiProxy implements ApiProxyLike {\n private readonly session: SessionControllerLike\n private readonly workspaceController: WorkspaceControllerLike | undefined\n private readonly directoryPicker: DirectoryPickerControllerLike | undefined\n private readonly interactions = new Map<string, DeferredInteraction>()\n private readonly shouldSurfaceInteraction: (kind: DshInteractionKind) => boolean\n\n constructor(private readonly ctx: Context, options: Dsh012ApiProxyOptions = {}) {\n const session = ctx.get('sessionController') as SessionControllerLike | undefined\n if (session === undefined) throw new Error('dsh 0.1.2 sessionController is unavailable')\n this.session = session\n this.workspaceController = ctx.get('workspaceController') as WorkspaceControllerLike | undefined\n this.directoryPicker = ctx.get('directoryPickerController') as DirectoryPickerControllerLike | undefined\n this.shouldSurfaceInteraction = options.shouldSurfaceInteraction ?? (() => true)\n }\n\n /**\n * Decide whether this Gateway Client can surface a phone card. The decision\n * fails open to false so a broken device registry delegates this delivery\n * while the official Web Client remains able to answer.\n */\n private canSurfaceInteraction(kind: DshInteractionKind): boolean {\n try {\n return this.shouldSurfaceInteraction(kind)\n } catch {\n return false\n }\n }\n\n readonly sessions: ApiProxyLike['sessions'] = {\n list: async () => this.call(async () => {\n const value = await this.session.list({}, new AbortController().signal)\n // A list row can outlive a corrupt/unsupported persisted log. Do not\n // advertise it to a phone that cannot later open its history.\n return {\n // DeepPilot intentionally never exposes subagent workers to a phone.\n // In 0.1.2 their durable read address additionally requires a parent.\n items: value.items.map(toPhoneSessionRow).filter(row => !isSubagentRow(row)),\n }\n }),\n history: async (request) => this.call(async () => {\n const sessionId = request.payload!.sessionId\n let inspected: { events: readonly unknown[] }\n try {\n inspected = await this.session.inspect(sessionId)\n } catch (error) {\n // No message data is logged: only the opaque session id and Host's\n // safe error chain, enough to distinguish an unsupported legacy log\n // from a bridge regression.\n console.warn(`[deeppilot] session history unavailable for ${JSON.stringify(sessionId)}: ${toError(error).code}: ${toError(error).message}`)\n throw error\n }\n const before = request.payload?.beforeSeq\n const limit = Math.max(1, request.payload?.maxMessages ?? 100)\n const source = inspected.events\n .filter((event): event is HistoryResult['events'][number]['event'] =>\n typeof event === 'object' && event !== null\n && typeof (event as { type?: unknown }).type === 'string'\n && typeof (event as { seq?: unknown }).seq === 'number')\n .filter(event => before === undefined || event.seq < before)\n let end = source.length\n let events: HistoryResult['events'] = []\n while (end > 0 && projectHistory(events).length < limit) {\n const start = Math.max(0, end - limit)\n events = [\n ...source.slice(start, end).map(event => ({ event })),\n ...events,\n ]\n end = start\n }\n let trimmed = false\n while (events.length > 0 && projectHistory(events).length > limit) {\n events = events.slice(1)\n trimmed = true\n }\n return { events, hasMore: end > 0 || trimmed }\n }),\n prompt: async (request) => this.call(() => this.session.prompt({\n ...request.payload!,\n requestId: request.rpcId ?? randomUUID(),\n }, new AbortController().signal)),\n create: async (request) => this.call(() => this.session.create(request.payload ?? {})),\n models: async (request) => this.call(async () => projectModels(\n await this.session.modelCatalog(),\n String(request.payload?.sessionId ?? ''),\n await this.session.list({}, new AbortController().signal),\n )),\n selectModel: async (request) => this.call(() => this.session.selectModel(request.payload ?? {})),\n rename: async (request) => this.call(() => this.session.rename(request.payload!)),\n cancel: async (request) => this.call(() => this.session.cancel(request.payload!)),\n attachment: async (request) => this.call(() => this.session.attachment(request.payload!)),\n }\n\n readonly workspace: ApiProxyLike['workspace'] = {\n list: async () => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const baseline = await readWorkspaceBaseline(this.workspaceController)\n return {\n items: baseline.items.map(toWorkspaceView),\n archivedSessionIds: baseline.archivedSessionIds.map(String),\n }\n }),\n create: async (request) => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const value = await this.workspaceController.create(request.payload!)\n return { workspace: toWorkspaceView(value.workspace), created: value.created === true }\n }),\n archiveSession: async (request) => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const value = await this.workspaceController.archiveSession(request.payload!)\n return { archivedSessionIds: [...value.archivedSessionIds] }\n }),\n }\n\n readonly host: ApiProxyLike['host'] = {\n listDirectory: async (request, signal) => this.call(async () => {\n if (this.directoryPicker === undefined) throw unavailable('directory picker unavailable')\n return await this.directoryPicker.list(request.payload?.path, signal ?? new AbortController().signal)\n }),\n pickDirectory: async (_request, signal) => this.call(async () => {\n if (this.directoryPicker === undefined) throw unavailable('directory picker unavailable')\n return { path: await this.directoryPicker.pick(signal ?? new AbortController().signal) }\n }),\n }\n\n readonly events: ApiProxyLike['events'] = {\n mux: (_request, signal) => this.mux(signal),\n host: (_request, signal) => this.hostEvents(signal),\n }\n\n async respond(message: { type: 'client-response'; rpcId: string; result: RpcResult<unknown> }): Promise<{ accepted: boolean; reason?: string }> {\n const pending = this.interactions.get(message.rpcId)\n if (pending === undefined) return { accepted: false, reason: 'not-pending' }\n if (!message.result.ok) return { accepted: false, reason: 'bad-response' }\n this.interactions.delete(message.rpcId)\n pending.resolve(pending.map(message.result.value))\n return { accepted: true }\n }\n\n private async *mux(signal: AbortSignal): AsyncIterable<MuxFrameLike> {\n const queue = new AsyncFrameQueue(signal)\n const offEvent = this.ctx.on('session/event' as never, ((session: { id: string }, event: unknown) => {\n queue.push({ type: 'session/event', sessionId: String(session.id), event: event as MuxFrameLike['event'] })\n }) as never, { global: true })\n const projections = this.ctx.get('sessionProjections') as {\n onChanged?(listener: (session: { id: string }, key: string, value: unknown) => void): () => void\n } | undefined\n const offProjection = projections?.onChanged?.((session, key, value) => {\n queue.push({ type: 'session/projection', sessionId: String(session.id), key, value })\n })\n\n let disposeInteractions: (() => Promise<void>) | undefined\n try {\n disposeInteractions = await startDsh012RemoteInteractions(this.ctx, {\n approval: (sessionId, request, next) => this.answerApproval(queue, sessionId, request, next),\n question: (sessionId, request, next) => this.answerQuestion(queue, sessionId, request, next),\n })\n } catch (error) {\n console.warn(`[deeppilot] DSH Remote interaction client unavailable: ${toError(error).message}`)\n }\n\n try {\n yield* queue.iterate()\n } finally {\n offEvent()\n offProjection?.()\n await disposeInteractions?.()\n queue.close()\n }\n }\n\n private answerApproval(\n queue: AsyncFrameQueue,\n sessionId: string,\n request: RemoteApprovalRequest,\n next: () => Promise<unknown>,\n ): Promise<unknown> {\n if (!this.canSurfaceInteraction('approval')) return next()\n const rpcId = randomUUID()\n const response = deferred<unknown>()\n const abort = (): void => response.resolve('cancelled')\n request.signal?.addEventListener('abort', abort, { once: true })\n this.interactions.set(rpcId, {\n resolve: response.resolve,\n map: value => {\n const outcome = (value as { outcome?: unknown } | undefined)?.outcome\n return outcome === 'allowed-once' || outcome === 'rejected' ? outcome : 'unavailable'\n },\n })\n queue.push({\n type: 'approval/requested', rpcId, sessionId, approvalId: rpcId,\n toolName: String(request.toolName ?? 'tool'), reason: String(request.reason ?? ''),\n })\n return response.promise.finally(() => {\n request.signal?.removeEventListener('abort', abort)\n this.interactions.delete(rpcId)\n queue.push({ type: 'approval/resolved', approvalId: rpcId })\n })\n }\n\n private answerQuestion(\n queue: AsyncFrameQueue,\n sessionId: string,\n request: RemoteQuestionRequest,\n next: () => Promise<unknown>,\n ): Promise<unknown> {\n if (!this.canSurfaceInteraction('question')) return next()\n const rpcId = randomUUID()\n const response = deferred<unknown>()\n const abort = (): void => response.reject(new Error('question cancelled'))\n request.signal?.addEventListener('abort', abort, { once: true })\n this.interactions.set(rpcId, {\n resolve: response.resolve,\n map: value => (value as { answer?: unknown } | undefined)?.answer ?? value,\n })\n queue.push({ type: 'question/requested', rpcId, sessionId, questions: request.questions ?? [] })\n return response.promise.finally(() => {\n request.signal?.removeEventListener('abort', abort)\n this.interactions.delete(rpcId)\n queue.push({ type: 'question/resolved', questionRpcId: rpcId })\n })\n }\n\n private async *hostEvents(signal: AbortSignal): AsyncIterable<MuxFrameLike> {\n const queue = new AsyncFrameQueue(signal)\n const listen = (event: string, type: string, project?: (...args: unknown[]) => Record<string, unknown>) =>\n this.ctx.on(event as never, ((...args: unknown[]) => queue.push({ type, ...(project?.(...args) ?? {}) })) as never, { global: true })\n const off = [\n listen('api-session/added', 'host/session-added'),\n listen('api-session/removed', 'host/session-removed'),\n listen('api-session/status', 'host/session-status', (sessionId, running) => ({ sessionId: String(sessionId), running: running === true })),\n listen('api-session/activity', 'host/session-added'),\n ]\n const workspaceAbort = new AbortController()\n const stop = (): void => workspaceAbort.abort()\n signal.addEventListener('abort', stop, { once: true })\n const workspaceTask = this.workspaceController === undefined ? undefined : (async () => {\n try {\n for await (const frame of this.workspaceController!.follow(workspaceAbort.signal)) {\n if (frame.type === 'archived') queue.push({ type: 'host/archived-sessions-changed', archivedSessionIds: (frame as { archivedSessionIds?: unknown }).archivedSessionIds } as MuxFrameLike)\n else if (frame.type !== 'baseline') queue.push({ type: 'host/workspace-changed' })\n }\n } catch { /* Host shutdown / withdrawn controller ends the stream. */ }\n })()\n try {\n yield* queue.iterate()\n } finally {\n for (const dispose of off) dispose()\n signal.removeEventListener('abort', stop)\n workspaceAbort.abort()\n void workspaceTask\n queue.close()\n }\n }\n\n private async call<T>(invoke: () => T | Promise<T>): Promise<{ result: RpcResult<T> }> {\n try { return { result: { ok: true, value: await invoke() } } }\n catch (error) { return { result: { ok: false, error: toError(error) } } }\n }\n}\n\nfunction deferred<T>(): { promise: Promise<T>; resolve(value: T): void; reject(reason: unknown): void } {\n let resolve!: (value: T) => void\n let reject!: (reason: unknown) => void\n const promise = new Promise<T>((ok, fail) => { resolve = ok; reject = fail })\n return { promise, resolve, reject }\n}\n\nclass AsyncFrameQueue {\n private readonly frames: MuxFrameLike[] = []\n private wake: (() => void) | undefined\n private closed = false\n constructor(signal: AbortSignal) {\n signal.addEventListener('abort', () => this.close(), { once: true })\n }\n push(frame: MuxFrameLike): void { if (!this.closed) { this.frames.push(frame); this.wake?.() } }\n close(): void { if (!this.closed) { this.closed = true; this.wake?.() } }\n async *iterate(): AsyncIterable<MuxFrameLike> {\n while (!this.closed) {\n const frame = this.frames.shift()\n if (frame !== undefined) { yield frame; continue }\n await new Promise<void>(resolve => { this.wake = resolve })\n this.wake = undefined\n }\n }\n}\n\nfunction unavailable(message: string): Error & { code: string } {\n return Object.assign(new Error(message), { code: 'directory-picker-unavailable' })\n}\nfunction toError(error: unknown): { code: string; message: string } {\n const value = error as { code?: unknown; message?: unknown }\n return { code: typeof value?.code === 'string' ? value.code : 'internal', message: typeof value?.message === 'string' ? value.message : String(error) }\n}\nfunction toPhoneSessionRow(value: unknown): PhoneSessionRow {\n const row = value as Record<string, unknown>\n return {\n sessionId: String(row.sessionId ?? ''), updatedAt: Number(row.updatedAt ?? Date.now()), running: row.running === true,\n ...(row.blank === true ? { blank: true } : {}), ...(typeof row.cwd === 'string' ? { cwd: row.cwd } : {}),\n ...(typeof row.origin === 'string' ? { origin: row.origin } : {}), ...(typeof row.parentSessionId === 'string' ? { parentSessionId: row.parentSessionId } : {}),\n ...(row.projections && typeof row.projections === 'object' ? { projections: row.projections as PhoneSessionRow['projections'] } : {}),\n }\n}\nfunction toWorkspaceView(value: unknown): WorkspaceViewLike {\n const row = value as Record<string, unknown>\n return { workspaceId: String(row.workspaceId ?? ''), title: String(row.title ?? ''), path: String(row.path ?? ''), sessionIds: Array.isArray(row.sessionIds) ? row.sessionIds.map(String) : [] }\n}\nasync function readWorkspaceBaseline(controller: WorkspaceControllerLike): Promise<{ items: WorkspaceViewLike[]; archivedSessionIds: string[] }> {\n const abort = new AbortController()\n const iterator = controller.follow(abort.signal)[Symbol.asyncIterator]()\n try {\n const first = await iterator.next()\n const baseline = first.value as { type?: string; value?: { items?: unknown[]; archivedSessionIds?: unknown[] } } | undefined\n if (baseline?.type !== 'baseline') throw new Error('workspace follow did not provide a baseline')\n return { items: (baseline.value?.items ?? []).map(toWorkspaceView), archivedSessionIds: (baseline.value?.archivedSessionIds ?? []).map(String) }\n } finally { abort.abort(); await iterator.return?.() }\n}\nasync function projectModels(catalog: unknown, sessionId: string, list: { items: readonly unknown[] }): Promise<HostSessionModels> {\n const value = catalog as { default?: { provider?: string; model?: string; reasoningEffort?: string }; groups?: unknown[]; failures?: unknown[] }\n const row = list.items.map(toPhoneSessionRow).find(item => item.sessionId === sessionId)\n const selected = (row?.projections?.values?.modelSelection as { next?: unknown } | undefined)?.next as { provider?: string; model?: string; reasoningEffort?: string } | undefined\n return {\n current: { provider: String(selected?.provider ?? value.default?.provider ?? ''), model: String(selected?.model ?? value.default?.model ?? ''), ...(typeof selected?.reasoningEffort === 'string' ? { reasoningEffort: selected.reasoningEffort } : {}) },\n routable: true,\n groups: Array.isArray(value.groups) ? value.groups as HostSessionModels['groups'] : [],\n failures: Array.isArray(value.failures) ? value.failures as HostSessionModels['failures'] : [],\n }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'\nimport type { DeviceScope } from './device-auth.ts'\nimport type { DeepPilotReport, PairingGrantSnapshot, PushTestResult, RelayTestResult } from './report-wire.ts'\n\n/** Async snapshot source wired by the plugin entry. */\nexport type ReportSnapshot = () => Promise<DeepPilotReport>\n\nexport type PairingStarter = () => Promise<PairingGrantSnapshot>\nexport type DeviceRevoker = (deviceId: string) => Promise<boolean>\nexport type DeviceScopeUpdater = (deviceId: string, scopes: DeviceScope[]) => Promise<DeviceScope[]>\n\n/** Runs the relay connectivity self-test (health + enrollment round-trip). */\nexport type RelayTester = () => Promise<RelayTestResult>\n\n/** Forces one synthetic notification down the active push pathway. */\nexport type PushTester = () => Promise<PushTestResult>\n\n/**\n * The Typert receiver the Gateway resolves for the DeepPilot Bridge report.\n * Snapshot data stays non-secret; the token crosses the boundary only through\n * the explicit, user-triggered revealToken/rotateToken invocations.\n */\nexport class DeepPilotReportService extends TypertRemoteService {\n private readonly snapshot: ReportSnapshot\n private readonly pairingStarter: PairingStarter\n private readonly deviceRevoker: DeviceRevoker\n private readonly deviceScopeUpdater: DeviceScopeUpdater\n\n private readonly relayTester: RelayTester\n private readonly pushTester: PushTester\n\n constructor(\n ctx: Context,\n snapshot: ReportSnapshot,\n pairingStarter: PairingStarter,\n deviceRevoker: DeviceRevoker,\n deviceScopeUpdater: DeviceScopeUpdater,\n relayTester: RelayTester,\n pushTester: PushTester,\n ) {\n super(ctx, 'deeppilotReport', { namespace: 'deeppilot' })\n this.snapshot = snapshot\n this.pairingStarter = pairingStarter\n this.deviceRevoker = deviceRevoker\n this.deviceScopeUpdater = deviceScopeUpdater\n this.relayTester = relayTester\n this.pushTester = pushTester\n }\n\n async report(): Promise<DeepPilotReport> {\n return this.snapshot()\n }\n\n async beginPairing(): Promise<PairingGrantSnapshot> {\n return this.pairingStarter()\n }\n\n async revokeDevice(deviceId: string): Promise<boolean> {\n return this.deviceRevoker(deviceId)\n }\n\n async setDeviceScopes(deviceId: string, scopes: DeviceScope[]): Promise<DeviceScope[]> {\n return this.deviceScopeUpdater(deviceId, scopes)\n }\n\n async testRelay(): Promise<RelayTestResult> {\n return this.relayTester()\n }\n\n async testPush(): Promise<PushTestResult> {\n return this.pushTester()\n }\n}\n","/**\n * Wire contract for the DeepPilot report Remote (`deeppilot/report`).\n *\n * The web settings page needs the bridge's live facts (paired devices,\n * connections, token state) — those live Host-side. This module is the single\n * source both halves share: the strict result codec (hand-rolled, so the\n * client bundle needs no schema library) and the exact descriptor object.\n *\n * @module dsh-deeppilot/report-wire\n */\n\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport { DEVICE_SCOPES, normalizeDeviceScopes, type DeviceScope } from './device-auth.ts'\n\nexport interface PairingGrantSnapshot {\n code: string\n expiresAt: number\n audience: string\n}\n\n/** One paired device row in the report. */\nexport interface ReportDevice {\n deviceId: string\n deviceName: string\n appVersion: string\n firstSeenTs: number\n lastSeenTs: number\n fingerprint: string\n scopes: DeviceScope[]\n revokedAt?: number\n /** Present once the device registered an APNs token (token itself never leaves the host). */\n apns?: { environment: 'development' | 'production'; updatedAt: number }\n}\n\n/** One step of the relay connectivity self-test. */\nexport interface RelayTestStep {\n id: 'health' | 'enroll'\n ok: boolean\n message: string\n latencyMs?: number\n}\n\n/** Result of deeppilot/testRelay. */\nexport interface RelayTestResult {\n url: string\n overall: 'ok' | 'failed'\n tokenIssued: boolean\n steps: RelayTestStep[]\n}\n\n/** Per-device delivery result of deeppilot/testPush. */\nexport interface PushTestDeviceResult {\n name: string\n environment: string\n /** sent | invalid-token | failed — mirrors the dispatch outcome contract. */\n outcome: string\n /** Apple's raw rejection reason when present (BadDeviceToken, …). */\n reason?: string\n /** First 10 hex chars of the stored token, for freshness verification. */\n tokenFingerprint?: string\n}\n\nexport interface PushTestResult {\n transport: 'apns' | 'relay' | 'none'\n /** sent = at least one accepted delivery; no-targets / not-configured / failed. */\n overall: 'sent' | 'failed' | 'no-targets' | 'not-configured'\n message?: string\n results: PushTestDeviceResult[]\n}\n\n/** Everything the settings page renders for the bridge. */\nexport interface DeepPilotReport {\n protocolVersion: number\n serverVersion: string\n /** Host plugin version (from package.json). Same value as serverVersion,\n * surfaced under a stable name so the wire contract does not change if\n * the legacy field is ever repurposed. */\n pluginVersion: string\n /** True once the host's background GitHub check has confirmed a newer\n * stable release exists. Undefined / false ⇒ the UI shows only the\n * version line, never the \"new version\" hint. */\n updateAvailable?: boolean\n /** GitHub release page URL, when an update is available. */\n releaseUrl?: string\n /** Whether the master bridge switch is on. */\n enabled: boolean\n /** Absolute protocol-v2 identity registry path. */\n identityPath: string\n /** Whether host identity and the device registry are ready. */\n pairingReady: boolean\n /** Currently connected phone sockets. */\n activeConnections: number\n historyBufferMax: number\n debug: boolean\n /** Private IPv4 candidates for local QR pairing. */\n lanAddresses: string[]\n /** Independent LAN listener; this never represents DSH's own web port. */\n local: {\n phase: 'disabled' | 'starting' | 'online' | 'error' | 'stopped'\n port: number\n endpoints: string[]\n message?: string\n updatedAt: number\n }\n remote: {\n provider: 'tailscale-funnel'\n phase: 'disabled' | 'starting' | 'login_required' | 'online' | 'error' | 'unavailable' | 'stopped'\n publicURL?: string\n authURL?: string\n message?: string\n updatedAt: number\n }\n devices: ReportDevice[]\n}\n\n/** The npm package identity both contribution registrations claim. */\nexport const REPORT_REMOTE_PACKAGE = 'dsh-deeppilot'\n\n/** Canonical `<namespace>/<method>` endpoint of the report Remote. */\nexport const REPORT_ENDPOINT = 'deeppilot/report'\n\nexport const BEGIN_PAIRING_ENDPOINT = 'deeppilot/beginPairing'\nexport const REVOKE_DEVICE_ENDPOINT = 'deeppilot/revokeDevice'\nexport const SET_DEVICE_SCOPES_ENDPOINT = 'deeppilot/setDeviceScopes'\n\nfunction reject(field: string): never {\n throw new TypeError(`deeppilot/report result: invalid ${field}`)\n}\n\nfunction str(source: Record<string, unknown>, key: string, field: string): string {\n const value = source[key]\n if (typeof value !== 'string') reject(field)\n return value\n}\n\n/**\n * Non-negative integer: counters and timestamps (activeConnections,\n * historyBufferMax, updatedAt, lastSeenTs, protocolVersion, etc.). A bare\n * `typeof number` check accepts 1.5, -1, and 1e20 — all of which then\n * surface verbatim on the settings page and break any sort or arithmetic\n * the UI does.\n */\nfunction int(source: Record<string, unknown>, key: string, field: string): number {\n const value = source[key]\n if (\n typeof value !== 'number' ||\n !Number.isFinite(value) ||\n !Number.isInteger(value) ||\n value < 0\n ) reject(field)\n return value\n}\nfunction bool(source: Record<string, unknown>, key: string, field: string): boolean {\n const value = source[key]\n if (typeof value !== 'boolean') reject(field)\n return value\n}\nfunction rec(value: unknown, field: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) reject(field)\n return value as Record<string, unknown>\n}\n\nfunction parseDevice(value: unknown): ReportDevice {\n const s = rec(value, 'device')\n let apns: ReportDevice['apns']\n if (s.apns !== undefined) {\n const a = rec(s.apns, 'device.apns')\n const environment = str(a, 'environment', 'device.apns.environment')\n if (environment !== 'development' && environment !== 'production') reject('device.apns.environment')\n apns = { environment, updatedAt: int(a, 'updatedAt', 'device.apns.updatedAt') }\n }\n return {\n deviceId: str(s, 'deviceId', 'device.deviceId'),\n deviceName: str(s, 'deviceName', 'device.deviceName'),\n appVersion: str(s, 'appVersion', 'device.appVersion'),\n firstSeenTs: int(s, 'firstSeenTs', 'device.firstSeenTs'),\n lastSeenTs: int(s, 'lastSeenTs', 'device.lastSeenTs'),\n fingerprint: str(s, 'fingerprint', 'device.fingerprint'),\n scopes: normalizeDeviceScopes(s.scopes),\n ...(s.revokedAt !== undefined ? { revokedAt: int(s, 'revokedAt', 'device.revokedAt') } : {}),\n ...(apns ? { apns } : {}),\n }\n}\n\nfunction parseRemote(value: unknown): DeepPilotReport['remote'] {\n const s = rec(value, 'remote')\n const provider = str(s, 'provider', 'remote.provider')\n const phase = str(s, 'phase', 'remote.phase')\n if (provider !== 'tailscale-funnel') reject('remote.provider')\n const phases = ['disabled', 'starting', 'login_required', 'online', 'error', 'unavailable', 'stopped']\n if (!phases.includes(phase)) reject('remote.phase')\n const publicURL = s.publicURL\n const authURL = s.authURL\n const message = s.message\n if (publicURL !== undefined && typeof publicURL !== 'string') reject('remote.publicURL')\n if (authURL !== undefined && typeof authURL !== 'string') reject('remote.authURL')\n if (message !== undefined && typeof message !== 'string') reject('remote.message')\n return {\n provider,\n phase: phase as DeepPilotReport['remote']['phase'],\n ...(typeof publicURL === 'string' ? { publicURL } : {}),\n ...(typeof authURL === 'string' ? { authURL } : {}),\n ...(typeof message === 'string' ? { message } : {}),\n updatedAt: int(s, 'updatedAt', 'remote.updatedAt'),\n }\n}\n\nfunction parseLocal(value: unknown): DeepPilotReport['local'] {\n const s = rec(value, 'local')\n const phase = str(s, 'phase', 'local.phase')\n const phases = ['disabled', 'starting', 'online', 'error', 'stopped']\n if (!phases.includes(phase)) reject('local.phase')\n const endpoints = s.endpoints\n if (!Array.isArray(endpoints) || endpoints.some((entry) => typeof entry !== 'string')) reject('local.endpoints')\n const message = s.message\n if (message !== undefined && typeof message !== 'string') reject('local.message')\n return {\n phase: phase as DeepPilotReport['local']['phase'],\n port: int(s, 'port', 'local.port'),\n endpoints: endpoints as string[],\n ...(typeof message === 'string' ? { message } : {}),\n updatedAt: int(s, 'updatedAt', 'local.updatedAt'),\n }\n}\n\nfunction parseRelayTestStep(value: unknown): RelayTestStep {\n const st = rec(value, 'step')\n const id = str(st, 'id', 'step.id')\n if (id !== 'health' && id !== 'enroll') reject('step.id')\n const latencyMs = st.latencyMs\n if (latencyMs !== undefined) {\n // Same int() check the report uses for counters: latency is always a\n // non-negative whole-millisecond number; a NaN/Infinity/negative arrives\n // from a buggy host and must not silently render as `(NaNms)`.\n if (\n typeof latencyMs !== 'number' ||\n !Number.isFinite(latencyMs) ||\n !Number.isInteger(latencyMs) ||\n latencyMs < 0\n ) reject('step.latencyMs')\n }\n return {\n id,\n ok: bool(st, 'ok', 'step.ok'),\n message: str(st, 'message', 'step.message'),\n ...(typeof latencyMs === 'number' ? { latencyMs } : {}),\n }\n}\n\nfunction parseRelayTestResult(value: unknown): RelayTestResult {\n const s = rec(value, 'result')\n const overall = str(s, 'overall', 'overall')\n if (overall !== 'ok' && overall !== 'failed') reject('overall')\n const stepsRaw = s.steps\n if (!Array.isArray(stepsRaw)) reject('steps')\n return {\n url: str(s, 'url', 'url'),\n overall,\n tokenIssued: bool(s, 'tokenIssued', 'tokenIssued'),\n steps: (stepsRaw as unknown[]).map(parseRelayTestStep),\n }\n}\n\nfunction parsePushTestResult(value: unknown): PushTestResult {\n const s = rec(value, 'result')\n const transport = str(s, 'transport', 'transport')\n if (transport !== 'apns' && transport !== 'relay' && transport !== 'none') reject('transport')\n const overall = str(s, 'overall', 'overall')\n const overalls = ['sent', 'failed', 'no-targets', 'not-configured']\n if (!overalls.includes(overall)) reject('overall')\n const resultsRaw = s.results\n if (!Array.isArray(resultsRaw)) reject('results')\n const results = (resultsRaw as unknown[]).map((value) => {\n const r = rec(value, 'device result')\n const reason = r.reason\n const tokenFingerprint = r.tokenFingerprint\n return {\n name: str(r, 'name', 'result.name'),\n environment: str(r, 'environment', 'result.environment'),\n outcome: str(r, 'outcome', 'result.outcome'),\n ...(typeof reason === 'string' && reason.length > 0 ? { reason } : {}),\n ...(typeof tokenFingerprint === 'string' && /^[0-9a-f]{10}$/.test(tokenFingerprint)\n ? { tokenFingerprint }\n : {}),\n }\n })\n const message = s.message\n return {\n transport,\n overall: overall as PushTestResult['overall'],\n ...(typeof message === 'string' && message.length > 0 ? { message } : {}),\n results,\n }\n}\n\nfunction parseReport(value: unknown): DeepPilotReport {\n const s = rec(value, 'report')\n const devices = s.devices\n const lanAddresses = s.lanAddresses\n if (!Array.isArray(devices)) reject('devices')\n if (!Array.isArray(lanAddresses) || lanAddresses.some((value) => typeof value !== 'string')) reject('lanAddresses')\n // Update fields are optional: an older Host (without the background\n // GitHub check) won't include them, and the UI must keep rendering.\n const releaseUrl = s.releaseUrl\n return {\n protocolVersion: int(s, 'protocolVersion', 'protocolVersion'),\n serverVersion: str(s, 'serverVersion', 'serverVersion'),\n pluginVersion: str(s, 'pluginVersion', 'pluginVersion'),\n ...(s.updateAvailable === true ? { updateAvailable: true } : {}),\n ...(typeof releaseUrl === 'string' && releaseUrl.length > 0\n ? { releaseUrl } : {}),\n enabled: bool(s, 'enabled', 'enabled'),\n identityPath: str(s, 'identityPath', 'identityPath'),\n pairingReady: bool(s, 'pairingReady', 'pairingReady'),\n activeConnections: int(s, 'activeConnections', 'activeConnections'),\n historyBufferMax: int(s, 'historyBufferMax', 'historyBufferMax'),\n debug: bool(s, 'debug', 'debug'),\n lanAddresses: lanAddresses as string[],\n local: parseLocal(s.local),\n remote: parseRemote(s.remote),\n devices: (devices as unknown[]).map(parseDevice),\n }\n}\n\nexport const reportSchema: TypertSchema<DeepPilotReport> = { parse: parseReport }\n\nexport const relayTestSchema: TypertSchema<RelayTestResult> = { parse: parseRelayTestResult }\n\nexport const pushTestSchema: TypertSchema<PushTestResult> = { parse: parsePushTestResult }\n\nexport const pairingGrantSchema: TypertSchema<PairingGrantSnapshot> = {\n parse(value: unknown): PairingGrantSnapshot {\n const s = rec(value, 'pairing grant')\n const code = str(s, 'code', 'pairingGrant.code')\n if (code.length < 32) reject('pairingGrant.code')\n return {\n code,\n expiresAt: int(s, 'expiresAt', 'pairingGrant.expiresAt'),\n audience: str(s, 'audience', 'pairingGrant.audience'),\n }\n },\n}\n\nconst deviceIdSchema: TypertSchema<string> = {\n parse(value: unknown): string {\n if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{43}$/.test(value)) reject('deviceId')\n return value\n },\n}\n\nconst scopesSchema: TypertSchema<DeviceScope[]> = {\n parse(value: unknown): DeviceScope[] {\n if (!Array.isArray(value) || value.some((scope) => typeof scope !== 'string' || !DEVICE_SCOPES.includes(scope as DeviceScope))) {\n reject('scopes')\n }\n return normalizeDeviceScopes(value)\n },\n}\n\nconst booleanSchema: TypertSchema<boolean> = {\n parse(value: unknown): boolean {\n if (typeof value !== 'boolean') reject('boolean')\n return value\n },\n}\n\n/**\n * Connectivity self-test for the push relay: health probe plus (when an\n * enroll key is on file) a real enrollment round-trip. Doubles as repair —\n * a token it issues is cached by the bridge.\n */\nexport const TEST_RELAY_ENDPOINT = 'deeppilot/testRelay'\n\n/**\n * Real-delivery push test: forces one synthetic notification down the active\n * push pathway to every registered device, ignoring connected/muted filters —\n * an explicit user action must always be able to prove the pipeline works.\n */\nexport const TEST_PUSH_ENDPOINT = 'deeppilot/testPush'\n\nexport const REPORT_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${REPORT_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'report',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeepPilotReport`,\n schema: reportSchema,\n },\n}\n\nexport const BEGIN_PAIRING_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${BEGIN_PAIRING_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'beginPairing',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#PairingGrantSnapshot`,\n schema: pairingGrantSchema,\n },\n}\n\nexport const REVOKE_DEVICE_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${REVOKE_DEVICE_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'revokeDevice',\n invocation: { kind: 'direct' },\n parameters: [{\n name: 'deviceId',\n wire: 'deviceId',\n source: 'json',\n codec: { mode: 'strict', typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceId`, schema: deviceIdSchema },\n }],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#Boolean`,\n schema: booleanSchema,\n },\n}\n\nexport const SET_DEVICE_SCOPES_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${SET_DEVICE_SCOPES_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'setDeviceScopes',\n invocation: { kind: 'direct' },\n parameters: [\n {\n name: 'deviceId', wire: 'deviceId', source: 'json',\n codec: { mode: 'strict', typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceId`, schema: deviceIdSchema },\n },\n {\n name: 'scopes', wire: 'scopes', source: 'json',\n codec: { mode: 'strict', typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceScopes`, schema: scopesSchema },\n },\n ],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceScopes`,\n schema: scopesSchema,\n },\n}\n\nexport const TEST_RELAY_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${TEST_RELAY_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'testRelay',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#RelayTestResult`,\n schema: relayTestSchema,\n },\n}\n\nexport const TEST_PUSH_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${TEST_PUSH_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'testPush',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#PushTestResult`,\n schema: pushTestSchema,\n },\n}\n\nconst INVOCATION_DESCRIPTORS = [\n REPORT_DESCRIPTOR,\n BEGIN_PAIRING_DESCRIPTOR,\n REVOKE_DEVICE_DESCRIPTOR,\n SET_DEVICE_SCOPES_DESCRIPTOR,\n TEST_RELAY_DESCRIPTOR,\n TEST_PUSH_DESCRIPTOR,\n]\n\nexport const REPORT_HOST_CONTRIBUTION = {\n package: REPORT_REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n // Typert contributions in dsh 0.1.2 include reflection metadata even when\n // a hand-written Remote has no generated reflection exports.\n model: { services: [], events: [], objects: [] },\n invocations: INVOCATION_DESCRIPTORS,\n}\n\nexport const REPORT_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: REPORT_REMOTE_PACKAGE,\n descriptors: INVOCATION_DESCRIPTORS,\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { DeepPilotReportService } from './report-service.ts'\nimport type { DeviceRevoker, DeviceScopeUpdater, PairingStarter, PushTester, RelayTester, ReportSnapshot } from './report-service.ts'\nimport { REPORT_HOST_CONTRIBUTION } from './report-wire.ts'\n\ninterface TypertContributionRegistry {\n register(contribution: typeof REPORT_HOST_CONTRIBUTION): () => void | Promise<void>\n}\n\n/**\n * Provide the report service and register its Remote descriptor. Rides an\n * optional `typert` inject: profiles without the web stack never activate it.\n */\nexport function applyReportRemote(\n ctx: Context,\n snapshot: ReportSnapshot,\n pairingStarter: PairingStarter,\n deviceRevoker: DeviceRevoker,\n deviceScopeUpdater: DeviceScopeUpdater,\n relayTester: RelayTester,\n pushTester: PushTester,\n): void {\n ctx.inject(['typert'], (remoteCtx) => {\n new DeepPilotReportService(remoteCtx, snapshot, pairingStarter, deviceRevoker, deviceScopeUpdater, relayTester, pushTester)\n const registry = remoteCtx.typert as unknown as TypertContributionRegistry\n const unregister = registry.register(REPORT_HOST_CONTRIBUTION)\n remoteCtx.effect(() => () => void unregister(), 'dsh-deeppilot: report remote')\n })\n}\n","/**\n * Normalize an operator-configured relay URL without a backtracking regular\n * expression. Scanning from the end keeps even pathological inputs linear.\n */\nexport function normalizeRelayBaseUrl(value: string): string {\n const trimmed = value.trim()\n let end = trimmed.length\n while (end > 0 && trimmed.charCodeAt(end - 1) === 0x2f) end -= 1\n return end === trimmed.length ? trimmed : trimmed.slice(0, end)\n}\n","/**\n * Relay connectivity self-test used by the settings page \"测试中继\" button.\n *\n * Two steps mirror what zero-touch enrollment actually does:\n * 1. health — GET {url}/healthz → is the relay reachable?\n * 2. enroll — POST {url}/v1/enroll → does the shared key grant a token?\n *\n * The enroll step doubles as a repair path: a token it issues is handed back\n * via `onEnrolled` so the bridge caches it and flips push readiness without\n * waiting for the next app registration.\n *\n * Transport is injectable (`fetchImpl`) so tests never touch the network.\n */\n\nimport { normalizeRelayBaseUrl } from './relay-url.ts'\n\nexport interface RelayTestStep {\n id: 'health' | 'enroll'\n ok: boolean\n /** Human-readable, user-facing (zh) outcome; safe to render verbatim. */\n message: string\n latencyMs?: number\n}\n\nexport interface RelayTestResult {\n url: string\n overall: 'ok' | 'failed'\n /** True when the probe produced/cached a usable relay token. */\n tokenIssued: boolean\n steps: RelayTestStep[]\n}\n\nexport interface RelayProbeOptions {\n url: string\n /** Stable per-bridge identity for enrollment; generated upstream if absent. */\n clientId?: string\n /** Distributor's shared key; absent → enroll step reports why it cannot run. */\n enrollKey?: string\n /** True when the user configured relayToken manually (enroll unnecessary). */\n manualToken?: boolean\n timeoutMs?: number\n fetchImpl?: typeof fetch\n /** Called with an issued token so the caller can persist it. */\n onEnrolled?: (token: string) => void\n}\n\nconst DEFAULT_TIMEOUT_MS = 6_000\n\nasync function requestJson(\n fetchImpl: typeof fetch,\n url: string,\n init: RequestInit,\n timeoutMs: number,\n): Promise<{ status: number; body: unknown }> {\n const response = await fetchImpl(url, {\n ...init,\n signal: AbortSignal.timeout(timeoutMs),\n })\n let body: unknown = null\n try {\n body = await response.json()\n } catch {\n // non-JSON body keeps body null; status still drives the verdict\n }\n return { status: response.status, body }\n}\n\nexport async function runRelayProbe(options: RelayProbeOptions): Promise<RelayTestResult> {\n const base = normalizeRelayBaseUrl(options.url)\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const fetchImpl = options.fetchImpl ?? fetch\n const steps: RelayTestStep[] = []\n let tokenIssued = false\n\n // ---- step 1: reachability ----\n try {\n const startedAt = Date.now()\n const { status, body } = await requestJson(\n fetchImpl,\n `${base}/healthz`,\n { method: 'GET' },\n timeoutMs,\n )\n const latencyMs = Date.now() - startedAt\n if (status === 200 && (body as { ok?: unknown })?.ok === true) {\n steps.push({ id: 'health', ok: true, message: '中继服务可达', latencyMs })\n } else {\n steps.push({ id: 'health', ok: false, message: `中继响应异常(HTTP ${status})`, latencyMs })\n }\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n steps.push({ id: 'health', ok: false, message: '无法连接中继:' + reason })\n }\n\n // ---- step 2: enrollment ----\n if ((options.manualToken ?? false)) {\n steps.push({ id: 'enroll', ok: true, message: '已手动配置 relayToken,跳过注册验证' })\n } else if (!options.enrollKey) {\n steps.push({ id: 'enroll', ok: false, message: '尚无注册密钥:等待分发版 App 首次注册后才能验证注册' })\n } else {\n const clientId = options.clientId ?? 'u_' + Math.random().toString(36).slice(2)\n try {\n const startedAt = Date.now()\n const { status, body } = await requestJson(\n fetchImpl,\n `${base}/v1/enroll`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ clientId, enrollKey: options.enrollKey }),\n },\n timeoutMs,\n )\n const latencyMs = Date.now() - startedAt\n const token = (body as { token?: unknown })?.token\n if (status === 200 && typeof token === 'string' && token.startsWith('rl_')) {\n tokenIssued = true\n options.onEnrolled?.(token)\n steps.push({ id: 'enroll', ok: true, message: '注册成功,已取得推送凭证', latencyMs })\n } else if (status === 403) {\n steps.push({ id: 'enroll', ok: false, message: '注册被拒:注册密钥不匹配(检查 App 内 DSPushEnrollKey 与服务器 RELAY_ENROLL_KEY)', latencyMs })\n } else if (status === 429) {\n steps.push({ id: 'enroll', ok: false, message: '尝试过于频繁,稍后再试', latencyMs })\n } else {\n steps.push({ id: 'enroll', ok: false, message: `注册失败(HTTP ${status})`, latencyMs })\n }\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n steps.push({ id: 'enroll', ok: false, message: '注册请求失败:' + reason })\n }\n }\n\n const overall: RelayTestResult['overall'] =\n steps.length > 0 && steps.some((step) => step.id === 'health' && step.ok) &&\n steps.every((step) => step.ok)\n ? 'ok'\n : 'failed'\n return { url: base, overall, tokenIssued, steps }\n}\n","/**\n * Minimal APNs provider client (HTTP/2) with zero npm dependencies.\n *\n * Implements exactly what the bridge needs:\n * - ES256 provider token (JWT) signed with an Apple .p8 key, refreshed under\n * the 1-hour freshness window Apple enforces;\n * - one long-lived HTTP/2 session per environment, recreated transparently\n * after GOAWAY/errors;\n * - alert pushes carrying the notify projection (category/thread/collapse),\n * with `interruption-level: time-sensitive` for approval/question events;\n * - outcome classification so callers can prune dead device tokens.\n *\n * Privacy: logs carry outcomes and masked token prefixes only — never message\n * bodies or full tokens.\n */\n\nimport { connect as http2Connect, type ClientHttp2Session } from 'node:http2'\nimport { createHash, createPrivateKey, sign as cryptoSign, type KeyObject } from 'node:crypto'\nimport { readFile } from 'node:fs/promises'\nimport type { ApnsEnvironment } from './token.ts'\nimport type { PushNotification } from './protocol.ts'\n\nexport interface ApnsClientOptions {\n teamId: string\n keyId: string\n /** Absolute path to the .p8 private key file. */\n keyPath: string\n bundleId: string\n debug?: boolean\n log: (message: string) => void\n}\n\nexport type ApnsOutcome = 'sent' | 'invalid-token' | 'failed'\n\n/** Outcome plus Apple's rejection reason (when present) for diagnosis. */\nexport interface ApnsSendResult {\n outcome: ApnsOutcome\n reason?: string\n}\n\n/** Classify Apple's reason without losing recoverable configuration errors. */\nexport function classifyApnsReason(reason: string): ApnsOutcome {\n return reason === 'Unregistered' || reason === 'ExpiredToken' ? 'invalid-token' : 'failed'\n}\n\nconst PROVIDER_TOKEN_TTL_MS = 50 * 60 * 1000 // Apple allows 1h; refresh early.\nconst REQUEST_TIMEOUT_MS = 10_000\n\n/** base64url without padding. */\nfunction b64url(input: Buffer | string): string {\n return Buffer.from(input).toString('base64url')\n}\n\n/** Sign one ES256 JWT for the given signing input with a P-256 private key. */\nexport function es256Jwt(signingInput: string, key: KeyObject): string {\n const signature = cryptoSign('sha256', Buffer.from(signingInput, 'utf8'), {\n key,\n // JOSE/ES256 wants raw r||s; node emits DER by default.\n dsaEncoding: 'ieee-p1363',\n })\n return signingInput + '.' + b64url(signature)\n}\n\n/** Strip PEM armor from a .p8 file and decode to PKCS#8 DER. */\nexport function p8ToDer(pem: string): Buffer {\n const body = pem\n .replace(/-----BEGIN PRIVATE KEY-----/, '')\n .replace(/-----END PRIVATE KEY-----/, '')\n .replace(/\\s+/g, '')\n return Buffer.from(body, 'base64')\n}\n\nexport interface LoadedKey {\n key: KeyObject\n}\n\n/** Pure payload builder so tests can assert the wire format without sockets. */\nexport function apnsPayload(notification: PushNotification): Record<string, unknown> {\n const timeSensitive = notification.category === 'approval.required' || notification.category === 'question.asked'\n return {\n aps: {\n alert: {\n title: notification.title.slice(0, 120),\n body: notification.body.slice(0, 200),\n },\n sound: 'default',\n category: notification.category,\n 'thread-id': notification.sessionId.slice(0, 64),\n ...(timeSensitive ? { 'interruption-level': 'time-sensitive' } : {}),\n },\n sessionId: notification.sessionId,\n notificationId: notification.notificationId,\n kind: notification.category,\n }\n}\n\n/** One delivery request: the notify projection plus its target device token.\n * The environment comes from the device's own registration (its build kind),\n * so one client serves both sandbox and production devices. */\nexport interface ApnsSendRequest extends PushNotification {\n deviceToken: string\n environment: ApnsEnvironment\n}\n\n/** collapse-id accepts ≤64 bytes of ASCII; keep it stable per session+event. */\nexport function collapseIdFor(notification: PushNotification): string {\n const raw = `${notification.category}:${notification.sessionId}`\n const readable = raw.replace(/[^a-zA-Z0-9.:-]/g, '')\n const digest = createHash('sha256').update(raw, 'utf8').digest('hex').slice(0, 12)\n return `${readable.slice(0, 51)}:${digest}`\n}\n\nfunction authorityFor(environment: ApnsEnvironment): string {\n return environment === 'production' ? 'api.push.apple.com' : 'api.sandbox.push.apple.com'\n}\n\nexport class ApnsClient {\n private readonly log: (message: string) => void\n private readonly debug: boolean\n private readonly opts: ApnsClientOptions\n\n private providerToken = ''\n private providerTokenIssuedAt = 0\n private key: KeyObject | undefined\n\n constructor(opts: ApnsClientOptions) {\n this.opts = opts\n this.log = opts.log\n this.debug = opts.debug === true\n }\n\n async dispose(): Promise<void> {\n const sessions = [...this.sessions.values()]\n this.sessions.clear()\n await Promise.all(\n sessions\n .filter((session) => !session.destroyed)\n .map((session) => new Promise<void>((resolve) => session.close(() => resolve()))),\n )\n }\n\n // ---------- credentials ----------\n\n private async ensureProviderToken(): Promise<string> {\n if (this.providerToken && Date.now() - this.providerTokenIssuedAt < PROVIDER_TOKEN_TTL_MS) {\n return this.providerToken\n }\n if (!this.key) {\n const pem = await readFile(this.opts.keyPath, 'utf8')\n this.key = createPrivateKey({ key: p8ToDer(pem), format: 'der', type: 'pkcs8' })\n }\n const issuedAt = Math.floor(Date.now() / 1000)\n const header = b64url(JSON.stringify({ alg: 'ES256', kid: this.opts.keyId }))\n const claims = b64url(JSON.stringify({ iss: this.opts.teamId, iat: issuedAt }))\n this.providerToken = es256Jwt(`${header}.${claims}`, this.key)\n this.providerTokenIssuedAt = Date.now()\n return this.providerToken\n }\n\n // ---------- transport ----------\n\n /** One long-lived HTTP/2 session per Apple host (sandbox + production). */\n private readonly sessions = new Map<string, ClientHttp2Session>()\n\n private ensureSession(authority: string): ClientHttp2Session {\n const existing = this.sessions.get(authority)\n if (existing && !existing.destroyed && !existing.closed) return existing\n const session = http2Connect(`https://${authority}`)\n // Keep a handler attached so background errors never become uncaught\n // exceptions; the next send() recreates the session when dead.\n session.on('error', (error) => {\n if (this.debug) this.log('apns session error (' + authority + '): ' + String(error))\n this.sessions.delete(authority)\n })\n this.sessions.set(authority, session)\n return session\n }\n\n /**\n * Deliver one alert. Never throws — every failure path resolves to an\n * outcome so fan-out loops cannot crash the host on a flaky network.\n */\n async send(request: ApnsSendRequest): Promise<ApnsSendResult> {\n const { deviceToken, environment, ...notification } = request\n let stream: ReturnType<ClientHttp2Session['request']> | undefined\n try {\n const token = await this.ensureProviderToken()\n const body = JSON.stringify(apnsPayload(notification))\n const session = this.ensureSession(authorityFor(environment))\n const done = new Promise<ApnsSendResult>((resolve) => {\n const req = session.request({\n [':method']: 'POST',\n [':path']: '/3/device/' + deviceToken,\n authorization: 'bearer ' + token,\n 'apns-topic': this.opts.bundleId,\n 'apns-push-type': 'alert',\n 'apns-priority': '10',\n // Stale approvals arriving hours later are worse than none.\n 'apns-expiration': String(Math.floor(Date.now() / 1000) + 3600),\n 'apns-collapse-id': collapseIdFor(notification),\n 'content-type': 'application/json',\n 'content-length': String(Buffer.byteLength(body)),\n })\n stream = req\n let status = 0\n let responseBody = ''\n const settle = (outcome: ApnsOutcome, reason?: string): void => {\n if (this.debug) {\n this.log(`apns ${outcome}${reason ? ' (' + reason + ')' : ''} (${this.maskToken(deviceToken)})`)\n }\n resolve(reason !== undefined && reason !== '' ? { outcome, reason } : { outcome })\n }\n const timer = setTimeout(() => {\n req.close()\n settle('failed')\n }, REQUEST_TIMEOUT_MS)\n timer.unref?.()\n req.on('response', (headers) => {\n status = Number(headers[':status'] ?? 0)\n })\n req.on('data', (chunk: Buffer) => {\n responseBody += chunk.toString('utf8')\n })\n req.on('error', () => {\n clearTimeout(timer)\n settle('failed')\n })\n req.on('end', () => {\n clearTimeout(timer)\n if (status === 200) return settle('sent')\n let reason = ''\n try {\n reason = String((JSON.parse(responseBody) as { reason?: string }).reason ?? '')\n } catch {\n // non-JSON body; fall through with empty reason\n }\n if (status !== 200 && !reason) reason = 'HTTP ' + String(status)\n // Unregistered/ExpiredToken are authoritative lifecycle verdicts.\n // BadDeviceToken can also mean the provider selected the wrong APNs\n // environment; pruning then destroys a valid registration exactly\n // when the operator needs its stored environment to diagnose config.\n const outcome = classifyApnsReason(reason)\n if (outcome === 'invalid-token') return settle(outcome, reason)\n if (this.debug) this.log(`apns rejected status=${status} reason=${reason}`)\n settle('failed', reason)\n })\n req.end(body)\n })\n return await done\n } catch (error) {\n // Credential load failures and dead sessions land here; force both to be\n // rebuilt on the next attempt.\n this.key = undefined\n this.providerToken = ''\n this.sessions.clear()\n if (this.debug) this.log('apns send failed: ' + String(error))\n return { outcome: 'failed', reason: String(error).slice(0, 120) }\n } finally {\n try { stream?.close() } catch { /* already closed */ }\n }\n }\n\n maskToken(token: string): string {\n return token.length <= 10 ? '…' : token.slice(0, 6) + '…' + token.slice(-4)\n }\n}\n","/**\n * Client for the operator-run push relay (relay/server.js). Used when the App\n * is distributed under the operator's team: bridges cannot hold the\n * distributor's .p8, so they forward notify projections over HTTPS and let\n * the relay do APNs.\n *\n * Outcome contract mirrors src/apns.ts exactly so the dispatcher prunes dead\n * tokens identically on either path:\n * sent | invalid-token (terminal Unregistered/ExpiredToken) | failed\n */\n\nimport type { ApnsEnvironment } from './token.ts'\nimport type { PushNotification } from './protocol.ts'\nimport { normalizeRelayBaseUrl } from './relay-url.ts'\n\nexport interface RelayClientOptions {\n /** Base URL of the relay, e.g. https://relay.example.com */\n url: string\n /** Per-user bearer token issued by the relay operator (or via enroll). */\n token?: string\n timeoutMs?: number\n debug?: boolean\n log: (message: string) => void\n}\n\nexport interface RelaySendRequest {\n deviceToken: string\n environment: ApnsEnvironment\n notification: PushNotification\n}\n\nexport class RelayClient {\n private readonly base: string\n private readonly token: string\n private readonly timeoutMs: number\n private readonly debug: boolean\n private readonly log: (message: string) => void\n\n constructor(opts: RelayClientOptions) {\n this.base = normalizeRelayBaseUrl(opts.url)\n this.token = (opts.token ?? '').trim()\n this.timeoutMs = opts.timeoutMs ?? 10_000\n this.debug = opts.debug === true\n this.log = opts.log\n }\n\n /**\n * Zero-touch enrollment: exchange the distributor's shared key (baked into\n * the distributed app) for a stable per-bridge bearer token. Idempotent —\n * relays derive the same token for the same clientId. Returns null on any\n * failure; callers treat that as \"not enrolled yet\", not as an error.\n */\n async enroll(clientId: string, enrollKey: string): Promise<string | null> {\n try {\n const response = await fetch(this.base + '/v1/enroll', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ clientId, enrollKey }),\n signal: AbortSignal.timeout(this.timeoutMs),\n })\n if (!response.ok) {\n if (this.debug) this.log(`enroll http ${response.status}`)\n return null\n }\n const body = (await response.json()) as { token?: unknown }\n if (typeof body.token === 'string' && body.token.startsWith('rl_')) return body.token\n if (this.debug) this.log('enroll returned no usable token')\n return null\n } catch (error) {\n if (this.debug) this.log('enroll failed: ' + String(error))\n return null\n }\n }\n\n async send(request: RelaySendRequest): Promise<{ outcome: 'sent' | 'invalid-token' | 'failed'; reason?: string }> {\n try {\n const response = await fetch(this.base + '/v1/push', {\n method: 'POST',\n headers: {\n authorization: 'Bearer ' + this.token,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n deviceToken: request.deviceToken,\n environment: request.environment,\n notification: request.notification,\n }),\n signal: AbortSignal.timeout(this.timeoutMs),\n })\n if (response.status === 401 || response.status === 429) {\n // Credential/quota problems are configuration errors, not token death;\n // surface as failed so the user fixes the config instead of silently\n // losing registrations.\n if (this.debug) this.log(`relay rejected status=${response.status}`)\n return { outcome: 'failed', reason: 'HTTP ' + String(response.status) }\n }\n if (!response.ok) {\n if (this.debug) this.log(`relay http ${response.status}`)\n return { outcome: 'failed', reason: 'HTTP ' + String(response.status) }\n }\n const body = (await response.json()) as { outcome?: string; reason?: string }\n if (body.outcome === 'sent') return { outcome: 'sent' }\n if (body.outcome === 'invalid-token') return { outcome: 'invalid-token', reason: body.reason }\n if (this.debug) this.log('relay outcome=' + String(body.outcome) + ' reason=' + String(body.reason ?? ''))\n return { outcome: 'failed', reason: body.reason }\n } catch (error) {\n if (this.debug) this.log('relay send failed: ' + String(error))\n const message = error instanceof Error ? error.message.slice(0, 120) : String(error).slice(0, 120)\n return { outcome: 'failed', reason: message }\n }\n }\n}\n","export const DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE = 8\nexport const MAX_FUNNEL_CONNECTIONS_PER_SOURCE = 16\n\nexport function normalizeFunnelConnectionLimit(value: unknown): number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= MAX_FUNNEL_CONNECTIONS_PER_SOURCE\n ? value\n : DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { access, mkdir, readdir, rm, writeFile } from 'node:fs/promises'\nimport { constants as fsConstants } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { expandHome } from './token.ts'\nimport { normalizeFunnelConnectionLimit } from './funnel-policy.ts'\n\nexport type RemotePhase =\n | 'disabled'\n | 'starting'\n | 'login_required'\n | 'online'\n | 'error'\n | 'unavailable'\n | 'stopped'\n\nexport interface RemoteStatus {\n provider: 'tailscale-funnel'\n phase: RemotePhase\n publicURL?: string\n authURL?: string\n message?: string\n updatedAt: number\n}\n\nexport interface RemoteSupervisorOptions {\n enabled: boolean\n hostname: string\n statePath: string\n helperPath?: string\n funnelPort?: 443 | 8443 | 10000\n maxConnectionsPerSource?: number\n log: (message: string) => void\n}\n\ninterface HelperEvent {\n phase?: RemotePhase\n publicURL?: string\n authURL?: string\n message?: string\n}\n\nconst RESTART_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000]\n/**\n * When the helper dies with a Go panic, the supervisor keeps only the last\n * 2KB of stderr for the status message — enough for a summary but not for the\n * full goroutine dump that would pinpoint the crash (and be needed to report\n * upstream). Each crash therefore also writes the full stderr into the state\n * directory as crash-<millis>.log (0600), and the log line points at it.\n * Only the newest dumps are retained to bound disk usage.\n */\nexport const MAX_CRASH_DUMPS = 6\n/**\n * Throttle for configuration-level failures (helper binary missing, state dir\n * unwritable). The environment will not self-heal between attempts, so the\n * previous \"1s..30s exponential\" backoff was a CPU/for-loop on a misconfigured\n * Host. 60s matches the APNs sender-failure throttle on the host plugin\n * (index.ts SENDER_FAILURE_RETRY_MS) and the relay enrollment throttle.\n */\nconst UNAVAILABLE_RETRY_MS = 60_000\n\n/**\n * Exposed for tests: the backoff schedule depends on the failure category\n * (unavailable = config, won't self-heal; crash = transient). Tying this to\n * the constants above keeps the public schedule easy to assert against.\n */\nexport function restartDelayMs(kind: 'unavailable' | 'crash', attempt: number): number {\n if (kind === 'unavailable') return UNAVAILABLE_RETRY_MS\n const index = Math.min(attempt, RESTART_DELAYS_MS.length - 1)\n // RESTART_DELAYS_MS is a non-empty literal array, so the indexed value is\n // always defined; the explicit fallback is just to satisfy the strict\n // noUncheckedIndexedAccess setting without a non-null assertion.\n return RESTART_DELAYS_MS[index] ?? RESTART_DELAYS_MS[RESTART_DELAYS_MS.length - 1]!\n}\n\nexport const DEFAULT_REMOTE_HOSTNAME = 'dsh-deeppilot'\n\n/** Preserve custom node names while migrating every pre-DeepPilot default. */\nexport function normalizeRemoteHostname(value: string | undefined): string {\n const hostname = value?.trim() ?? ''\n if (hostname === '' || ['dsh-phone', 'dsh-pocket', 'harnesspocket'].includes(hostname.toLowerCase())) {\n return DEFAULT_REMOTE_HOSTNAME\n }\n return hostname\n}\n\nexport function tunnelHelperArguments(\n originURL: string,\n statePath: string,\n options: Pick<RemoteSupervisorOptions, 'hostname' | 'funnelPort' | 'maxConnectionsPerSource'>,\n): string[] {\n return [\n '--origin', originURL,\n '--hostname', normalizeRemoteHostname(options.hostname),\n '--state-dir', statePath,\n '--port', String(options.funnelPort ?? 443),\n '--max-connections-per-source', String(normalizeFunnelConnectionLimit(options.maxConnectionsPerSource)),\n ]\n}\n\n/**\n * Summarize a fatal helper crash from its stderr tail. Go panics dump the\n * actual reason on the `panic:` line while the trailing stack frames are\n * `file.go:NN +0xOFF` noise — the old behavior of reporting only the final\n * line surfaced exactly that noise (e.g. `.../singleflight.go:194 +0x45c`)\n * and hid the real panic message. Keep the crash header line (a raw\n * `panic:`, a runtime `fatal error:`, or net/http's `http: panic serving`),\n * plus an optional `[signal ...]` continuation and the first non-runtime\n * stack frame's symbol + `file.go:NN` as a location hint. Pointer offsets\n * are not architecture stable, so they are deliberately dropped.\n *\n * The frame symbol sits on the line just above the indented source line in a\n * Go dump, e.g.:\n * tailscale.com/net/dnscache.(*Resolver).lookupIP(0x1400012c000, {...})\n * tailscale.com@v1.102.3/net/dnscache/dnscache.go:604 +0x25c\n * The first symbol (shortened) is used because a bare `file.go:NN` is not\n * unique across tailscale (singleflight.go is one example).\n */\nexport function helperCrashSummary(stderr: string): string {\n const lines = stderr.split(/\\r?\\n/)\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!.trim()\n if (line === '') continue\n // `panic:` line, a runtime `fatal error:`, or net/http's\n // `http: panic serving` (optionally prefixed by Go's log timestamp).\n const logTimestamp = /^(\\d{4}\\/\\d{2}\\/\\d{2} \\d{2}:\\d{2}:\\d{2} )/.exec(line)?.[1] ?? ''\n if (!/^(panic:|fatal error:|http: panic serving)/.test(logTimestamp.length > 0 ? line.slice(logTimestamp.length) : line)) {\n continue\n }\n let summary = logTimestamp.length > 0 ? line.slice(logTimestamp.length) : line\n const next = lines[i + 1]?.trim()\n if (next?.startsWith('[signal')) summary += ' ' + next\n // Walk the dump for the first non-runtime frame: symbol line followed by\n // an indented `path/file.go:NN` source line. Track the last symbol seen\n // before each source line.\n let lastSymbol: string | undefined\n for (let j = i + 1; j < lines.length; j++) {\n const frame = lines[j]!\n const trimmed = frame.trim()\n if (trimmed === '') continue\n // A symbol/argument line: `package.(*Type).method(args)` — not a source\n // line (which is indented and ends with `file.go:NN +0x…`). Take the\n // last symbol preceding a source line; the first source line after the\n // crash header is the crash point.\n const sourceMatch = /^\\s+(\\S+\\.go:\\d+)/.exec(frame)\n if (sourceMatch !== null) {\n const source = sourceMatch[1]!\n if (source.startsWith('runtime/') || source.startsWith('runtime\\\\')) {\n // runtime/debug.Stack() noise — skip to the next frame.\n lastSymbol = undefined\n continue\n }\n const slash = Math.max(source.lastIndexOf('/'), source.lastIndexOf('\\\\'))\n const file = slash >= 0 ? source.slice(slash + 1) : source\n const symbol = lastSymbol !== undefined ? shortenSymbol(lastSymbol) : undefined\n summary += ' @ ' + (symbol !== undefined ? `${symbol} (${file})` : file)\n break\n }\n // Otherwise this is a frame symbol (or a goroutine heading / created-by\n // note); remember the last one so the following source line can pair.\n if (trimmed.includes('(') || trimmed.endsWith(')')) {\n lastSymbol = trimmed\n }\n }\n return summary.replace(/\\s+/g, ' ').trim()\n }\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i]!.trim()\n if (line !== '') return line\n }\n return ''\n}\n\n/** Shrink a Go frame symbol to `pkg.Receiver.method` form (drop module-root\n * path, generic type arguments and the trailing call arguments), so the\n * summary hint stays readable. Keeps a `.funcN` closure suffix when present\n * (e.g. `doCall.func2`), since it identifies the exact closure.\n *\n * A symbol looks like:\n * tailscale.com/util/singleflight.(*Group[...]).doCall.func2(0x…, …)\n * The trailing call arguments form a balanced paren group that starts at\n * the function name — that group is stripped first; generics appear only\n * inside `(*Group[...])` receiver brackets before the final method dot, so\n * they are removed by trimming from the first `[` to the matching `]`.\n */\nexport function shortenSymbol(symbol: string): string {\n const trimmed = symbol.trim()\n let end = trimmed.length\n if (trimmed.endsWith(')')) {\n let depth = 0\n for (let i = trimmed.length - 1; i >= 0; i--) {\n const ch = trimmed[i]!\n if (ch === ')') depth++\n else if (ch === '(') {\n depth--\n if (depth === 0) {\n end = i\n break\n }\n }\n }\n }\n let name = trimmed.slice(0, end).trim()\n // Remove generic instantiations `[...]` inside receiver/type brackets.\n const bracketOpen = name.indexOf('[')\n if (bracketOpen >= 0) {\n const bracketClose = name.indexOf(']', bracketOpen)\n if (bracketClose > bracketOpen) {\n name = name.slice(0, bracketOpen) + name.slice(bracketClose + 1)\n }\n }\n // Keep only the last path segment (after the final /).\n const slash = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\\\'))\n return slash >= 0 ? name.slice(slash + 1) : name\n}\n\n/** A normalized fatal-crash analysis used by the exit handler to produce a\n * bounded status message and, when a full dump is available, persist it. */\nexport interface CrashAnalysis {\n summary: string\n dumpPath?: string\n}\n\n/** Shared by crash summary and dump: whether the stderr looks like a Go\n * panic/fatal-error crash (vs. an ordinary exit). */\nfunction looksLikeCrash(stderr: string): boolean {\n return /(?:^|\\n)\\s*(?:\\d{4}\\/\\d{2}\\/\\d{2} \\d{2}:\\d{2}:\\d{2} )?(?:panic:|fatal error:|http: panic serving)/.test(stderr)\n}\n\n/** Turn a crash stderr tail into a status message and optionally persist the\n * full dump under the state dir. Keeps at most MAX_CRASH_DUMPS dump files. */\nexport async function analyzeCrashExit(stderr: string, statePath: string): Promise<CrashAnalysis> {\n const summary = helperCrashSummary(stderr) || 'helper exited'\n if (!looksLikeCrash(stderr) || stderr.trim() === '') return { summary }\n const target = statePath.trim()\n if (target === '') return { summary }\n try {\n const file = join(target, `crash-${Date.now()}.log`)\n await writeFile(file, stderr, { mode: 0o600 })\n await trimCrashDumps(target)\n return { summary, dumpPath: file }\n } catch {\n return { summary }\n }\n}\n\n/** Remove oldest crash-*.log files beyond MAX_CRASH_DUMPS. */\nasync function trimCrashDumps(dir: string): Promise<void> {\n let names: string[]\n try {\n names = (await readdir(dir)).filter((name) => name.startsWith('crash-') && name.endsWith('.log'))\n } catch {\n return\n }\n if (names.length <= MAX_CRASH_DUMPS) return\n names.sort()\n const excess = names.length - MAX_CRASH_DUMPS\n await Promise.all(names.slice(0, excess).map((name) => rm(join(dir, name), { force: true }).catch(() => {})))\n}\n\n/** Parse one helper IPC line without ever evaluating or interpolating it. */\nexport function parseHelperEvent(line: string): HelperEvent | null {\n try {\n const value = JSON.parse(line) as Record<string, unknown>\n const phases: RemotePhase[] = ['starting', 'login_required', 'online', 'error', 'stopped']\n if (typeof value.phase !== 'string' || !phases.includes(value.phase as RemotePhase)) return null\n return {\n phase: value.phase as RemotePhase,\n ...(typeof value.publicURL === 'string' ? { publicURL: value.publicURL } : {}),\n ...(typeof value.authURL === 'string' ? { authURL: value.authURL } : {}),\n ...(typeof value.message === 'string' ? { message: value.message.slice(0, 500) } : {}),\n }\n } catch {\n return null\n }\n}\n\nfunction isTailscaleAuthURL(value: string | undefined): boolean {\n if (!value) return false\n try {\n const url = new URL(value)\n return url.protocol === 'https:' &&\n (url.hostname === 'login.tailscale.com' || url.hostname.endsWith('.login.tailscale.com'))\n } catch {\n return false\n }\n}\n\n/** Translate Node's platform/architecture names to the GOOS/GOARCH directory\n * names used by the committed helper matrix. */\nexport function bundledHelperPlatformDir(\n platform: NodeJS.Platform = process.platform,\n arch: string = process.arch,\n): string {\n const goos = platform === 'win32' ? 'windows' : platform\n const goarch = arch === 'x64' ? 'amd64' : arch\n return `${goos}-${goarch}`\n}\n\n/** Build the list of candidate locations for the embedded tunnel helper, in\n * priority order. The first existing executable wins at start() time. The\n * order matters: explicit config (handled by the caller) > npm install\n * layout > DSH-bundled layout > user data dir. */\nexport function bundledHelperCandidates(\n platform: NodeJS.Platform = process.platform,\n arch: string = process.arch,\n): string[] {\n const here = dirname(fileURLToPath(import.meta.url))\n const pkgRoot = resolve(here, '..')\n const fileName = platform === 'win32' ? 'dsh-deeppilot-tunnel.exe' : 'dsh-deeppilot-tunnel'\n const platformDir = bundledHelperPlatformDir(platform, arch)\n\n const candidates: string[] = []\n // 1. Standard npm layout: <pkgRoot>/bin/<os>-<arch>/<file>\n candidates.push(resolve(pkgRoot, 'bin', platformDir, fileName))\n // 2. DSH sometimes relocates lib/ into apps/web or a build cache while\n // leaving bin/ beside the original package root. Try a few hops up.\n candidates.push(resolve(pkgRoot, '..', '..', '..', 'node_modules', 'dsh-deeppilot', 'bin', platformDir, fileName))\n candidates.push(resolve(pkgRoot, '..', '..', 'dsh-deeppilot', 'bin', platformDir, fileName))\n candidates.push(resolve(pkgRoot, '..', '..', '..', '..', 'node_modules', 'dsh-deeppilot', 'bin', platformDir, fileName))\n\n // 3. As a last resort, ask the loader to resolve the binary via Node's\n // package resolution. Works when bin/ is shipped but import.meta.url\n // points somewhere unexpected.\n try {\n const require = createRequire(import.meta.url)\n const resolved = require.resolve(`dsh-deeppilot/bin/${platformDir}/${fileName}`)\n if (!candidates.includes(resolved)) candidates.push(resolved)\n } catch {\n /* package.json exports field may not list bin/ — ignore */\n }\n\n // 4. User data dir fallback so power users can drop a custom build in.\n const home = process.env.DSH_HOME?.trim()\n || process.env.HOME\n || process.env.USERPROFILE\n if (home && home.length > 0) {\n const dataDir = resolve(home, '.dsh')\n candidates.push(join(dataDir, 'deeppilot', 'bin', platformDir, fileName))\n }\n\n return candidates\n}\n\n/** Owns exactly one embedded tunnel helper and restarts it after failures. */\nexport class RemoteSupervisor {\n private child: ChildProcess | undefined\n private restartTimer: NodeJS.Timeout | undefined\n private restartAttempt = 0\n private stopping = false\n private statusValue: RemoteStatus\n\n constructor(private readonly options: RemoteSupervisorOptions) {\n this.statusValue = {\n provider: 'tailscale-funnel',\n phase: options.enabled ? 'stopped' : 'disabled',\n updatedAt: Date.now(),\n }\n }\n\n status(): RemoteStatus {\n return { ...this.statusValue }\n }\n\n async start(originURL: string): Promise<void> {\n if (!this.options.enabled || this.child !== undefined || this.stopping) return\n const statePath = expandHome(this.options.statePath)\n // Resolve a usable helper path. An explicit remote.helperPath wins; if it\n // is missing, fall back to a small set of candidate locations so that\n // DSH-bundled layouts and manually-dropped builds still work.\n const configured = this.options.helperPath?.trim() ?? ''\n const candidates = configured\n ? [expandHome(configured)]\n : bundledHelperCandidates()\n let helper: string | undefined\n let lastError: unknown\n for (const candidate of candidates) {\n try {\n await access(candidate, fsConstants.X_OK)\n helper = candidate\n break\n } catch (error) {\n lastError = error\n }\n }\n if (helper === undefined) {\n // A dispose() that raced these checks must not be overwritten by a\n // late failure report.\n if (this.stopping) return\n const platform = `${process.platform}-${process.arch}`\n const message = configured\n ? `embedded tunnel helper unavailable: ${configured}: ${String(lastError ?? 'not found')}`\n : `embedded tunnel helper not found for ${platform} (tried: ${candidates.join(', ')}); set remote.helperPath to override`\n this.setStatus({ phase: 'unavailable', message })\n this.scheduleRestart(originURL, 'unavailable')\n return\n }\n try {\n await mkdir(statePath, { recursive: true, mode: 0o700 })\n } catch (error) {\n if (this.stopping) return\n this.setStatus({ phase: 'unavailable', message: `cannot create remote state dir: ${String(error)}` })\n this.scheduleRestart(originURL, 'unavailable')\n return\n }\n\n // dispose() may have run while the filesystem checks above were in\n // flight; spawning afterwards would orphan a helper process that nothing\n // will ever reap (dispose already returned seeing no child).\n if (this.stopping) return\n\n this.setStatus({ phase: 'starting', message: undefined })\n const child = spawn(helper, tunnelHelperArguments(originURL, statePath, this.options), {\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n PATH: process.env.PATH ?? '/usr/bin:/bin',\n TMPDIR: process.env.TMPDIR ?? '/tmp',\n },\n })\n this.child = child\n if (child.stdout === null || child.stderr === null) {\n this.setStatus({ phase: 'error', message: 'helper stdio unavailable' })\n child.kill('SIGTERM')\n return\n }\n\n let stdoutBuffer = ''\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => {\n stdoutBuffer += chunk\n const lines = stdoutBuffer.split('\\n')\n stdoutBuffer = lines.pop() ?? ''\n for (const line of lines) this.acceptLine(line)\n })\n\n // Keep enough stderr to write a full crash dump on exit; the summary the\n // user sees is derived from this buffer.\n let stderrBuffer = ''\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => {\n stderrBuffer = (stderrBuffer + chunk).slice(-16_000)\n })\n\n child.once('error', (error) => {\n this.setStatus({ phase: 'error', message: `helper launch failed: ${String(error)}` })\n })\n child.once('exit', () => {\n if (this.child === child) this.child = undefined\n if (this.stopping) {\n this.setStatus({ phase: 'stopped', message: undefined })\n return\n }\n void analyzeCrashExit(stderrBuffer, this.options.statePath).then((analysis) => {\n if (this.stopping) return\n const message = analysis.summary + (analysis.dumpPath !== undefined ? ` (full dump: ${analysis.dumpPath})` : '')\n this.setStatus({\n phase: 'error',\n message,\n })\n this.scheduleRestart(originURL, 'crash')\n })\n })\n }\n\n async dispose(): Promise<void> {\n this.stopping = true\n if (this.restartTimer !== undefined) clearTimeout(this.restartTimer)\n this.restartTimer = undefined\n const child = this.child\n this.child = undefined\n if (child === undefined) {\n this.setStatus({ phase: 'stopped', message: undefined })\n return\n }\n await new Promise<void>((resolveDone) => {\n const force = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL')\n }, 3_000)\n child.once('exit', () => {\n clearTimeout(force)\n resolveDone()\n })\n child.kill('SIGTERM')\n })\n this.setStatus({ phase: 'stopped', message: undefined })\n }\n\n private acceptLine(line: string): void {\n const event = parseHelperEvent(line)\n if (event === null || event.phase === undefined) return\n if (event.phase === 'login_required') {\n // UserLogf is diagnostic output, not a typed auth callback. Accept only\n // the known login origin, and never let an incidental runtime URL knock\n // an already-online Funnel back into the setup state.\n if (this.statusValue.phase === 'online' || !isTailscaleAuthURL(event.authURL)) return\n }\n if (event.phase === 'online') this.restartAttempt = 0\n this.setStatus({ ...event, phase: event.phase })\n }\n\n private scheduleRestart(originURL: string, kind: 'unavailable' | 'crash' = 'crash'): void {\n if (this.stopping || this.restartTimer !== undefined) return\n // Configuration-level failures (helper missing, state dir unwritable)\n // cannot self-heal in a tight loop; throttle to one probe per minute so\n // a misconfigured Host stays observable without becoming a CPU sink.\n // Crashes still get the original exponential backoff so a transient\n // helper failure recovers quickly.\n const delay = kind === 'unavailable'\n ? UNAVAILABLE_RETRY_MS\n : RESTART_DELAYS_MS[Math.min(this.restartAttempt, RESTART_DELAYS_MS.length - 1)]\n if (kind === 'crash') this.restartAttempt += 1\n this.restartTimer = setTimeout(() => {\n this.restartTimer = undefined\n void this.start(originURL)\n }, delay)\n this.restartTimer.unref?.()\n }\n\n private setStatus(next: Partial<RemoteStatus> & Pick<RemoteStatus, 'phase'>): void {\n const cleared: Partial<RemoteStatus> = next.phase === 'online'\n ? { authURL: undefined, message: undefined }\n : next.phase === 'login_required'\n ? { publicURL: undefined, message: undefined }\n : next.phase === 'starting' || next.phase === 'stopped' || next.phase === 'disabled'\n ? { publicURL: undefined, authURL: undefined, message: undefined }\n : {}\n this.statusValue = {\n ...this.statusValue,\n ...cleared,\n ...next,\n updatedAt: Date.now(),\n }\n if (next.phase === 'online') {\n this.options.log('remote Funnel online')\n } else if (next.phase === 'login_required') {\n this.options.log('remote Funnel requires browser authorization')\n } else if (next.phase === 'error' || next.phase === 'unavailable') {\n this.options.log(`remote Funnel ${next.phase}: ${next.message ?? 'unknown error'}`)\n }\n }\n}\n","import { networkInterfaces } from 'node:os'\n\nexport function isPrivateIPv4(address: string): boolean {\n const octets = address.split('.').map(Number)\n if (octets.length !== 4 || octets.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {\n return false\n }\n const [a, b] = octets as [number, number, number, number]\n return a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168)\n}\n\n/** Private IPv4 candidates, preferring physical en* interfaces over tunnels. */\nexport function localLANIPv4Addresses(): string[] {\n const candidates: Array<{ name: string; address: string }> = []\n for (const [name, entries] of Object.entries(networkInterfaces())) {\n for (const entry of entries ?? []) {\n if (entry.family === 'IPv4' && !entry.internal && isPrivateIPv4(entry.address)) {\n candidates.push({ name, address: entry.address })\n }\n }\n }\n const priority = (name: string): number => name === 'en0' ? 0 : name.startsWith('en') ? 1 : name.startsWith('bridge') ? 2 : 3\n candidates.sort((left, right) => priority(left.name) - priority(right.name) || left.name.localeCompare(right.name))\n return [...new Set(candidates.map(({ address }) => address))]\n}\n","/**\n * Lightweight self-update check for dsh-deeppilot.\n *\n * On Host boot we ask the GitHub Releases API (REST) which is the latest\n * stable tag, compare it to the installed plugin version, and surface a\n * \"newer release exists\" flag plus the GitHub release URL through the\n * report Remote. The settings page renders one small line at the bottom;\n * a successful check is enough — no manual button, no persistent cache\n * (the host process is the lifetime of the answer).\n *\n * Deliberately no third-party dependency: we use {@link https.request}\n * directly to keep parity with the rest of the project (remote-supervisor\n * uses node:http, host-bridge uses ws, etc).\n *\n * Failure policy: every network/parse error collapses to a single log\n * line and the in-memory snapshot stays \"unknown\". The bridge must never\n * crash because GitHub rate-limited us, returned a 5xx, or the user is\n * offline.\n */\n\nimport { request as httpsRequest, type RequestOptions } from 'node:https'\n\n/** GitHub repo (no .git suffix). Public, unauthenticated, low rate limit. */\nconst RELEASES_PATH = '/repos/Mars-Sea/dsh-deeppilot/releases'\n\n/** Hard ceiling on the network round-trip. The host must never hang. */\nconst FETCH_TIMEOUT_MS = 8_000\n\n/** Per-page limit. We only need the first stable release, but pre-releases\n * tend to be listed first; fetching 20 gives the comparator enough room. */\nconst PER_PAGE = 20\n\n/**\n * Public snapshot surfaced to the report Remote. `available` is `false`\n * until the network answer lands; on failure it stays `false` so the UI\n * simply doesn't render the \"new version\" hint.\n */\nexport interface UpdateInfo {\n /** Host plugin version (from package.json). */\n currentVersion: string\n /** True once a newer stable release has been found on GitHub. */\n available: boolean\n /** GitHub release page URL, when an update is available. */\n releaseUrl: string | null\n /** Newer stable tag, when an update is available. */\n latestVersion: string | null\n}\n\ninterface GitHubRelease {\n tag_name?: unknown\n prerelease?: unknown\n draft?: unknown\n html_url?: unknown\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction parseStableEntry(value: unknown): { tag: string; url: string | null } | null {\n if (!isPlainObject(value)) return null\n const tag = value.tag_name\n if (typeof tag !== 'string') return null\n if (value.prerelease === true || value.draft === true) return null\n if (parseStableTag(tag) === null) return null\n const url = value.html_url\n return { tag, url: typeof url === 'string' ? url : null }\n}\n\n/** Parse one stable release from the `tag_name` shape `vX.Y.Z` (the v is\n * optional; `1.2.3` is also accepted). Pre-release tags like `0.3.0-rc.1`\n * return null — the policy is \"stable channel only\". */\nexport function parseStableTag(tag: string): { major: number; minor: number; patch: number } | null {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)$/.exec(tag.trim())\n if (match === null) return null\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n }\n}\n\n/** Semver compare for X.Y.Z. Returns -1 / 0 / 1. */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parseStableTag(a)\n const pb = parseStableTag(b)\n if (pa === null && pb === null) return 0\n if (pa === null) return -1\n if (pb === null) return 1\n if (pa.major !== pb.major) return pa.major < pb.major ? -1 : 1\n if (pa.minor !== pb.minor) return pa.minor < pb.minor ? -1 : 1\n if (pa.patch !== pb.patch) return pa.patch < pb.patch ? -1 : 1\n return 0\n}\n\n/** Hit the GitHub Releases API. Resolves with the first stable release\n * GitHub returned, or null if the list contains no stable entries.\n * Network / parse errors reject — the caller is responsible for\n * collapsing them to a log line. */\nexport function fetchLatestStableRelease(): Promise<{ tag: string; url: string | null } | null> {\n return new Promise((resolve, reject) => {\n const options: RequestOptions = {\n method: 'GET',\n host: 'api.github.com',\n path: `${RELEASES_PATH}?per_page=${PER_PAGE}`,\n headers: {\n 'user-agent': 'dsh-deeppilot-update-check',\n 'accept': 'application/vnd.github+json',\n },\n }\n const req = httpsRequest(options, (res) => {\n const status = res.statusCode ?? 0\n if (status < 200 || status >= 300) {\n res.resume()\n reject(new Error(`github releases http ${status}`))\n return\n }\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => chunks.push(chunk))\n res.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf8')\n const parsed = JSON.parse(body) as unknown\n if (!Array.isArray(parsed)) {\n reject(new Error('github releases: response is not an array'))\n return\n }\n for (const entry of parsed) {\n const stable = parseStableEntry(entry)\n if (stable !== null) {\n resolve(stable)\n return\n }\n }\n resolve(null)\n } catch (error) {\n reject(error instanceof Error ? error : new Error(String(error)))\n }\n })\n res.on('error', (error) => reject(error))\n })\n req.setTimeout(FETCH_TIMEOUT_MS, () => {\n req.destroy(new Error('github releases: timeout after ' + FETCH_TIMEOUT_MS + 'ms'))\n })\n req.on('error', (error) => reject(error))\n req.end()\n })\n}\n\n/**\n * Process-wide check state. Constructed once in `apply()`, queried\n * synchronously by the report snapshot. The check itself fires once in\n * the background shortly after boot; the answer lives for the lifetime\n * of the host process — re-running the page in the Web UI does not\n * trigger another network call.\n */\nexport class UpdateChecker {\n private readonly log: (message: string) => void\n private readonly currentVersion: string\n private readonly fetchImpl: typeof fetchLatestStableRelease\n private readonly initialDelayMs: number\n private snapshot: UpdateInfo\n private inflight: Promise<void> | null = null\n\n constructor(options: {\n log: (message: string) => void\n currentVersion: string\n fetchImpl?: typeof fetchLatestStableRelease\n initialDelayMs?: number\n }) {\n this.log = options.log\n this.currentVersion = options.currentVersion\n this.fetchImpl = options.fetchImpl ?? fetchLatestStableRelease\n this.initialDelayMs = options.initialDelayMs ?? 2_000\n this.snapshot = {\n currentVersion: this.currentVersion,\n available: false,\n releaseUrl: null,\n latestVersion: null,\n }\n }\n\n /** Return the current in-memory snapshot — safe to call from any host\n * thread. Never throws, never awaits. */\n get(): UpdateInfo {\n return this.snapshot\n }\n\n /**\n * Schedule one background refresh after the configured initial delay.\n * Used by the plugin entry to do the first check without blocking boot.\n */\n scheduleInitial(): void {\n if (this.initialDelayMs <= 0) {\n void this.runOnce()\n return\n }\n const timer = setTimeout(() => {\n void this.runOnce()\n }, this.initialDelayMs)\n if (typeof (timer as { unref?: () => void }).unref === 'function') {\n (timer as { unref: () => void }).unref()\n }\n }\n\n private async runOnce(): Promise<void> {\n if (this.inflight !== null) {\n await this.inflight\n return\n }\n const task = (async () => {\n try {\n const stable = await this.fetchImpl()\n if (stable === null) {\n // No stable release on GitHub (yet) — leave `available` false.\n return\n }\n if (compareSemver(stable.tag, this.currentVersion) > 0) {\n this.snapshot = {\n currentVersion: this.currentVersion,\n available: true,\n releaseUrl: stable.url,\n latestVersion: stable.tag,\n }\n } else {\n // Up to date. Clear any previous \"available\" state so a host\n // restart after an upgrade immediately stops showing the hint.\n this.snapshot = {\n currentVersion: this.currentVersion,\n available: false,\n releaseUrl: null,\n latestVersion: null,\n }\n }\n } catch (error) {\n this.log('update check failed: ' + (error instanceof Error ? error.message : String(error)))\n // Leave the previous snapshot in place. Even \"no answer\" is a\n // worse signal than the last successful check.\n }\n })()\n this.inflight = task.finally(() => {\n this.inflight = null\n })\n return this.inflight\n }\n\n /** No-op kept for API symmetry with the host lifecycle wiring. */\n dispose(): void {\n // The initial-delay timer is unref'd; nothing to track here.\n }\n}\n","export const DEFAULT_LOCAL_PORT = 3098\nexport const MIN_LOCAL_PORT = 1024\nexport const MAX_LOCAL_PORT = 65_535\n\nexport function normalizeLocalPort(value: unknown): number {\n return typeof value === 'number'\n && Number.isInteger(value)\n && value >= MIN_LOCAL_PORT\n && value <= MAX_LOCAL_PORT\n ? value\n : DEFAULT_LOCAL_PORT\n}\n\nexport function localEndpointURLs(addresses: readonly string[], port: number): string[] {\n const normalizedPort = normalizeLocalPort(port)\n return [...new Set(addresses)].map((address) => `http://${address}:${normalizedPort}`)\n}\n\nexport function localListenError(error: unknown, port: number): string {\n const code = (error as NodeJS.ErrnoException | undefined)?.code\n if (code === 'EADDRINUSE') return `local port ${port} is already in use`\n if (code === 'EACCES') return `permission denied while opening local port ${port}`\n return error instanceof Error ? error.message : String(error)\n}\n","import { join } from 'node:path'\nimport z from '@deepseek-ai/schemastery'\nimport {\n DEFAULT_REMOTE_HOSTNAME,\n} from './remote-supervisor.ts'\nimport { DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE, MAX_FUNNEL_CONNECTIONS_PER_SOURCE } from './funnel-policy.ts'\nimport { bridgeDataDir } from './token.ts'\nimport { DEFAULT_LOCAL_PORT, MAX_LOCAL_PORT, MIN_LOCAL_PORT } from './local-policy.ts'\n\nexport interface Config {\n /** Master switch; when false the plugin activates and does nothing. */\n enabled?: boolean\n /** Protocol-v2 device registry JSON path. */\n devicesPath?: string\n /** Replay ring buffer bound (frames) per deployment. */\n historyBufferMax?: number\n /** Verbose per-frame diagnostics (never prints token or message bodies). */\n debug?: boolean\n /** Independent LAN transport. Never exposes the wider DSH web server. */\n local?: {\n enabled?: boolean\n port?: number\n }\n /** Optional embedded remote transport. Reconciled when settings change. */\n remote?: {\n enabled?: boolean\n provider?: 'tailscale-funnel'\n hostname?: string\n statePath?: string\n helperPath?: string\n funnelPort?: 443 | 8443 | 10000\n /** Concurrent Funnel WebSockets allowed from one public source address. */\n maxConnectionsPerSource?: number\n }\n /**\n * Offline push (F-9). `apns` sends directly from the Mac with the user's\n * Apple credentials. `relay` sends notify projections to an operator-run\n * relay for distributed builds. The device reports its own APNs environment,\n * so development and TestFlight/App Store devices may coexist.\n */\n push?: {\n /** `none` (default), `apns`, or `relay`. */\n provider?: 'none' | 'apns' | 'relay'\n /** Apple Developer team id (JWT iss claim). */\n teamId?: string\n /** APNs auth key id (JWT kid header). */\n keyId?: string\n /** `.p8` private key path. */\n keyPath?: string\n /** App bundle id — the apns-topic header. */\n bundleId?: string\n /** Relay base URL. */\n relayUrl?: string\n /** Per-user bearer token issued by the relay operator. */\n relayToken?: string\n }\n}\n\n/** Operator-run relay used by distributed builds; overridable via config. */\nexport const DEFAULT_RELAY_URL = 'https://pilot.hailab.dev'\n\nexport const Config = z.object({\n enabled: z.boolean().default(true),\n devicesPath: z.string().default(join(bridgeDataDir(), 'devices-v2.json')),\n historyBufferMax: z.natural().min(100).default(2000),\n debug: z.boolean().default(false),\n local: z.object({\n enabled: z.boolean().default(true),\n port: z.natural()\n .min(MIN_LOCAL_PORT)\n .max(MAX_LOCAL_PORT)\n .default(DEFAULT_LOCAL_PORT)\n .description('DeepPilot 局域网独立端口(默认 3098,修改后本地连接会短暂重连)'),\n }).default({\n enabled: true,\n port: DEFAULT_LOCAL_PORT,\n }),\n remote: z.object({\n enabled: z.boolean().default(false),\n provider: z.union(['tailscale-funnel'] as const).default('tailscale-funnel'),\n hostname: z.string().default(DEFAULT_REMOTE_HOSTNAME),\n statePath: z.string().default(join(bridgeDataDir(), 'tailscale')),\n helperPath: z.string().default(''),\n funnelPort: z.union([443, 8443, 10000] as const).default(443),\n maxConnectionsPerSource: z.natural()\n .min(1)\n .max(MAX_FUNNEL_CONNECTIONS_PER_SOURCE)\n .default(DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE)\n .description('Funnel 每个来源允许的并发连接数(1–16,修改后远程连接会短暂重连)'),\n }).default({\n enabled: false,\n provider: 'tailscale-funnel',\n hostname: DEFAULT_REMOTE_HOSTNAME,\n statePath: join(bridgeDataDir(), 'tailscale'),\n helperPath: '',\n funnelPort: 443,\n maxConnectionsPerSource: DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE,\n }),\n push: z.object({\n provider: z.union(['none', 'apns', 'relay'] as const).default('none'),\n teamId: z.string().default(''),\n keyId: z.string().default(''),\n keyPath: z.string().default(join(bridgeDataDir(), 'apns', 'AuthKey.p8')),\n bundleId: z.string().default('dev.hailab.deeppilot'),\n relayUrl: z.string().default(DEFAULT_RELAY_URL),\n relayToken: z.string().default(''),\n }).default({\n provider: 'none',\n teamId: '',\n keyId: '',\n keyPath: join(bridgeDataDir(), 'apns', 'AuthKey.p8'),\n bundleId: 'dev.hailab.deeppilot',\n relayUrl: DEFAULT_RELAY_URL,\n relayToken: '',\n }),\n})\n\n/**\n * Cordis hands the second argument in different shapes depending on host\n * composition: a reactive options getter, the resolved config value, or\n * nothing when the patch row omits `config`. Normalize all of them.\n */\nexport function normalizeOptions(options: unknown): Config {\n if (typeof options === 'function') return (options as () => Config)()\n if (options && typeof options === 'object') return options as Config\n const validated = (Config as unknown as (data: unknown) => Config)(undefined)\n return validated ?? {}\n}\n","import type { IncomingMessage } from 'node:http'\nimport { isIP } from 'node:net'\nimport type { Duplex } from 'node:stream'\n\nexport const CLIENT_IP_HEADER = 'x-deeppilot-client-ip'\n\nexport function rejectUpgrade(socket: Duplex, status: number, reason: string, retryAfterSeconds?: number): void {\n const body = JSON.stringify({ error: reason })\n const statusText: Record<number, string> = {\n 401: 'Unauthorized',\n 429: 'Too Many Requests',\n 500: 'Internal Server Error',\n 503: 'Service Unavailable',\n }\n const retryAfter = status === 429 && retryAfterSeconds !== undefined\n ? `Retry-After: ${Math.max(1, Math.ceil(retryAfterSeconds))}\\r\\n`\n : ''\n socket.end(\n 'HTTP/1.1 ' + status + ' ' + (statusText[status] ?? 'Error') + '\\r\\n' +\n retryAfter +\n 'Content-Type: application/json\\r\\n' +\n 'Content-Length: ' + Buffer.byteLength(body) + '\\r\\n' +\n 'Connection: close\\r\\n' +\n '\\r\\n' +\n body,\n )\n}\n\nfunction normalizedAddress(value: string | undefined): string | null {\n if (!value) return null\n const normalized = value.startsWith('::ffff:') ? value.slice(7) : value\n return isIP(normalized) === 0 ? null : normalized\n}\n\nfunction isLoopback(value: string | undefined): boolean {\n const address = normalizedAddress(value)\n return address === '127.0.0.1' || address === '::1'\n}\n\n/**\n * Resolve a stable rate-limit key. The helper-supplied address is trusted only\n * on the private loopback hop; direct clients cannot spoof it.\n */\nexport function requestClientIdentity(\n req: Pick<IncomingMessage, 'headers' | 'socket'>,\n): string {\n if (isLoopback(req.socket.remoteAddress)) {\n const forwarded = req.headers[CLIENT_IP_HEADER]\n const value = Array.isArray(forwarded) ? forwarded[0] : forwarded\n const address = normalizedAddress(value)\n if (address !== null) return address\n }\n return normalizedAddress(req.socket.remoteAddress) ?? 'unknown'\n}\n","export interface AuthRatePolicy {\n windowMs: number\n attemptsPerSource: number\n globalAttempts: number\n maxUnauthenticatedPerSource: number\n failureWindowMs: number\n failuresBeforeBlock: number\n blockMs: number\n maxSources: number\n}\n\nexport const DEFAULT_AUTH_RATE_POLICY: AuthRatePolicy = {\n windowMs: 60_000,\n attemptsPerSource: 12,\n globalAttempts: 120,\n maxUnauthenticatedPerSource: 2,\n failureWindowMs: 10 * 60_000,\n failuresBeforeBlock: 5,\n blockMs: 15 * 60_000,\n maxSources: 4_096,\n}\n\ninterface SourceState {\n attempts: number[]\n failures: number[]\n blockedUntil: number\n active: number\n lastSeen: number\n}\n\nexport interface AuthAdmission {\n ok: boolean\n retryAfterMs: number\n release: () => void\n}\n\nexport interface AuthFailureResult {\n blocked: boolean\n newlyBlocked: boolean\n retryAfterMs: number\n}\n\nconst noop = (): void => {}\n\n/** Bounded in-memory protection for anonymous authentication attempts. */\nexport class AuthRateLimiter {\n private readonly sources = new Map<string, SourceState>()\n private globalAttempts: number[] = []\n\n constructor(private readonly policy: AuthRatePolicy = DEFAULT_AUTH_RATE_POLICY) {}\n\n admit(source: string, now = Date.now()): AuthAdmission {\n const state = this.source(source, now)\n if (state === null) return { ok: false, retryAfterMs: this.policy.windowMs, release: noop }\n this.prune(state, now)\n state.lastSeen = now\n\n if (state.blockedUntil > now) {\n return { ok: false, retryAfterMs: state.blockedUntil - now, release: noop }\n }\n if (state.active >= this.policy.maxUnauthenticatedPerSource) {\n return { ok: false, retryAfterMs: this.policy.windowMs, release: noop }\n }\n if (state.attempts.length >= this.policy.attemptsPerSource) {\n return { ok: false, retryAfterMs: state.attempts[0]! + this.policy.windowMs - now, release: noop }\n }\n this.globalAttempts = this.globalAttempts.filter((ts) => ts > now - this.policy.windowMs)\n if (this.globalAttempts.length >= this.policy.globalAttempts) {\n return { ok: false, retryAfterMs: this.globalAttempts[0]! + this.policy.windowMs - now, release: noop }\n }\n\n state.attempts.push(now)\n this.globalAttempts.push(now)\n state.active += 1\n let released = false\n return {\n ok: true,\n retryAfterMs: 0,\n release: () => {\n if (released) return\n released = true\n state.active = Math.max(0, state.active - 1)\n },\n }\n }\n\n recordFailure(source: string, now = Date.now()): AuthFailureResult {\n const state = this.source(source, now)\n if (state === null) return { blocked: true, newlyBlocked: false, retryAfterMs: this.policy.blockMs }\n this.prune(state, now)\n state.lastSeen = now\n const wasBlocked = state.blockedUntil > now\n state.failures.push(now)\n if (state.failures.length >= this.policy.failuresBeforeBlock) {\n state.blockedUntil = Math.max(state.blockedUntil, now + this.policy.blockMs)\n }\n return {\n blocked: state.blockedUntil > now,\n newlyBlocked: !wasBlocked && state.blockedUntil > now,\n retryAfterMs: Math.max(0, state.blockedUntil - now),\n }\n }\n\n recordSuccess(source: string, now = Date.now()): void {\n const state = this.sources.get(source)\n if (state === undefined) return\n state.failures = []\n state.blockedUntil = 0\n state.lastSeen = now\n }\n\n private source(source: string, now: number): SourceState | null {\n const existing = this.sources.get(source)\n if (existing !== undefined) return existing\n if (this.sources.size >= this.policy.maxSources) this.pruneSources(now)\n if (this.sources.size >= this.policy.maxSources) return null\n const state: SourceState = { attempts: [], failures: [], blockedUntil: 0, active: 0, lastSeen: now }\n this.sources.set(source, state)\n return state\n }\n\n private prune(state: SourceState, now: number): void {\n state.attempts = state.attempts.filter((ts) => ts > now - this.policy.windowMs)\n state.failures = state.failures.filter((ts) => ts > now - this.policy.failureWindowMs)\n if (state.blockedUntil <= now) state.blockedUntil = 0\n }\n\n private pruneSources(now: number): void {\n const staleBefore = now - Math.max(this.policy.failureWindowMs, this.policy.blockMs)\n for (const [source, state] of this.sources) {\n this.prune(state, now)\n if (state.active === 0 && state.blockedUntil === 0 && state.lastSeen < staleBefore) {\n this.sources.delete(source)\n }\n }\n }\n}\n","/** Prune only when the provider supplies an authoritative token-lifecycle verdict. */\nexport function shouldPrunePushToken(\n outcome: 'sent' | 'invalid-token' | 'failed',\n reason?: string,\n): boolean {\n return outcome === 'invalid-token' && (reason === 'Unregistered' || reason === 'ExpiredToken')\n}\n\n/**\n * Zero-touch relay self-heal: HTTP 401 means the relay no longer honors the\n * cached credential. Only auto-enrolled cells with a still-current token may\n * re-derive it; an explicitly configured relay token remains user-owned\n * configuration and is never silently rewritten.\n */\nexport function shouldReEnrollRelayToken(\n transport: 'apns' | 'relay',\n outcome: 'sent' | 'invalid-token' | 'failed',\n reason: string | undefined,\n opts: { usedCellToken: boolean; hasEnrollKey: boolean; tokenStillCurrent: boolean },\n): boolean {\n return (\n transport === 'relay' &&\n outcome === 'failed' &&\n reason === 'HTTP 401' &&\n opts.hasEnrollKey &&\n opts.usedCellToken &&\n opts.tokenStillCurrent\n )\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport type { Duplex } from 'node:stream'\n\nexport interface PhoneServerHandlers {\n health(req: IncomingMessage, res: ServerResponse): void | Promise<void>\n pair(req: IncomingMessage, res: ServerResponse): void | Promise<void>\n upgrade(req: IncomingMessage, socket: Duplex, head: Buffer): void\n}\n\n/**\n * A deliberately narrow transport listener. Both the LAN endpoint and the\n * loopback-only Funnel origin use this factory, so neither can accidentally\n * inherit DSH's wider web/API route surface.\n */\nexport function createPhoneServer(handlers: PhoneServerHandlers): Server {\n const server = createServer((req, res) => {\n const path = requestPath(req)\n if (path === '/phone/health') {\n void handlers.health(req, res)\n } else if (path === '/phone/pair') {\n void handlers.pair(req, res)\n } else {\n res.statusCode = 404\n res.end('not found')\n }\n })\n server.on('upgrade', (req, socket, head) => {\n if (requestPath(req) !== '/phone') {\n socket.end('HTTP/1.1 404 Not Found\\r\\nConnection: close\\r\\n\\r\\n')\n return\n }\n handlers.upgrade(req, socket, head)\n })\n return server\n}\n\nfunction requestPath(req: IncomingMessage): string {\n try {\n return new URL(req.url ?? '/', 'http://phone.local').pathname\n } catch {\n return '/'\n }\n}\n\nexport function listen(server: Server, port: number, host: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const onError = (error: Error): void => {\n server.off('listening', onListening)\n reject(error)\n }\n const onListening = (): void => {\n server.off('error', onError)\n resolve()\n }\n server.once('error', onError)\n server.once('listening', onListening)\n server.listen(port, host)\n })\n}\n\nexport function closeServer(server: Server | undefined): Promise<void> {\n if (server === undefined || !server.listening) return Promise.resolve()\n return new Promise((resolve) => server.close(() => resolve()))\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { createHash, randomBytes } from 'node:crypto'\nimport { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport type { Duplex } from 'node:stream'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { WebSocketServer } from 'ws'\nimport { BridgeConnection } from './connection.ts'\nimport { HostBridge } from './host-bridge.ts'\nimport type { PushOutlet } from './host-bridge.ts'\nimport { Dsh012ApiProxy, type DshInteractionKind } from './dsh012-api-proxy.ts'\nimport type { SettingsSectionHooks } from '@deepseek-ai/dsh-settings'\nimport { applyReportRemote } from './report-remote.ts'\nimport { runRelayProbe } from './relay-test.ts'\nimport type { DeepPilotReport, PushTestResult } from './report-wire.ts'\nimport { DeviceStore, MAX_DEVICES, bridgeDataDir, ensurePrivateBridgeDataDir, expandHome, migrateLegacyBridgeDataDir } from './token.ts'\nimport type { ApnsEnvironment } from './token.ts'\nimport {\n PairingCodeManager,\n deviceIdForPublicKey,\n loadOrCreateHostAudience,\n normalizeDeviceScopes,\n} from './device-auth.ts'\nimport { ApnsClient } from './apns.ts'\nimport { RelayClient } from './relay-client.ts'\nimport type { PushNotification } from './protocol.ts'\nimport {\n DEFAULT_REMOTE_HOSTNAME,\n normalizeRemoteHostname,\n RemoteSupervisor,\n type RemoteStatus,\n} from './remote-supervisor.ts'\nimport { normalizeFunnelConnectionLimit } from './funnel-policy.ts'\nimport { localLANIPv4Addresses } from './local-address.ts'\nimport { UpdateChecker, type UpdateInfo } from './update-check.ts'\nimport { Config, DEFAULT_RELAY_URL, normalizeOptions } from './config.ts'\nimport type { Config as PluginConfig } from './config.ts'\nimport { rejectUpgrade, requestClientIdentity } from './phone-http.ts'\nimport { AuthRateLimiter } from './auth-rate-limit.ts'\nimport { shouldPrunePushToken, shouldReEnrollRelayToken } from './push-policy.ts'\nimport { MAX_APP_VERSION_CHARS, MAX_DEVICE_NAME_CHARS, sanitizeDeviceField } from './connection-policy.ts'\nimport { DEFAULT_LOCAL_PORT, localEndpointURLs, localListenError, normalizeLocalPort } from './local-policy.ts'\nimport { closeServer, createPhoneServer, listen } from './phone-server.ts'\n\n/**\n * dsh-deeppilot — data bridge between the DSH host and DeepPilot\n * clients. Owns independent, narrowly routed LAN and Funnel-origin listeners;\n * temporary compatibility routes remain on the existing DSH web server. The\n * web UI and the rest of DSH's API are never exposed by these listeners.\n *\n * Data plane: an in-process HostBridge consumes a local compatibility façade\n * over DSH 0.1.2 Session/Workspace controllers, mirrors session summaries,\n * tracks pending approvals/questions, and fans projected protocol-v2 pushes\n * out to every connected device.\n *\n * Protocol: PROTOCOL.md is normative; src/protocol.ts and the private app's\n * Swift models mirror that v2 contract.\n */\n\nexport const name = 'deeppilot'\n\nexport { HostBridge } from './host-bridge.ts'\nexport { Config } from './config.ts'\nexport { shouldPrunePushToken, shouldReEnrollRelayToken } from './push-policy.ts'\n\n/** No eager web-service requirement: independent transports start on their own. */\nexport const inject: string[] = []\n\n\ninterface WebServerLike {\n register(route: {\n kind: 'exact' | 'prefix'\n path: string\n handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>\n }): () => void\n registerUpgrade(route: {\n path: string\n handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void\n }): () => void\n}\n\ntype SubContext = {\n effect: (setup: () => unknown, name?: string) => unknown\n}\n\nconst SERVER_VERSION = readOwnPackageVersion()\nconst MAX_CLIENT_CONNECTIONS = 16\n/**\n * Single-frame bound. Covers the protocol maximum (4 × 8 MB base64 images\n * plus prompt text) with headroom while keeping an unauthenticated client's\n * pre-hello buffering far below ws's 100 MiB default.\n */\nconst MAX_FRAME_BYTES = 64 * 1024 * 1024\n\n/**\n * Resolve the host plugin's own version from the installed package.json.\n * Sourced at boot so the wire / UI always agrees with what npm published.\n * `createRequire(import.meta.url)` is the tsdown-bundled ESM equivalent of\n * CommonJS's `require`; the package.json sits next to lib/index.js after\n * the build, so `../package.json` resolves to the published manifest.\n */\nfunction readOwnPackageVersion(): string {\n try {\n const require_ = createRequire(import.meta.url)\n const pkg = require_('../package.json') as { version?: unknown }\n if (typeof pkg.version === 'string' && pkg.version.length > 0) return pkg.version\n } catch {\n // fall through to env / hardcoded default below\n }\n // `npm` injects this for `npm run` / `npm exec` / `npm start` invocations.\n // `process.env.npm_package_version` is unset when DSH loads the plugin\n // directly, so we keep it as a secondary source rather than the truth.\n const envVersion = process.env.npm_package_version\n if (typeof envVersion === 'string' && envVersion.length > 0) return envVersion\n return '0.0.0+unknown'\n}\n\nexport function apply(ctx: Context, options: unknown): void {\n const cfg = normalizeOptions(options)\n\n const log = (message: string): void => {\n console.log('[deeppilot] ' + message)\n }\n const auditSalt = randomBytes(32)\n const auditLabel = (value: string): string => createHash('sha256')\n .update(auditSalt)\n .update(value)\n .digest('hex')\n .slice(0, 12)\n\n /**\n * Settings-section source: while a settings service is attached this holds\n * the user-edited section value; otherwise the composition defaults. Read\n * through currentConfig() everywhere (normalizeOptions prefers it).\n */\n let liveSource: (() => Config) | undefined\n let scheduleRemoteReconcile: (() => void) | undefined\n let scheduleLocalReconcile: (() => void) | undefined\n const currentConfig = (): Config => {\n if (liveSource !== undefined) return normalizeOptions(liveSource())\n return normalizeOptions(options)\n }\n const enabledNow = (): boolean => currentConfig().enabled === true\n\n // Web settings page: a \"deeppilot\" section with the plugin knobs.\n // Values persist through the settings document and re-enter via setSource;\n // `enabled` decides whether the bridge starts at all (next restart). This is\n // registered unconditionally so the master switch stays reachable even while\n // the bridge is off — otherwise a disabled bridge could never be re-enabled.\n const settingsHooks: SettingsSectionHooks<PluginConfig> = {\n setSource: (source) => {\n liveSource = source\n // Defer one microtask so the settings service can finish publishing the\n // new source before either transport runtime reads it.\n queueMicrotask(() => {\n scheduleLocalReconcile?.()\n scheduleRemoteReconcile?.()\n })\n },\n onChange: () => queueMicrotask(() => {\n scheduleLocalReconcile?.()\n scheduleRemoteReconcile?.()\n }),\n }\n ctx.inject(['settings'], (settingsCtx) => {\n settingsCtx.settings.installSection(\n ctx,\n 'deeppilot',\n Config,\n normalizeOptions(undefined),\n settingsHooks,\n )\n })\n\n // Master switch, resolved against the latest available settings document.\n // Individual injected services also read currentConfig() when they activate.\n if (currentConfig().enabled !== true) {\n log('disabled via settings; bridge stays inactive (rumors of /phone below are skipped)')\n }\n\n // Resolved asynchronously; route handlers await readiness. Never rejects:\n // a storage failure degrades the bridge instead of killing the host.\n const dataDir = bridgeDataDir()\n\n // ---------- zero-touch push enrollment (distributed builds) ----------\n\n /**\n * Persistent relay-enrollment cell (deeppilot/push-relay.json). A\n * distributed app presents the distributor's shared enrollKey during\n * c2s.push.register; the bridge then auto-enables relay mode, enrolls with\n * the operator's relay and caches the issued token. Users never fill in\n * anything; explicit config always wins over the auto flag.\n */\n interface RelayEnrollmentCell {\n clientId?: string\n autoRelay?: boolean\n enrollKey?: string\n token?: string\n }\n const pushRelayPath = join(dataDir, 'push-relay.json')\n const enrollmentCell: RelayEnrollmentCell = {}\n let enrollmentWriteTail: Promise<void> = Promise.resolve()\n\n function persistEnrollment(): void {\n const snapshot = JSON.stringify({ version: 1, ...enrollmentCell }, null, 2) + '\\n'\n enrollmentWriteTail = enrollmentWriteTail.then(async () => {\n const tempPath = pushRelayPath + '.' + randomBytes(6).toString('hex') + '.tmp'\n try {\n await mkdir(dataDir, { recursive: true })\n await writeFile(tempPath, snapshot, { mode: 0o600 })\n await rename(tempPath, pushRelayPath)\n } catch {\n await unlink(tempPath).catch(() => {})\n // best-effort persistence; enrollment retries on next trigger\n }\n })\n }\n\n /** Fired from BridgeConnection when an app presents its built-in key. */\n const handlePushEnrollKey = async (enrollKey: string): Promise<void> => {\n if (enrollmentCell.enrollKey !== enrollKey) {\n enrollmentCell.enrollKey = enrollKey\n }\n const configuredProvider = currentConfig().push?.provider\n // Only flip when the user has not made an explicit choice.\n if (!configuredProvider || configuredProvider === 'none') {\n if (!enrollmentCell.autoRelay) {\n enrollmentCell.autoRelay = true\n log('push relay mode auto-enabled by enrolled app')\n }\n }\n persistEnrollment()\n // Enroll inline so the register handler sees final readiness: the first\n // offline notification must not depend on a reconnect.\n const url = (currentConfig().push?.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n await ensureRelayEnrolled(url)\n }\n const pairingCodes = new PairingCodeManager()\n const auth: { audience: string | null; devices: DeviceStore | null } = {\n audience: null,\n devices: null,\n }\n const ready = (async () => {\n try {\n try {\n const migratedFrom = await migrateLegacyBridgeDataDir()\n if (migratedFrom !== null) log(`migrated legacy plugin state from ${migratedFrom} to ${dataDir}`)\n } catch (error) {\n log('legacy plugin-state migration skipped: ' + String(error))\n }\n await ensurePrivateBridgeDataDir()\n auth.audience = await loadOrCreateHostAudience(join(dataDir, 'host-id'))\n auth.devices = await DeviceStore.load(cfg.devicesPath ?? join(dataDir, 'devices-v2.json'))\n {\n // Startup visibility: makes \"registrations vanished after restart\"\n // instantly diagnosable (0 push rows ⇒ the file itself lost data).\n const rows = auth.devices.list()\n const registered = rows.filter((row) => row.apns !== undefined).length\n log(`device registry loaded from ${expandHome(cfg.devicesPath ?? join(dataDir, 'devices-v2.json'))}: ${rows.length} device(s), ${registered} push registration(s)`)\n }\n // Restore zero-touch push enrollment state (best effort).\n try {\n const raw = JSON.parse(await readFile(pushRelayPath, 'utf8')) as RelayEnrollmentCell\n if (typeof raw.clientId === 'string') enrollmentCell.clientId = raw.clientId\n if (typeof raw.enrollKey === 'string') enrollmentCell.enrollKey = raw.enrollKey\n if (typeof raw.token === 'string') enrollmentCell.token = raw.token\n if (raw.autoRelay === true) enrollmentCell.autoRelay = true\n } catch {\n // first boot: no enrollment yet\n }\n } catch (error) {\n const message = String(error)\n log('auth material unavailable, bridge degraded: ' + message)\n return { audience: null, devices: null }\n }\n return { audience: auth.audience, devices: auth.devices }\n })()\n\n const beginPairing = async (): Promise<{ code: string; expiresAt: number; audience: string }> => {\n await ready\n if (auth.audience === null || auth.devices === null) throw new Error('device authentication unavailable')\n return { ...pairingCodes.issue(), audience: auth.audience }\n }\n\n /**\n * Settings-page push self-test: force one synthetic notification down the\n * active pathway to EVERY registered device, deliberately ignoring the\n * connected-skip and category-mute filters — an explicit user action must\n * always be able to prove delivery end to end.\n */\n const runPushSelfTest = async (): Promise<PushTestResult> => {\n const resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok) {\n return {\n transport: 'none',\n overall: 'not-configured',\n message: '推送未启用(' + resolved.reason + ')。可先用「测试访问与注册」完成中继注册,或在配置中设置 push.provider',\n results: [],\n }\n }\n const tokenized = (auth.devices?.list() ?? []).filter((device) => device.apns !== undefined)\n if (!auth.devices || tokenized.length === 0) {\n return {\n transport: resolved.value.kind,\n overall: 'no-targets',\n message: '还没有设备注册离线推送——在手机上打开 DeepPilot 并允许系统通知,等状态变为「已就绪」后再试',\n results: [],\n }\n }\n const send = await senderFor(resolved.value)\n if (!send) {\n return { transport: resolved.value.kind, overall: 'failed', message: '发送通道不可用(检查 .p8 密钥文件或中继配置)', results: [] }\n }\n const notification: PushNotification = {\n notificationId: 'test-' + Date.now(),\n category: 'turn.completed',\n sessionId: 'push-test',\n title: 'DeepPilot 测试推送',\n body: '收到这条通知说明离线推送链路正常',\n }\n const results = await Promise.all(tokenized.map(async (device) => {\n const registration = device.apns!\n const { outcome, reason } = await send({\n deviceToken: registration.token,\n environment: registration.environment,\n notification,\n })\n return {\n name: device.deviceName,\n environment: registration.environment,\n outcome,\n // First 10 hex chars let the operator verify the stored token matches\n // what the device currently holds (tokens rotate on reinstall).\n tokenFingerprint: registration.token.slice(0, 10),\n ...(reason !== undefined ? { reason } : {}),\n }\n }))\n const overall: PushTestResult['overall'] = results.some((r) => r.outcome === 'sent') ? 'sent' : 'failed'\n log('push self-test: ' + overall + ' (' + results.map((r) => `\"${r.name}\"=${r.outcome}${r.reason ? '/' + r.reason : ''}`).join(', ') + ')')\n return { transport: resolved.value.kind, overall, results }\n }\n\n const connections = new Set<BridgeConnection>()\n\n const closeConnectionsForBridge = (bridge: HostBridge): void => {\n for (const connection of connections) {\n if (!connection.isAttachedTo(bridge)) continue\n connection.closeForServerStop()\n connections.delete(connection)\n }\n }\n\n const closeAllConnections = (): void => {\n for (const connection of connections) connection.closeForServerStop()\n connections.clear()\n }\n\n // ---------- offline push outlet (F-9) ----------\n\n type PushConfigSnapshot =\n | { kind: 'apns'; teamId: string; keyId: string; keyPath: string; bundleId: string }\n | { kind: 'relay'; url: string; token: string }\n\n const resolvePushConfig = (config: Config): { ok: true; value: PushConfigSnapshot } | { ok: false; reason: string } => {\n const push = config.push ?? {}\n // Auto-enabled by an enrolled distributed app when the user made no\n // explicit provider choice.\n const configured = push.provider ?? 'none'\n const effectiveProvider = configured === 'none' && enrollmentCell.autoRelay === true ? 'relay' : configured\n if (effectiveProvider === 'relay') {\n const url = (push.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n const token = (push.relayToken ?? '').trim() || enrollmentCell.token || ''\n if (!/^https:\\/\\//i.test(url)) return { ok: false, reason: 'relayUrl must be an https URL' }\n if (!token) return { ok: false, reason: 'relay token not enrolled yet' }\n return { ok: true, value: { kind: 'relay', url, token } }\n }\n if (effectiveProvider === 'apns') {\n const teamId = (push.teamId ?? '').trim()\n const keyId = (push.keyId ?? '').trim()\n const keyPath = expandHome((push.keyPath ?? '').trim() || join(dataDir, 'apns', 'AuthKey.p8'))\n const bundleId = (push.bundleId ?? '').trim()\n if (!teamId || !keyId || !bundleId) return { ok: false, reason: 'teamId/keyId/bundleId missing' }\n return { ok: true, value: { kind: 'apns', teamId, keyId, keyPath, bundleId } }\n }\n return { ok: false, reason: 'provider disabled' }\n }\n\n /**\n * Zero-touch enrollment against the operator's relay. Idempotent and\n * cached in the persistent cell; a failure disables push for this config\n * fingerprint with one log line until something changes.\n */\n let enrollAttemptFor: string | undefined\n let enrollLastAttemptAt = 0\n const ensureRelayEnrolled = async (url: string): Promise<string | undefined> => {\n // The enrollment body carries the distributor's shared key; a mis-typed\n // http:// relayUrl must never leak it in cleartext. (Send-path requests\n // are already gated by resolvePushConfig — enrollment call sites are not.)\n if (!/^https:\\/\\//i.test(url.trim())) {\n log('push relay enrollment refused: relayUrl must be an https URL')\n return undefined\n }\n if (enrollmentCell.token) return enrollmentCell.token\n const fingerprint = url + ':' + String(enrollmentCell.enrollKey ?? '')\n if (fingerprint !== enrollAttemptFor) {\n enrollAttemptFor = fingerprint\n enrollLastAttemptAt = 0\n }\n // Same fingerprint failing repeatedly: throttle to one attempt/minute so\n // a down relay cannot turn every notification into an outbound storm,\n // while transient failures still recover quickly.\n if (Date.now() - enrollLastAttemptAt < 60_000) return undefined\n enrollLastAttemptAt = Date.now()\n try {\n if (!enrollmentCell.clientId) {\n enrollmentCell.clientId = 'u_' + randomBytes(16).toString('base64url')\n persistEnrollment()\n }\n const client = new RelayClient({ url, debug: currentConfig().debug === true, log })\n const token = await client.enroll(enrollmentCell.clientId, enrollmentCell.enrollKey ?? '')\n if (!token) {\n log('push relay enrollment failed (' + url + '); will retry on next trigger')\n return undefined\n }\n enrollmentCell.token = token\n persistEnrollment()\n log('push relay enrollment succeeded')\n return token\n } catch (error) {\n log('push relay enrollment error: ' + String(error))\n return undefined\n }\n }\n\n interface SendOutcome { outcome: 'sent' | 'invalid-token' | 'failed'; reason?: string }\n type PushSender = (\n request: { deviceToken: string; environment: ApnsEnvironment; notification: Parameters<PushOutlet['fanOut']>[0] },\n ) => Promise<SendOutcome>\n\n interface CachedSender {\n fingerprint: string\n send: PushSender\n dispose?: () => Promise<void>\n }\n let cachedSender: CachedSender | undefined\n /**\n * Last failed APNs-sender build. The config fingerprint cannot see the\n * filesystem, so remembering a failure forever meant \"copy the .p8 into\n * place later\" never recovered without an edit or restart; throttle the\n * retry by time instead — same pattern as relay enrollment below.\n */\n let senderFailedFor: { fingerprint: string; at: number } | undefined\n const SENDER_FAILURE_RETRY_MS = 60_000\n\n /**\n * Lazily build the push sender for the current config. A broken config\n * (unreadable .p8) disables push for that fingerprint with exactly one log\n * line instead of failing on every event.\n */\n const senderFor = async (resolved: PushConfigSnapshot): Promise<PushSender | undefined> => {\n const fingerprint = JSON.stringify(resolved)\n if (cachedSender?.fingerprint === fingerprint) return cachedSender.send\n // A recent failure only blocks retries for a short window: a permanently\n // broken config must not log-storm on every event, but the same config\n // with the key file since added MUST get another chance.\n if (\n senderFailedFor?.fingerprint === fingerprint &&\n Date.now() - senderFailedFor.at < SENDER_FAILURE_RETRY_MS\n ) {\n return undefined\n }\n if (cachedSender) {\n await cachedSender.dispose?.().catch(() => {})\n cachedSender = undefined\n }\n if (resolved.kind === 'relay') {\n // resolvePushConfig already guarantees a token exists in the cell\n // (config token or a completed enrollment).\n const client = new RelayClient({ url: resolved.url, token: resolved.token, debug: currentConfig().debug === true, log })\n cachedSender = {\n fingerprint,\n send: (request) => client.send(request),\n }\n log('push relay enabled')\n } else {\n try {\n await readFile(expandHome(resolved.keyPath), 'utf8')\n } catch (error) {\n senderFailedFor = { fingerprint, at: Date.now() }\n log('apns push unavailable (key unreadable at ' + resolved.keyPath + '): ' + String(error))\n return undefined\n }\n const client = new ApnsClient({\n teamId: resolved.teamId,\n keyId: resolved.keyId,\n keyPath: resolved.keyPath,\n bundleId: resolved.bundleId,\n debug: currentConfig().debug === true,\n log,\n })\n cachedSender = {\n fingerprint,\n send: (request) => client.send({\n ...request.notification,\n deviceToken: request.deviceToken,\n environment: request.environment,\n }),\n dispose: () => client.dispose(),\n }\n log('apns push enabled')\n }\n senderFailedFor = undefined\n return cachedSender.send\n }\n\n /**\n * Fan one notification-worthy event out to paired devices holding an APNs\n * token. Rules:\n * - devices with a live WebSocket are skipped (they already got the WS\n * frame and will raise the local notification themselves);\n * - each device is delivered on ITS registered environment (the build\n * kind it self-reported), so sandbox and production devices coexist;\n * - the device's per-category switches suppress muted categories;\n * - only APNs' terminal Unregistered/ExpiredToken verdicts prune storage;\n * BadDeviceToken may be an environment mismatch and stays diagnosable.\n */\n const makePushOutlet = (): PushOutlet => ({\n // The capability bit must tell the truth: only advertise push when the\n // provider is fully configured, otherwise clients would suppress their\n // local banners expecting a delivery that never happens.\n isAvailable: () => {\n const resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok) return false\n // Relay mode is only truly ready once enrollment produced a token;\n // advertising earlier would make clients suppress their local banners\n // for deliveries that cannot happen yet.\n if (resolved.value.kind === 'relay' && !resolved.value.token) return false\n return true\n },\n fanOut: (notification) => {\n void (async () => {\n let resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok && resolved.reason === 'relay token not enrolled yet') {\n // A registration carried the enrollKey but enrollment has not run —\n // try once now, then re-resolve.\n const relayUrl = (currentConfig().push?.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n await ensureRelayEnrolled(relayUrl)\n resolved = resolvePushConfig(currentConfig())\n }\n if (!resolved.ok) return\n const devices = auth.devices\n if (!devices) return\n const send = await senderFor(resolved.value)\n if (!send) return\n const transport = resolved.value.kind\n const connectedIds = new Set<string>()\n for (const connection of connections) {\n const id = connection.connectedDeviceId\n if (id) connectedIds.add(id)\n }\n // Observability first: push failures used to be completely silent\n // (outcomes were debug-gated), which made field diagnosis impossible.\n // Every dispatch and every skip now leaves one flat log line —\n // categories and outcomes only, never message bodies.\n const candidates = devices.list().filter((device) => {\n const registration = device.apns\n if (!registration) return false\n if (connectedIds.has(device.deviceId)) return false\n if (registration.categories?.[notification.category] === false) {\n if (currentConfig().debug === true) {\n log(`push skip \"${device.deviceName}\": category ${notification.category} muted`)\n }\n return false\n }\n return true\n })\n if (candidates.length === 0) {\n const tokenized = devices.list().filter((device) => device.apns !== undefined).length\n log(`push(${transport}) ${notification.category}: no offline targets (connected=${connectedIds.size}, tokenized=${tokenized})`)\n return\n }\n // Relay self-heal inputs, resolved once per dispatch: the URL we are\n // actually sending through, and whether the credential came from the\n // zero-touch cell (explicit relayToken configs are never rewritten).\n const relayUrl = resolved.value.kind === 'relay' ? resolved.value.url : undefined\n const relayTokenUsed = resolved.value.kind === 'relay' ? resolved.value.token : undefined\n const usedCellToken = relayTokenUsed !== undefined && relayTokenUsed === enrollmentCell.token\n const hasEnrollKey = Boolean(enrollmentCell.enrollKey)\n for (const device of candidates) {\n const registration = device.apns!\n void send({ deviceToken: registration.token, environment: registration.environment, notification })\n .then(({ outcome, reason }) => {\n log(`push(${transport}) ${notification.category} → \"${device.deviceName}\" [${registration.environment}] = ${outcome}${reason ? ' (' + reason + ')' : ''}`)\n if (shouldPrunePushToken(outcome, reason)) {\n devices.clearPushToken(device.deviceId)\n log(`push: pruned stale token of \"${device.deviceName}\" (${reason ?? 'unknown'}) — app re-registers on next launch`)\n return\n }\n if (\n relayUrl !== undefined &&\n shouldReEnrollRelayToken(transport, outcome, reason, {\n usedCellToken,\n hasEnrollKey,\n // Compare-and-clear: a delayed 401 from another request sent\n // with the old credential must not erase a token that an\n // earlier callback has already refreshed.\n tokenStillCurrent: enrollmentCell.token === relayTokenUsed,\n })\n ) {\n // The relay no longer honors the cached credential. Drop it and\n // re-derive from the enroll key; ensureRelayEnrolled's own\n // throttle keeps parallel 401s from storming the endpoint, and\n // senderFor's config fingerprint rebuilds the client with the\n // fresh token on the next dispatch.\n enrollmentCell.token = undefined\n persistEnrollment()\n log('push relay credential rejected (HTTP 401); re-enrolling')\n void ensureRelayEnrolled(relayUrl)\n }\n })\n .catch(() => {})\n }\n })()\n },\n })\n\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_FRAME_BYTES })\n let remoteSupervisor: RemoteSupervisor | undefined\n let localState: DeepPilotReport['local'] = {\n phase: currentConfig().enabled === true && currentConfig().local?.enabled !== false ? 'starting' : 'disabled',\n port: normalizeLocalPort(currentConfig().local?.port),\n endpoints: [],\n updatedAt: Date.now(),\n }\n const localStatus = (addresses: readonly string[]): DeepPilotReport['local'] => ({\n ...localState,\n endpoints: localState.phase === 'online' ? localEndpointURLs(addresses, localState.port) : [],\n })\n const remoteStatus = (): RemoteStatus => remoteSupervisor?.status() ?? {\n provider: 'tailscale-funnel',\n phase: currentConfig().remote?.enabled === true ? 'stopped' : 'disabled',\n updatedAt: Date.now(),\n }\n\n // Self-update check: one process-wide instance. The initial schedule fires\n // a single background GitHub fetch shortly after boot. The result is\n // surfaced through the report snapshot; the UI shows nothing extra on\n // a quiet host, and one inline \"new version\" link when an update exists.\n const updateChecker = new UpdateChecker({ log, currentVersion: SERVER_VERSION })\n updateChecker.scheduleInitial()\n const updateInfo = (): UpdateInfo => updateChecker.get()\n\n // Typert Remote for the web settings page (deeppilot/report).\n applyReportRemote(ctx, async () => {\n let pairingReady = false\n let devices: Array<{\n deviceId: string; deviceName: string; appVersion: string; firstSeenTs: number; lastSeenTs: number\n fingerprint: string; scopes: ReturnType<typeof normalizeDeviceScopes>; revokedAt?: number\n apns?: { environment: 'development' | 'production'; updatedAt: number }\n }> = []\n try {\n await ready\n pairingReady = auth.audience !== null && auth.devices !== null\n // Strip the raw APNs token at the source; the report carries only the\n // registration fact (environment + freshness).\n devices = (auth.devices?.list() ?? [])\n .filter((device) => device.publicKey !== undefined && device.fingerprint !== undefined)\n .map(({ deviceId, deviceName, appVersion, firstSeenTs, lastSeenTs, fingerprint, scopes, revokedAt, apns }) => ({\n deviceId,\n deviceName,\n appVersion,\n firstSeenTs,\n lastSeenTs,\n fingerprint: fingerprint!,\n scopes: normalizeDeviceScopes(scopes),\n ...(revokedAt !== undefined ? { revokedAt } : {}),\n ...(apns ? { apns: { environment: apns.environment, updatedAt: apns.updatedAt } } : {}),\n }))\n } catch {\n // degraded: report the minimum without token facts\n }\n const update = updateInfo()\n const lanAddresses = localLANIPv4Addresses()\n return {\n protocolVersion: 2,\n serverVersion: SERVER_VERSION,\n pluginVersion: update.currentVersion,\n ...(update.available ? { updateAvailable: true } : {}),\n ...(update.releaseUrl !== null ? { releaseUrl: update.releaseUrl } : {}),\n enabled: currentConfig().enabled === true,\n identityPath: expandHome(currentConfig().devicesPath ?? join(bridgeDataDir(), 'devices-v2.json')),\n pairingReady,\n activeConnections: connections.size,\n historyBufferMax: currentConfig().historyBufferMax ?? 2000,\n debug: currentConfig().debug === true,\n lanAddresses,\n local: localStatus(lanAddresses),\n remote: remoteStatus(),\n devices,\n }\n }, beginPairing, async (deviceId) => {\n const { devices } = await ready\n if (!devices) throw new Error('device registry unavailable')\n const revoked = devices.revoke(deviceId, Date.now())\n if (revoked) {\n for (const connection of [...connections]) {\n if (connection.connectedDeviceId !== deviceId) continue\n connection.terminate()\n connections.delete(connection)\n }\n log(`device revoked id=${auditLabel(deviceId)}`)\n }\n return revoked\n }, async (deviceId, scopes) => {\n const { devices } = await ready\n if (!devices) throw new Error('device registry unavailable')\n const updated = devices.setScopes(deviceId, scopes)\n if (updated === null) throw new Error('active device not found')\n // Scope changes take effect on the next signed connection; disconnect the\n // current socket so stale in-memory authority cannot survive the update.\n for (const connection of [...connections]) {\n if (connection.connectedDeviceId !== deviceId) continue\n connection.terminate()\n connections.delete(connection)\n }\n log(`device scopes updated id=${auditLabel(deviceId)} scopes=${updated.join(',')}`)\n return updated\n }, async () => {\n const push = currentConfig().push ?? {}\n const configured = push.provider ?? 'none'\n const effective = configured === 'none' && enrollmentCell.autoRelay === true ? 'relay' : configured\n if (effective !== 'relay') {\n return {\n url: '',\n overall: 'failed' as const,\n tokenIssued: false,\n steps: [{ id: 'health' as const, ok: false, message: `当前推送模式不是中继(provider=${configured})。启用方式二选一:① 零配置——在 ios/project.yml 填写 DSPushEnrollKey(与服务器 RELAY_ENROLL_KEY 一致)并重新安装 App,打开 App 即自动启用;② 手动——将 push.provider 设为 relay 并填入 relayToken` }],\n }\n }\n const url = (push.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n if (!/^https:\\/\\//i.test(url)) {\n return {\n url,\n overall: 'failed' as const,\n tokenIssued: false,\n steps: [{ id: 'health' as const, ok: false, message: 'relayUrl 必须是 https 地址:注册请求携带共享密钥,明文 HTTP 会把它暴露给链路上的任何节点' }],\n }\n }\n // The enroll step needs an identity; mint one now so a successful test\n // doubles as a completed enrollment.\n if (!enrollmentCell.clientId && enrollmentCell.enrollKey) {\n enrollmentCell.clientId = 'u_' + randomBytes(16).toString('base64url')\n persistEnrollment()\n }\n return await runRelayProbe({\n url,\n clientId: enrollmentCell.clientId,\n enrollKey: enrollmentCell.enrollKey,\n manualToken: Boolean((push.relayToken ?? '').trim()),\n onEnrolled: (token) => {\n enrollmentCell.token = token\n persistEnrollment()\n log('push relay enrollment succeeded (via settings self-test)')\n },\n })\n }, async () => {\n return await runPushSelfTest()\n })\n const state: { bridge?: HostBridge } = {}\n let pendingUpgrades = 0\n const authRateLimiter = new AuthRateLimiter()\n\n const readJSONBody = async (req: IncomingMessage, maxBytes = 16 * 1024): Promise<unknown> => {\n const chunks: Buffer[] = []\n let size = 0\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n size += buffer.length\n if (size > maxBytes) throw new Error('request body too large')\n chunks.push(buffer)\n }\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as unknown\n }\n\n const handlePair = async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n res.setHeader('Content-Type', 'application/json')\n if (!enabledNow()) {\n res.statusCode = 503\n res.end(JSON.stringify({ ok: false, error: 'bridge disabled' }))\n return\n }\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.setHeader('Allow', 'POST')\n res.end(JSON.stringify({ ok: false, error: 'POST required' }))\n return\n }\n const source = requestClientIdentity(req)\n const admission = authRateLimiter.admit(source)\n if (!admission.ok) {\n res.statusCode = 429\n res.setHeader('Retry-After', String(Math.max(1, Math.ceil(admission.retryAfterMs / 1_000))))\n res.end(JSON.stringify({ ok: false, error: 'pairing rate limited' }))\n return\n }\n try {\n const { devices, audience } = await ready\n if (!devices || !audience) throw new Error('device authentication unavailable')\n const raw = await readJSONBody(req) as Record<string, unknown>\n if (raw === null || typeof raw !== 'object' || raw.v !== 2) throw new TypeError('protocol v2 required')\n const code = typeof raw.code === 'string' ? raw.code : ''\n const publicKey = typeof raw.publicKey === 'string' ? raw.publicKey : ''\n const deviceName = sanitizeDeviceField(raw.deviceName, MAX_DEVICE_NAME_CHARS) || 'unknown'\n const appVersion = sanitizeDeviceField(raw.appVersion, MAX_APP_VERSION_CHARS) || 'unknown'\n const deviceId = deviceIdForPublicKey(publicKey)\n if (devices.list().length >= MAX_DEVICES && devices.authorized(deviceId) === undefined) {\n res.statusCode = 409\n res.end(JSON.stringify({ ok: false, error: 'device registry is full' }))\n return\n }\n if (!pairingCodes.consume(code)) {\n const failure = authRateLimiter.recordFailure(source)\n res.statusCode = failure.blocked ? 429 : 401\n if (failure.retryAfterMs > 0) res.setHeader('Retry-After', String(Math.max(1, Math.ceil(failure.retryAfterMs / 1_000))))\n res.end(JSON.stringify({ ok: false, error: failure.blocked ? 'pairing rate limited' : 'pairing code invalid or expired' }))\n return\n }\n const record = devices.register({\n publicKey,\n deviceName,\n appVersion,\n scopes: normalizeDeviceScopes(raw.scopes),\n }, Date.now())\n authRateLimiter.recordSuccess(source)\n log(`device paired id=${auditLabel(record.deviceId)} source=${auditLabel(source)}`)\n res.statusCode = 201\n res.end(JSON.stringify({\n ok: true,\n v: 2,\n deviceId: record.deviceId,\n audience,\n scopes: record.scopes ?? [],\n }))\n } catch (error) {\n res.statusCode = error instanceof SyntaxError || error instanceof TypeError ? 400 : 503\n res.end(JSON.stringify({ ok: false, error: error instanceof Error ? error.message : 'pairing failed' }))\n } finally {\n admission.release()\n }\n }\n\n const handleUpgrade = (req: IncomingMessage, socket: Duplex, head: Buffer): void => {\n void (async () => {\n try {\n if (!enabledNow()) {\n rejectUpgrade(socket, 503, 'bridge disabled')\n return\n }\n if (connections.size + pendingUpgrades >= MAX_CLIENT_CONNECTIONS) {\n rejectUpgrade(socket, 429, 'too many connections')\n return\n }\n pendingUpgrades += 1\n try {\n const { devices, audience } = await ready\n if (!audience || !devices) {\n rejectUpgrade(socket, 503, 'bridge degraded')\n return\n }\n const source = requestClientIdentity(req)\n const admission = authRateLimiter.admit(source)\n if (!admission.ok) {\n rejectUpgrade(socket, 429, 'authentication rate limited', admission.retryAfterMs / 1_000)\n return\n }\n const bridge = state.bridge\n if (!bridge) {\n admission.release()\n rejectUpgrade(socket, 503, 'bridge not ready')\n return\n }\n try {\n wss.handleUpgrade(req, socket, head, (ws) => {\n if (auth.audience !== audience || state.bridge !== bridge) {\n admission.release()\n ws.close(1012, 'bridge changed')\n return\n }\n try {\n const connection = new BridgeConnection(ws, {\n bridge,\n devices,\n serverVersion: SERVER_VERSION,\n audience,\n log,\n debug: currentConfig().debug === true,\n onClosed: (closed) => connections.delete(closed),\n onAuthenticationSettled: (ok) => {\n admission.release()\n if (ok) {\n authRateLimiter.recordSuccess(source)\n } else {\n const failure = authRateLimiter.recordFailure(source)\n if (failure.newlyBlocked) log(`authentication source blocked source=${auditLabel(source)}`)\n }\n },\n onDeviceAuthenticated: (deviceId) => {\n log(`device authenticated id=${auditLabel(deviceId)} source=${auditLabel(source)}`)\n },\n onPushEnrollKey: handlePushEnrollKey,\n })\n connections.add(connection)\n } catch (error) {\n admission.release()\n ws.close(1011, 'connection setup failed')\n throw error\n }\n })\n } catch (error) {\n admission.release()\n throw error\n }\n } finally {\n pendingUpgrades -= 1\n }\n } catch (error) {\n log('upgrade failed: ' + String(error))\n rejectUpgrade(socket, 500, 'internal error')\n }\n })()\n }\n\n const handleHealth = async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n await ready\n res.setHeader('Content-Type', 'application/json')\n if (!auth.audience || !auth.devices) {\n res.statusCode = 503\n res.end(JSON.stringify({ ok: false, degraded: true }))\n return\n }\n res.statusCode = 200\n res.end(JSON.stringify({\n ok: true,\n enabled: enabledNow(),\n protocolVersion: 2,\n serverVersion: SERVER_VERSION,\n dataPlane: Boolean(state.bridge),\n }))\n } catch {\n res.statusCode = 500\n res.end(JSON.stringify({ ok: false }))\n }\n }\n\n const phoneHandlers = {\n health: handleHealth,\n pair: handlePair,\n upgrade: handleUpgrade,\n }\n\n // Independent transport listeners. LAN owns a stable configurable port;\n // Funnel keeps its loopback-only ephemeral origin. They share only the\n // narrow handlers above, so a LAN bind failure cannot take remote access\n // down and neither listener exposes DSH's wider web/API surface.\n let localServer: ReturnType<typeof createPhoneServer> | undefined\n let appliedLocalKey: string | undefined\n let localDisposed = false\n let localTail = Promise.resolve()\n const reconcileLocal = async (): Promise<void> => {\n if (localDisposed) return\n const config = currentConfig()\n const localConfig = config.local ?? {}\n const next = {\n enabled: config.enabled === true && localConfig.enabled !== false,\n port: normalizeLocalPort(localConfig.port),\n }\n const nextKey = JSON.stringify(next)\n if (nextKey === appliedLocalKey) return\n appliedLocalKey = nextKey\n\n const previous = localServer\n localServer = undefined\n await closeServer(previous)\n if (localDisposed) return\n if (!next.enabled) {\n localState = { phase: 'disabled', port: next.port, endpoints: [], updatedAt: Date.now() }\n log('local transport disabled')\n return\n }\n\n localState = { phase: 'starting', port: next.port, endpoints: [], updatedAt: Date.now() }\n const server = createPhoneServer(phoneHandlers)\n localServer = server\n try {\n await listen(server, next.port, '0.0.0.0')\n if (localDisposed || localServer !== server) {\n await closeServer(server)\n return\n }\n localState = { phase: 'online', port: next.port, endpoints: [], updatedAt: Date.now() }\n log(`local transport listening on 0.0.0.0:${next.port}`)\n } catch (error) {\n if (localServer === server) localServer = undefined\n await closeServer(server)\n const message = localListenError(error, next.port)\n localState = { phase: 'error', port: next.port, endpoints: [], message, updatedAt: Date.now() }\n log('local transport failed: ' + message)\n }\n }\n scheduleLocalReconcile = () => {\n localTail = localTail\n .then(reconcileLocal)\n .catch((error) => log('local reconcile failed: ' + String(error)))\n }\n\n const originServer = createPhoneServer(phoneHandlers)\n let originURL: string | undefined\n let appliedRemoteKey: string | undefined\n let remoteDisposed = false\n let remoteTail = Promise.resolve()\n const reconcileRemote = async (): Promise<void> => {\n if (remoteDisposed || originURL === undefined) return\n const config = currentConfig()\n const remoteConfig = config.remote ?? {}\n const remotePort: 443 | 8443 | 10000 = remoteConfig.funnelPort === 8443 || remoteConfig.funnelPort === 10000\n ? remoteConfig.funnelPort\n : 443\n const helperPath = remoteConfig.helperPath?.trim() || undefined\n const next = {\n enabled: config.enabled === true && remoteConfig.enabled === true && remoteConfig.provider === 'tailscale-funnel',\n hostname: normalizeRemoteHostname(remoteConfig.hostname),\n statePath: remoteConfig.statePath?.trim() || join(dataDir, 'tailscale'),\n helperPath,\n funnelPort: remotePort,\n maxConnectionsPerSource: normalizeFunnelConnectionLimit(remoteConfig.maxConnectionsPerSource),\n }\n const nextKey = JSON.stringify(next)\n if (nextKey === appliedRemoteKey) return\n\n const previous = remoteSupervisor\n remoteSupervisor = undefined\n if (previous !== undefined) await previous.dispose()\n if (remoteDisposed) return\n\n const supervisor = new RemoteSupervisor({\n enabled: next.enabled,\n hostname: next.hostname,\n statePath: next.statePath,\n ...(next.helperPath ? { helperPath: next.helperPath } : {}),\n funnelPort: next.funnelPort,\n maxConnectionsPerSource: next.maxConnectionsPerSource,\n log,\n })\n remoteSupervisor = supervisor\n appliedRemoteKey = nextKey\n await supervisor.start(originURL)\n }\n scheduleRemoteReconcile = () => {\n remoteTail = remoteTail\n .then(reconcileRemote)\n .catch((error) => log('remote reconcile failed: ' + String(error)))\n }\n\n ;(ctx as unknown as SubContext).effect(() => {\n scheduleLocalReconcile?.()\n void listen(originServer, 0, '127.0.0.1').then(() => {\n const address = originServer.address()\n if (address && typeof address === 'object') {\n originURL = `http://127.0.0.1:${address.port}`\n scheduleRemoteReconcile?.()\n }\n }, (error: unknown) => log('remote origin failed: ' + String(error)))\n return async () => {\n localDisposed = true\n remoteDisposed = true\n scheduleLocalReconcile = undefined\n scheduleRemoteReconcile = undefined\n const activeLocal = localServer\n localServer = undefined\n await Promise.allSettled([closeServer(activeLocal), closeServer(originServer)])\n localState = { phase: 'stopped', port: localState.port, endpoints: [], updatedAt: Date.now() }\n await Promise.allSettled([\n localTail,\n remoteTail.then(async () => {\n const supervisor = remoteSupervisor\n remoteSupervisor = undefined\n if (supervisor !== undefined) await supervisor.dispose()\n }),\n ])\n }\n }, 'deeppilot: independent transports')\n\n const sweep = setInterval(() => {\n const now = Date.now()\n for (const connection of connections) {\n if (connection.isStale(now, 60_000)) {\n log('dropping stale connection')\n connection.closeIdle()\n connections.delete(connection)\n }\n }\n }, 30_000)\n ;(ctx as unknown as SubContext).effect(() => () => clearInterval(sweep), 'deeppilot: stale sweep')\n\n // Data plane: dsh 0.1.2 removed apiProxy. Build the bridge's stable\n // protocol-facing façade from the public Session/Workspace controllers.\n\n /**\n * Whether the resident Gateway Client represents a real phone surface. A\n * paired device remains answerable even while offline: HostBridge retains an\n * authoritative pending snapshot that the app pulls on reconnect, while\n * APNs is only a best-effort wakeup. With no paired device this Client calls\n * `next()`; Gateway's independent official Web delivery is unaffected.\n */\n const hasPairedPhoneSurface = (_kind: DshInteractionKind): boolean => {\n const devices = auth.devices?.list() ?? []\n return devices.some((device) => device.revokedAt === undefined)\n }\n\n ;(ctx as unknown as { inject: (deps: string[], fn: (sub: unknown) => void) => void }).inject(\n ['sessionController', 'connection', 'typertGateway'],\n (sub) => {\n if (currentConfig().enabled !== true) {\n log('bridge disabled; data plane stays inactive')\n return\n }\n const apiCtx = sub as unknown as Context & SubContext\n let proxy: Dsh012ApiProxy\n try {\n proxy = new Dsh012ApiProxy(apiCtx, { shouldSurfaceInteraction: hasPairedPhoneSurface })\n } catch (error) {\n log('dsh 0.1.2 session bridge unavailable: ' + String(error))\n return\n }\n const bridge = new HostBridge(proxy, cfg.historyBufferMax)\n bridge.setPushOutlet(makePushOutlet())\n state.bridge = bridge\n bridge.start()\n log('data plane active (mux + host streams)')\n apiCtx.effect(() => () => {\n closeConnectionsForBridge(bridge)\n if (state.bridge === bridge) state.bridge = undefined\n bridge.dispose()\n }, 'deeppilot: host streams')\n },\n )\n\n // Temporary 3080 compatibility plane. New clients use the independent LAN\n // listener above; these DSH routes remain for one migration cycle.\n ;(ctx as unknown as { inject: (deps: string[], fn: (sub: unknown) => void) => void }).inject(\n ['webServer'],\n (sub) => {\n const webCtx = sub as unknown as { webServer?: WebServerLike } & SubContext\n const web = webCtx.webServer\n if (!web) {\n log('webServer service absent; 3080 compatibility routes unavailable (independent transports remain active)')\n return\n }\n // Routes are registered regardless of the master switch so a mid-session\n // toggle always stays serviceable; every handler refuses work when the\n // bridge is currently disabled (evaluated per request so it is robust to\n // the settings scope attaching before or after webServer).\n webCtx.effect(\n () =>\n web.registerUpgrade({\n path: '/phone',\n handler: handleUpgrade,\n }),\n 'deeppilot: /phone WebSocket',\n )\n\n webCtx.effect(\n () =>\n web.register({\n kind: 'exact',\n path: '/phone/health',\n handler: handleHealth,\n }),\n 'deeppilot: /phone/health',\n )\n\n webCtx.effect(\n () =>\n web.register({\n kind: 'exact',\n path: '/phone/pair',\n handler: handlePair,\n }),\n 'deeppilot: /phone/pair',\n )\n\n if (enabledNow()) {\n log('/phone compatibility routes registered on DSH web server')\n } else {\n log('bridge disabled; /phone refuses connections until re-enabled')\n }\n },\n )\n\n ;(ctx as unknown as SubContext).effect(() => async () => {\n closeAllConnections()\n const bridge = state.bridge\n state.bridge = undefined\n bridge?.dispose()\n const sender = cachedSender\n cachedSender = undefined\n updateChecker.dispose()\n const wssClosed = new Promise<void>((resolve) => wss.close(() => resolve()))\n await Promise.allSettled([\n enrollmentWriteTail,\n sender?.dispose?.() ?? Promise.resolve(),\n wssClosed,\n ])\n }, 'deeppilot: process resources')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["record","cryptoSign","alert","http2Connect","fsConstants","httpsRequest"],"sources":["../src/prompt-delivery.ts","../src/request-validation.ts","../src/device-auth.ts","../src/token.ts","../src/connection-policy.ts","../src/connection.ts","../src/host-api.ts","../src/document-payload.ts","../src/host-event-projection.ts","../src/host-bridge.ts","../src/dsh012-remote-interactions.ts","../src/dsh012-api-proxy.ts","../src/report-service.ts","../src/report-wire.ts","../src/report-remote.ts","../src/relay-url.ts","../src/relay-test.ts","../src/apns.ts","../src/relay-client.ts","../src/funnel-policy.ts","../src/remote-supervisor.ts","../src/local-address.ts","../src/update-check.ts","../src/local-policy.ts","../src/config.ts","../src/phone-http.ts","../src/auth-rate-limit.ts","../src/push-policy.ts","../src/widget-push.ts","../src/live-activity.ts","../src/phone-server.ts","../src/index.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto'\nimport { existsSync, readFileSync, mkdirSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, statSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\nexport type DeliveryStatus = 'accepted' | 'rejected' | 'unknown' | 'notFound' | 'expired'\nexport interface DeliveryReceipt { clientSendId: string; status: DeliveryStatus; userSeq?: number; code?: string }\ninterface Entry { fingerprint: string; sessionId: string; createdAt: number; receipt: DeliveryReceipt }\nexport const DELIVERY_RETENTION_MS = 7 * 24 * 3600 * 1000\nexport function validSendId(id: unknown): id is string {\n return typeof id === 'string' && /^\\d{13}-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)\n}\n\n/** Durable at-most-once dispatch. Unknown outcomes are never automatically retried. */\nexport class PromptDeliveryJournal {\n private entries: Record<string, Entry> = Object.create(null)\n private inFlight = new Map<string, Promise<DeliveryReceipt>>()\n private healthy = true\n constructor(private readonly path?: string, private readonly capacity = 10000) {\n if (!path || !existsSync(path)) return\n try {\n if (statSync(path).size > 8 * 1024 * 1024) throw new Error('oversized journal')\n const parsed = JSON.parse(readFileSync(path, 'utf8'))\n if (parsed.version !== 1 || !Array.isArray(parsed.entries) || parsed.entries.length > capacity) throw new Error('invalid journal')\n for (const [key, value] of parsed.entries) {\n if (typeof key !== 'string' || !/^[a-f0-9]{64}$/.test(key) || !value || typeof value.sessionId !== 'string' || !Number.isFinite(value.createdAt) || typeof value.fingerprint !== 'string' || !validSendId(value.receipt?.clientSendId) || !['accepted', 'rejected', 'unknown'].includes(value.receipt.status)) throw new Error('invalid entry')\n if (!/^[a-f0-9]{64}$/.test(value.fingerprint) || value.createdAt !== Number(value.receipt.clientSendId.slice(0, 13)) || (value.receipt.status === 'accepted' && !Number.isSafeInteger(value.receipt.userSeq)) || (value.receipt.status === 'rejected' && !['E_BUSY', 'E_NOT_FOUND', 'E_PROTOCOL', 'E_UNSUPPORTED'].includes(value.receipt.code))) throw new Error('invalid receipt')\n this.entries[key] = value\n }\n } catch { this.healthy = false }\n }\n private key(deviceId: string, id: string) { return createHash('sha256').update(JSON.stringify([deviceId, id])).digest('hex') }\n private expired(id: string, now = Date.now()) { const age = now - Number(id.slice(0, 13)); return age > DELIVERY_RETENTION_MS || age < -5 * 60 * 1000 }\n private save() {\n if (!this.path) return\n mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 })\n const temp = this.path + '.' + randomUUID() + '.tmp'\n const fd = openSync(temp, 'wx', 0o600)\n try { writeFileSync(fd, JSON.stringify({ version: 1, entries: Object.entries(this.entries) })); fsyncSync(fd) } finally { closeSync(fd) }\n renameSync(temp, this.path)\n const dir = openSync(dirname(this.path), 'r')\n try { fsyncSync(dir) } finally { closeSync(dir) }\n }\n lookup(deviceId: string, sessionId: string, id: string): DeliveryReceipt {\n if (!this.healthy) return { clientSendId: id, status: 'unknown' }\n const entry = this.entries[this.key(deviceId, id)]\n if (entry && entry.sessionId === sessionId) return entry.receipt\n return { clientSendId: id, status: this.expired(id) ? 'expired' : 'notFound' }\n }\n async dispatch(deviceId: string, sessionId: string, id: string, content: unknown, operation: () => Promise<{ ok: true; value: number } | { ok: false; kind: string }>): Promise<DeliveryReceipt> {\n const key = this.key(deviceId, id)\n const fingerprint = createHash('sha256').update(JSON.stringify([sessionId, content])).digest('hex')\n const existing = this.entries[key]\n if (existing) {\n if (existing.fingerprint !== fingerprint) return { clientSendId: id, status: 'rejected', code: 'E_PROTOCOL' }\n return this.inFlight.get(key) ?? existing.receipt\n }\n if (!this.healthy) return { clientSendId: id, status: 'unknown' }\n if (this.expired(id)) return { clientSendId: id, status: 'expired' }\n for (const [key, value] of Object.entries(this.entries)) {\n if (Date.now() - value.createdAt > DELIVERY_RETENTION_MS + 5 * 60 * 1000 && !this.inFlight.has(key)) delete this.entries[key]\n }\n if (Object.keys(this.entries).length >= this.capacity) return { clientSendId: id, status: 'rejected', code: 'E_BUSY' }\n const entry: Entry = { fingerprint, sessionId, createdAt: Number(id.slice(0, 13)), receipt: { clientSendId: id, status: 'unknown' } }\n this.entries[key] = entry\n try { this.save() } catch { this.healthy = false; return entry.receipt }\n const run = (async () => {\n try {\n const result = await operation()\n if (result.ok) entry.receipt = { clientSendId: id, status: 'accepted', userSeq: result.value }\n else if (['busy', 'not-found', 'invalid', 'unsupported'].includes(result.kind)) {\n const code = { busy: 'E_BUSY', 'not-found': 'E_NOT_FOUND', invalid: 'E_PROTOCOL', unsupported: 'E_UNSUPPORTED' }[result.kind]!\n entry.receipt = { clientSendId: id, status: 'rejected', code }\n }\n } catch { /* Upstream may have accepted before transport failed. */ }\n try { this.save() } catch { this.healthy = false }\n return entry.receipt\n })()\n this.inFlight.set(key, run)\n try { return await run } finally { this.inFlight.delete(key) }\n }\n}\n\nconst journals = new Map<string, PromptDeliveryJournal>()\nexport function openDeliveryJournal(path?: string): PromptDeliveryJournal {\n if (!path) return new PromptDeliveryJournal()\n let journal = journals.get(path)\n if (!journal) { journal = new PromptDeliveryJournal(path); journals.set(path, journal) }\n return journal\n}\n","import { validSendId } from './prompt-delivery.ts'\n/** Shape and resource limits for authenticated client requests. Unknown fields\n * remain accepted for additive protocol-v2 compatibility. Business validation\n * (supported models, pending choices, permissions) stays with its owner. */\nexport function validateRequest(type: string, value: unknown): string | undefined {\n const empty = new Set(['c2s.ping', 'c2s.sessions.list', 'c2s.pending.list', 'c2s.workspaces.list', 'c2s.directory.pick'])\n if (value === undefined && (type === 'c2s.session.create' || type === 'c2s.directory.list')) value = {}\n if (value == null && empty.has(type)) return\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return 'payload must be an object'\n const p = value as Record<string, unknown>\n const text = (v: unknown, max = 4096, nonempty = true) => typeof v === 'string' && v.length <= max && (!nonempty || v.trim().length > 0)\n const optional = (key: string, check: (v: unknown) => boolean) => p[key] === undefined || check(p[key])\n const integer = (v: unknown, min: number, max: number) => typeof v === 'number' && Number.isSafeInteger(v) && v >= min && v <= max\n if (type.startsWith('c2s.session.') && type !== 'c2s.session.create' && !text(p.sessionId)) return 'invalid sessionId'\n if (type === 'c2s.session.create' && (!optional('workspaceId', v => text(v)) || !optional('cwd', v => text(v, 32768)) || (p.workspaceId !== undefined && p.cwd !== undefined))) return 'invalid workspace selection'\n if (type === 'c2s.directory.list' && !optional('path', v => text(v, 32768, false))) return 'invalid path'\n if (type === 'c2s.workspace.create' && !text(p.path, 32768)) return 'invalid path'\n if (type === 'c2s.session.open' && !optional('tailCount', v => integer(v, 1, 10000))) return 'invalid tailCount'\n if (type === 'c2s.session.history' && (!integer(p.beforeSeq, 0, Number.MAX_SAFE_INTEGER) || !optional('limit', v => integer(v, 1, 500)))) return 'invalid history range'\n if (type === 'c2s.session.rename' && !text(p.title, 4096)) return 'invalid title'\n if (type === 'c2s.session.attachment' && !text(p.attachmentId)) return 'invalid attachmentId'\n if (type === 'c2s.session.selectModel' && (!text(p.provider, 256) || !text(p.model, 1024) || !optional('reasoningEffort', v => text(v, 128, false)))) return 'invalid model selection'\n if (type === 'c2s.session.delivery' && !validSendId(p.clientSendId)) return 'invalid clientSendId'\n if (type === 'c2s.session.sendPrompt') {\n if (p.clientSendId !== undefined && !validSendId(p.clientSendId)) return 'invalid clientSendId'\n if (!optional('text', v => text(v, 256 * 1024, false)) || !optional('images', Array.isArray) || !optional('documents', Array.isArray)) return 'invalid prompt fields'\n for (const key of ['images', 'documents']) {\n const items = p[key] as unknown[] | undefined\n if (items && items.some(v => v === null || typeof v !== 'object' || Array.isArray(v))) return 'invalid attachment'\n for (const item of (items ?? []) as Record<string, unknown>[]) {\n if (item.name !== undefined && !text(item.name, 4096, false)) return 'invalid attachment name'\n if (item.truncated !== undefined && typeof item.truncated !== 'boolean') return 'invalid truncated flag'\n }\n }\n }\n if (type === 'c2s.approval.respond' || type === 'c2s.question.respond') {\n if (!text(p.requestId)) return 'invalid requestId'\n }\n if (type === 'c2s.approval.respond' && (!['allow', 'deny'].includes(p.decision as string) || !optional('reason', v => text(v, 65536, false)))) return 'invalid approval response'\n if (type === 'c2s.question.respond') {\n if (!Array.isArray(p.answers) || p.answers.length > 100) return 'invalid answers'\n const ids = new Set<string>()\n for (const answer of p.answers) {\n if (!answer || typeof answer !== 'object' || Array.isArray(answer) || !text(answer.id) || ids.has(answer.id) || !Array.isArray(answer.selected) || answer.selected.length > 100 || !answer.selected.every((v: unknown) => text(v, 4096)) || (answer.custom !== undefined && !text(answer.custom, 65536))) return 'invalid answer'\n ids.add(answer.id)\n }\n }\n if (type === 'c2s.liveActivity.register' || type === 'c2s.liveActivity.unregister') {\n if (!text(p.activityId, 128)) return 'invalid activityId'\n if (type === 'c2s.liveActivity.register' &&\n (!text(p.sessionId) || typeof p.deviceToken !== 'string' || !/^[0-9a-fA-F]{32,512}$/.test(p.deviceToken) ||\n !['development', 'production'].includes(p.environment as string) || !optional('enrollKey', v => text(v, 128)))) return 'invalid live activity registration'\n }\n if (type === 'c2s.push.register' || type === 'c2s.widget.push.register') {\n if (p.environment !== undefined && p.environment !== 'production' && p.environment !== 'development') return 'invalid APNs environment'\n if (!optional('enrollKey', v => text(v, 128))) return 'invalid enrollKey'\n if (p.categories !== undefined && (!p.categories || typeof p.categories !== 'object' || Array.isArray(p.categories) || Object.values(p.categories).some(v => typeof v !== 'boolean'))) return 'invalid categories'\n }\n}\n","import {\n createHash,\n createPublicKey,\n randomBytes,\n timingSafeEqual,\n verify,\n type KeyObject,\n} from 'node:crypto'\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\nexport function getPairingCodeTtlMs(): number {\n return Number(process.env.DEEPPILOT_PAIRING_TTL_MS) || 5 * 60_000\n}\nexport const AUTH_CHALLENGE_TTL_MS = 30_000\n\nexport const DEVICE_SCOPES = [\n 'sessions.read',\n 'prompt.send',\n 'sessions.manage',\n 'interactions.respond',\n 'notifications.register',\n] as const\n\nexport type DeviceScope = (typeof DEVICE_SCOPES)[number]\n\nexport const DEFAULT_DEVICE_SCOPES: readonly DeviceScope[] = DEVICE_SCOPES\n\nexport interface PairingGrant {\n code: string\n expiresAt: number\n audience?: string\n}\n\nexport async function loadOrCreateHostAudience(path: string): Promise<string> {\n try {\n const existing = (await readFile(path, 'utf8')).trim()\n if (/^deeppilot:[A-Za-z0-9_-]{22}$/.test(existing)) return existing\n throw new Error(`host audience is malformed at ${path}`)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n const audience = 'deeppilot:' + randomBytes(16).toString('base64url')\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, audience + '\\n', { mode: 0o600 })\n return audience\n}\n\nexport interface AuthChallenge {\n nonce: string\n audience: string\n issuedAt: number\n expiresAt: number\n}\n\nexport interface AuthProofFields extends AuthChallenge {\n deviceId: string\n deviceName: string\n appVersion: string\n resumeCursor?: number\n}\n\nfunction b64urlText(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64url')\n}\n\n/**\n * Cross-language signature input. Text fields are base64url encoded before\n * joining so names cannot create ambiguous separators. Decimal timestamps\n * and cursor values are finite integers, or `-` when the cursor is absent.\n */\nexport function canonicalAuthChallenge(fields: AuthProofFields): Buffer {\n const cursor = fields.resumeCursor === undefined ? '-' : String(fields.resumeCursor)\n return Buffer.from([\n 'deeppilot-auth-v2',\n `device-id:${b64urlText(fields.deviceId)}`,\n `nonce:${fields.nonce}`,\n `audience:${b64urlText(fields.audience)}`,\n `issued-at:${fields.issuedAt}`,\n `expires-at:${fields.expiresAt}`,\n `device-name:${b64urlText(fields.deviceName)}`,\n `app-version:${b64urlText(fields.appVersion)}`,\n `resume-cursor:${cursor}`,\n ].join('\\n'), 'utf8')\n}\n\n/** Accept only an uncompressed ANSI X9.63 P-256 public key (65 bytes). */\nexport function parseP256PublicKey(encoded: string): { key: KeyObject; raw: Buffer } {\n const raw = Buffer.from(encoded, 'base64url')\n if (raw.length !== 65 || raw[0] !== 0x04) {\n throw new TypeError('publicKey must be an uncompressed P-256 X9.63 key')\n }\n // SubjectPublicKeyInfo prefix for id-ecPublicKey / prime256v1 followed by\n // the 65-byte uncompressed point.\n const spkiPrefix = Buffer.from('3059301306072a8648ce3d020106082a8648ce3d030107034200', 'hex')\n const key = createPublicKey({ key: Buffer.concat([spkiPrefix, raw]), format: 'der', type: 'spki' })\n if (key.asymmetricKeyType !== 'ec' || key.asymmetricKeyDetails?.namedCurve !== 'prime256v1') {\n throw new TypeError('publicKey must use P-256')\n }\n return { key, raw }\n}\n\nexport function deviceIdForPublicKey(publicKey: string): string {\n const { raw } = parseP256PublicKey(publicKey)\n return createHash('sha256').update(raw).digest('base64url')\n}\n\nexport function fingerprintForPublicKey(publicKey: string): string {\n const { raw } = parseP256PublicKey(publicKey)\n return createHash('sha256').update(raw).digest('hex')\n}\n\nexport function verifyAuthProof(publicKey: string, fields: AuthProofFields, signature: string): boolean {\n try {\n const { key } = parseP256PublicKey(publicKey)\n const der = Buffer.from(signature, 'base64url')\n if (der.length < 64 || der.length > 80) return false\n return verify('sha256', canonicalAuthChallenge(fields), key, der)\n } catch {\n return false\n }\n}\n\nexport function normalizeDeviceScopes(value: unknown): DeviceScope[] {\n if (!Array.isArray(value)) return [...DEFAULT_DEVICE_SCOPES]\n const allowed = new Set<string>(DEVICE_SCOPES)\n return [...new Set(value.filter((scope): scope is DeviceScope => typeof scope === 'string' && allowed.has(scope)))]\n}\n\n/** One active, single-use pairing grant per plugin runtime. */\nexport class PairingCodeManager {\n private active: PairingGrant | null = null\n\n issue(now = Date.now()): PairingGrant {\n const grant = {\n code: randomBytes(24).toString('base64url'),\n expiresAt: now + getPairingCodeTtlMs(),\n }\n this.active = grant\n return { ...grant }\n }\n\n consume(presented: string, now = Date.now()): boolean {\n const active = this.active\n if (active === null || now > active.expiresAt) {\n this.active = null\n return false\n }\n const expected = Buffer.from(active.code)\n const actual = Buffer.from(presented)\n const matches = expected.length === actual.length && timingSafeEqual(expected, actual)\n if (matches) this.active = null\n return matches\n }\n\n invalidate(): void {\n this.active = null\n }\n}\n\nexport function createAuthChallenge(audience: string, now = Date.now()): AuthChallenge {\n return {\n nonce: randomBytes(24).toString('base64url'),\n audience,\n issuedAt: now,\n expiresAt: now + AUTH_CHALLENGE_TTL_MS,\n }\n}\n","import type { LiveActivityState } from './protocol.ts'\nimport { randomBytes } from 'node:crypto'\nimport { access, chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, resolve } from 'node:path'\nimport {\n deviceIdForPublicKey,\n fingerprintForPublicKey,\n normalizeDeviceScopes,\n type DeviceScope,\n} from './device-auth.ts'\n\n/** Expand a leading ~ using the process home directory. */\nexport function expandHome(p: string): string {\n if (p === '~') return homedir()\n if (p.startsWith('~/')) return resolve(homedir(), p.slice(2))\n return p\n}\n\nfunction dshDataRoot(): string {\n const dshHome = process.env.DSH_HOME\n if (dshHome && dshHome.trim().length > 0) return resolve(dshHome.trim())\n return resolve(homedir(), '.dsh')\n}\n\n/** DeepPilot data directory: under $DSH_HOME when set, else ~/.dsh. */\nexport function bridgeDataDir(): string {\n return resolve(dshDataRoot(), 'deeppilot')\n}\n\n/** Create or repair the canonical secret-bearing directory as owner-only. */\nexport async function ensurePrivateBridgeDataDir(): Promise<string> {\n const target = bridgeDataDir()\n await mkdir(target, { recursive: true, mode: 0o700 })\n await chmod(target, 0o700)\n return target\n}\n\n/**\n * Move the pre-DeepPilot data directory as one atomic directory rename.\n * Existing canonical data always wins; secrets are never merged or replaced.\n */\nexport async function migrateLegacyBridgeDataDir(): Promise<string | null> {\n const target = bridgeDataDir()\n try {\n await access(target)\n return null\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n\n const legacy = resolve(dshDataRoot(), 'pocket-bridge')\n try {\n await rename(legacy, target)\n return legacy\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null\n throw error\n }\n}\n\nexport type ApnsEnvironment = 'development' | 'production'\n\n/** Per-device APNs registration (F-9 离线推送). The raw token never leaves the registry file. */\nexport interface DeviceApnsInfo {\n /** Hex device token, lowercased, 32–512 chars. */\n token: string\n environment: ApnsEnvironment\n updatedAt: number\n /** Per-category opt-out mirror; absent keys mean enabled. */\n categories?: Record<string, boolean>\n}\n\nexport interface LiveActivityRegistration extends DeviceApnsInfo {\n activityId: string\n sessionId: string\n expiresAt: number\n endedState?: LiveActivityState\n}\n\nexport interface DeviceRecord {\n deviceId: string\n deviceName: string\n appVersion: string\n /** Uncompressed P-256 X9.63 public key, base64url encoded. */\n publicKey?: string\n /** SHA-256 fingerprint of publicKey, hex encoded for local display. */\n fingerprint?: string\n scopes?: DeviceScope[]\n revokedAt?: number\n firstSeenTs: number\n lastSeenTs: number\n apns?: DeviceApnsInfo\n widgetApns?: DeviceApnsInfo\n liveActivity?: LiveActivityRegistration\n}\n\n/** Hex shape of an APNs device token as delivered by iOS (usually 64 chars). */\nconst APNS_TOKEN_PATTERN = /^[0-9a-f]{32,512}$/\n\nexport function isValidApnsToken(token: unknown): token is string {\n return typeof token === 'string' && APNS_TOKEN_PATTERN.test(token)\n}\n\n/** Registry row cap: hello spam with fresh ids must not grow the file forever. */\nexport const MAX_DEVICES = 64\n\n/**\n * Paired-device registry persisted as one JSON document. Whole-document\n * writes (serialized, never interleaved); a corrupt file falls back to an\n * empty registry rather than failing the plugin.\n */\nexport class DeviceStore {\n private devices = new Map<string, DeviceRecord>()\n private flushTail: Promise<void> = Promise.resolve()\n\n private constructor(private readonly filePath: string) {}\n\n static async load(filePath: string): Promise<DeviceStore> {\n const store = new DeviceStore(filePath)\n try {\n const raw = JSON.parse(await readFile(expandHome(filePath), 'utf8')) as {\n devices?: DeviceRecord[]\n }\n for (const rec of raw.devices ?? []) {\n if (typeof rec.deviceId === 'string') store.devices.set(rec.deviceId, rec)\n }\n } catch (error) {\n const code = (error as NodeJS.ErrnoException)?.code\n if (code === 'ENOENT') {\n // First run on this home: nothing registered yet — normal.\n } else {\n // A truncated/corrupt registry silently wiping pairings and push\n // registrations would be indistinguishable from \"never registered\".\n // Make data loss loud so the cause (crash mid-write, disk, …) shows.\n console.log('[deeppilot] device registry unreadable, starting empty: ' + String(error))\n }\n }\n return store\n }\n\n /** Register one public key after a valid, single-use pairing grant. */\n register(\n record: { publicKey: string; deviceName: string; appVersion: string; scopes?: unknown },\n now: number,\n ): DeviceRecord {\n const deviceId = deviceIdForPublicKey(record.publicKey)\n const existing = this.devices.get(deviceId)\n if (!existing && this.devices.size >= MAX_DEVICES) {\n throw new Error('device registry is full')\n }\n const next: DeviceRecord = {\n deviceId,\n deviceName: record.deviceName,\n appVersion: record.appVersion,\n publicKey: record.publicKey,\n fingerprint: fingerprintForPublicKey(record.publicKey),\n scopes: normalizeDeviceScopes(record.scopes),\n firstSeenTs: existing?.firstSeenTs ?? now,\n lastSeenTs: now,\n ...(existing?.apns ? { apns: existing.apns } : {}),\n ...(existing?.widgetApns ? { widgetApns: existing.widgetApns } : {}),\n ...(existing?.liveActivity ? { liveActivity: existing.liveActivity } : {}),\n }\n this.devices.set(deviceId, next)\n void this.flush()\n return structuredClone(next)\n }\n\n /** Return an active cryptographic identity. */\n authorized(deviceId: string): DeviceRecord | undefined {\n const record = this.devices.get(deviceId)\n if (!record?.publicKey || record.revokedAt !== undefined) return undefined\n return record\n }\n\n markAuthenticated(deviceId: string, deviceName: string, appVersion: string, now: number): void {\n const record = this.authorized(deviceId)\n if (!record) return\n record.deviceName = deviceName || record.deviceName\n record.appVersion = appVersion || record.appVersion\n record.lastSeenTs = now\n void this.flush()\n }\n\n revoke(deviceId: string, now: number): boolean {\n const record = this.devices.get(deviceId)\n if (!record || record.revokedAt !== undefined) return false\n record.revokedAt = now\n delete record.apns\n delete record.widgetApns\n delete record.liveActivity\n void this.flush()\n return true\n }\n\n setScopes(deviceId: string, scopes: unknown): DeviceScope[] | null {\n const record = this.authorized(deviceId)\n if (!record) return null\n record.scopes = normalizeDeviceScopes(scopes)\n void this.flush()\n return [...record.scopes]\n }\n\n list(): DeviceRecord[] {\n return [...this.devices.values()].map((record) => structuredClone(record))\n }\n\n /**\n * Store (or refresh) the APNs registration of a paired device. Idempotent:\n * an unchanged registration does not rewrite the registry file, so the\n * app's re-register-on-every-handshake policy stays write-quiet.\n */\n setPushToken(\n deviceId: string,\n token: string,\n environment: ApnsEnvironment,\n categories: Record<string, boolean> | undefined,\n now: number,\n ): void {\n const normalized = token.toLowerCase()\n if (!isValidApnsToken(normalized)) return\n const record = this.authorized(deviceId)\n if (!record) return\n const next: DeviceApnsInfo = { token: normalized, environment, updatedAt: now }\n if (categories && typeof categories === 'object') {\n const clean: Record<string, boolean> = {}\n for (const [key, value] of Object.entries(categories)) {\n if (/^[a-z.]{1,64}$/.test(key) && typeof value === 'boolean') clean[key] = value\n }\n if (Object.keys(clean).length > 0) next.categories = clean\n }\n const current = record.apns\n if (\n current &&\n current.token === next.token &&\n current.environment === next.environment &&\n JSON.stringify(current.categories ?? {}) === JSON.stringify(next.categories ?? {})\n ) {\n return\n }\n record.apns = next\n void this.flush()\n }\n\n /** Drop a device's APNs registration (APNs reported the token unregistered). */\n clearPushToken(deviceId: string): void {\n const record = this.devices.get(deviceId)\n if (!record?.apns) return\n delete record.apns\n void this.flush()\n }\n\n setLiveActivity(deviceId: string, registration: LiveActivityRegistration): void {\n const record = this.authorized(deviceId)\n if (!record || !isValidApnsToken(registration.token)) return\n const old = record.liveActivity\n // Rotation/reconnect cannot extend a round or erase its terminal state.\n record.liveActivity = old?.activityId === registration.activityId\n ? { ...registration, expiresAt: old.expiresAt, endedState: old.endedState }\n : registration\n void this.flush()\n }\n\n endLiveActivity(deviceId: string, token: string, state: LiveActivityState): void {\n const registration = this.devices.get(deviceId)?.liveActivity\n if (!registration || registration.token !== token || registration.endedState) return\n registration.endedState = state\n void this.flush()\n }\n\n clearLiveActivity(deviceId: string, activityId: string, token?: string): void {\n const record = this.devices.get(deviceId)\n if (record?.liveActivity?.activityId !== activityId ||\n (token !== undefined && record.liveActivity.token !== token)) return\n delete record.liveActivity\n void this.flush()\n }\n\n setWidgetPushToken(deviceId: string, token: string, environment: ApnsEnvironment, now: number): void {\n const record = this.authorized(deviceId)\n if (!record || !isValidApnsToken(token)) return\n const previous = record.widgetApns\n if (previous?.token === token && previous.environment === environment &&\n now - previous.updatedAt < 60 * 60 * 1000) return\n record.widgetApns = { token, environment, updatedAt: now }\n void this.flush()\n }\n\n /** Compare-and-clear protects a rotated token from a delayed APNs rejection. */\n clearWidgetPushToken(deviceId: string, token: string): void {\n const record = this.devices.get(deviceId)\n if (record?.widgetApns?.token !== token) return\n delete record.widgetApns\n void this.flush()\n }\n\n /** Serialized so concurrent touches can never interleave half-written JSON. */\n private flush(): Promise<void> {\n const next = this.flushTail.then(() => this.writeFile())\n this.flushTail = next.catch(() => {\n // best-effort persistence; the bridge still works without it\n })\n return next\n }\n\n /** Resolves once every queued registry write has landed (test support). */\n async drain(): Promise<void> {\n await this.flushTail\n }\n\n private async writeFile(): Promise<void> {\n const full = expandHome(this.filePath)\n const body = JSON.stringify(\n { version: 2, devices: this.list() },\n null,\n 2,\n )\n try {\n await mkdir(dirname(full), { recursive: true })\n // Atomic replace: a restart mid-write previously left a truncated JSON\n // behind, which load() treats as corrupt and drops ENTIRELY — losing\n // pairings and push registrations on every unlucky shutdown.\n const temp = `${full}.${randomBytes(6).toString('hex')}.tmp`\n await writeFile(temp, body + '\\n', { mode: 0o600 })\n await rename(temp, full)\n } catch {\n // best-effort persistence; the bridge still works without it\n }\n }\n}\n","import type { DeviceScope } from './device-auth.ts'\nimport type { Envelope } from './protocol.ts'\n\nexport const AUTH_TIMEOUT_MS = 35_000\nexport const MAX_OUTBOUND_BUFFER_BYTES = 4 * 1024 * 1024\n/**\n * Pre-auth frame cap. The 64 MiB cap on a fully authenticated socket exists\n * to support multi-MB image attachments; before hello the only legal frames\n * are c2s.ping and c2s.auth.prove, neither of which can legitimately exceed\n * a few KB. Capping unauthenticated frames at 64 KiB keeps an anonymous TCP\n * peer from forcing expensive JSON.parse work on a 64 MiB payload inside\n * the 5-second auth window.\n */\nexport const PRE_AUTH_FRAME_BYTES = 64 * 1024\nexport const IMAGE_MEDIA_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp', 'image/gif'])\nexport const MAX_PROMPT_IMAGES = 4\nexport const MAX_BASE64_CHARS_PER_IMAGE = 8 * 1024 * 1024\nexport const MAX_PROMPT_DOCUMENTS = 4\nexport const MAX_DOCUMENT_TEXT_CHARS = 256 * 1024\nexport const MAX_DOCUMENT_NAME_CHARS = 180\nexport const MAX_DOCUMENT_MEDIA_TYPE_CHARS = 120\n/** Bounds a single prompt's text; the frame itself is capped by ws maxPayload. */\nexport const MAX_PROMPT_TEXT_CHARS = 256 * 1024\n// Client-supplied identity fields land in logs and devices-v2.json — keep them\n// short and free of control characters so they can neither flood the registry\n// nor forge log lines.\nexport const MAX_DEVICE_ID_CHARS = 128\nexport const MAX_DEVICE_NAME_CHARS = 64\nexport const MAX_APP_VERSION_CHARS = 32\n\nexport function sanitizeDeviceField(value: unknown, maxChars: number): string {\n const raw = typeof value === 'string' ? value : String(value ?? '')\n return raw.replace(/[\\u0000-\\u001f\\u007f]/g, ' ').trim().slice(0, maxChars)\n}\n\n/**\n * Runtime shape guard for a frame after JSON.parse. The old `as Envelope`\n * cast alone let JSON `null` reach `env.v` and let a missing or mistyped\n * `type` reach `requiredScope()`'s string operations — one anonymous frame\n * could crash the host process. Reject anything that is not a plain object\n * with a numeric version and a non-empty string type, so field access below\n * is always safe. The payload is intentionally opaque here; each handler\n * validates its own payload shape.\n */\nexport function isEnvelope(value: unknown): value is Envelope {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const frame = value as Record<string, unknown>\n if (typeof frame.v !== 'number') return false\n if (typeof frame.type !== 'string' || frame.type.length === 0) return false\n if (frame.id !== undefined && typeof frame.id !== 'string') return false\n if (frame.ts !== undefined && typeof frame.ts !== 'number') return false\n if (frame.seq !== undefined && typeof frame.seq !== 'number') return false\n return true\n}\n\nexport function requiredScope(type: string): DeviceScope | undefined {\n // Defense in depth: callers must pass the validated envelope's `type`, but\n // a non-string value must never reach the startsWith checks below.\n if (typeof type !== 'string') return undefined\n if (type === 'c2s.ping' || type === 'c2s.resume') return undefined\n if (type === 'c2s.session.sendPrompt' || type === 'c2s.session.delivery') return 'prompt.send'\n if (type === 'c2s.pending.list') return 'interactions.respond'\n if (type === 'c2s.approval.respond' || type === 'c2s.question.respond') return 'interactions.respond'\n if (type === 'c2s.liveActivity.register' || type === 'c2s.liveActivity.unregister') return 'notifications.register'\n if (type === 'c2s.push.register' || type === 'c2s.widget.push.register') return 'notifications.register'\n if (\n type === 'c2s.workspace.create' ||\n type === 'c2s.session.create' ||\n type === 'c2s.session.rename' ||\n type === 'c2s.session.archive' ||\n type === 'c2s.session.cancel' ||\n type === 'c2s.session.selectModel'\n ) return 'sessions.manage'\n if (type.startsWith('c2s.')) return 'sessions.read'\n return undefined\n}\n\n/** Broadcast and replay authorization. Unknown frame types fail closed. */\nconst PUSH_SCOPE_BY_TYPE: Partial<Record<string, DeviceScope>> = {\n 's2c.session.event': 'sessions.read',\n 's2c.sessions.delta': 'sessions.read',\n 's2c.session.tail': 'sessions.read',\n 's2c.history.page': 'sessions.read',\n 's2c.pending.approval': 'interactions.respond',\n 's2c.pending.question': 'interactions.respond',\n 's2c.pending.cleared': 'interactions.respond',\n}\n\nexport function pushScopeFor(type: string, payload?: unknown): DeviceScope | undefined {\n const fixed = PUSH_SCOPE_BY_TYPE[type]\n if (fixed !== undefined) return fixed\n if (type === 's2c.notify') {\n const category = (payload as { category?: unknown } | undefined)?.category\n if (category === 'approval.required' || category === 'question.asked') return 'interactions.respond'\n if (category === 'turn.completed' || category === 'session.error') return 'sessions.read'\n }\n return undefined\n}\n\nexport function sanitizeImageName(value: string): string {\n return value.replace(/[\\u0000-\\u001F\\u007F]/g, '').trim().slice(0, 120)\n}\n\nexport function sanitizeDocumentField(value: string, maxChars: number): string {\n return value.replace(/[\\u0000-\\u001F\\u007F]/g, ' ').trim().slice(0, maxChars)\n}\n\nexport const ERROR_CODES = {\n E_AUTH: 'device proof missing or invalid',\n E_FORBIDDEN: 'device scope does not allow this operation',\n E_PROTOCOL: 'unknown type or malformed payload',\n E_NOT_FOUND: 'session or request not found',\n E_BUSY: 'session is busy',\n E_UNSUPPORTED: 'protocol version or capability unsupported',\n E_INTERNAL: 'internal error',\n} as const\n\n/** Error code for a failed approval/question response outcome. */\nexport function pendingResponseErrorCode(reason: 'not-pending' | 'bad-response' | 'transport'): keyof typeof ERROR_CODES {\n switch (reason) {\n case 'not-pending': return 'E_NOT_FOUND'\n // The host refused the answer batch (shape/labels mismatch) — a client\n // payload problem, not a missing pending request.\n case 'bad-response': return 'E_PROTOCOL'\n case 'transport': return 'E_INTERNAL'\n }\n}\n\n/** Human-readable failure detail; `question not pending` must only ever mean\n * \"nothing pending\", never \"the host rejected the answer\". */\nexport function pendingResponseMessage(\n kind: 'approval' | 'question',\n reason: 'not-pending' | 'bad-response' | 'transport',\n): string {\n switch (reason) {\n case 'not-pending': return kind + ' not pending'\n case 'bad-response': return kind + ' answer rejected by host: answer does not match the asked questions'\n case 'transport': return 'host connection failed while answering ' + kind\n }\n}\n\nexport function managementErrorCode(\n kind: 'unsupported' | 'not-found' | 'busy' | 'invalid' | 'internal',\n): keyof typeof ERROR_CODES {\n switch (kind) {\n case 'unsupported': return 'E_UNSUPPORTED'\n case 'not-found': return 'E_NOT_FOUND'\n case 'busy': return 'E_BUSY'\n case 'invalid': return 'E_PROTOCOL'\n case 'internal': return 'E_INTERNAL'\n }\n}\n","import { validateRequest } from './request-validation.ts'\nimport type { WebSocket } from 'ws'\nimport {\n PROTOCOL_VERSION,\n} from './protocol.ts'\nimport type { AuthProofPayload, Envelope } from './protocol.ts'\nimport type { BridgeSink, HostBridge } from './host-bridge.ts'\nimport type { DeviceStore, ApnsEnvironment } from './token.ts'\nimport { isValidApnsToken } from './token.ts'\nimport {\n createAuthChallenge,\n verifyAuthProof,\n type AuthChallenge,\n type DeviceScope,\n} from './device-auth.ts'\nimport {\n AUTH_TIMEOUT_MS,\n ERROR_CODES,\n IMAGE_MEDIA_TYPES,\n MAX_APP_VERSION_CHARS,\n MAX_BASE64_CHARS_PER_IMAGE,\n MAX_DOCUMENT_MEDIA_TYPE_CHARS,\n MAX_DOCUMENT_NAME_CHARS,\n MAX_DOCUMENT_TEXT_CHARS,\n MAX_DEVICE_ID_CHARS,\n MAX_DEVICE_NAME_CHARS,\n MAX_OUTBOUND_BUFFER_BYTES,\n MAX_PROMPT_IMAGES,\n MAX_PROMPT_DOCUMENTS,\n MAX_PROMPT_TEXT_CHARS,\n PRE_AUTH_FRAME_BYTES,\n managementErrorCode,\n pendingResponseErrorCode,\n pendingResponseMessage,\n sanitizeDeviceField,\n sanitizeImageName,\n sanitizeDocumentField,\n requiredScope,\n isEnvelope,\n} from './connection-policy.ts'\n\nexport {\n AUTH_TIMEOUT_MS,\n MAX_OUTBOUND_BUFFER_BYTES,\n PRE_AUTH_FRAME_BYTES,\n} from './connection-policy.ts'\n\n\nexport interface ConnectionStateDeps {\n bridge: HostBridge\n devices: DeviceStore\n serverVersion: string\n /** Stable Host identity included in every signed challenge. */\n audience: string\n debug?: boolean\n log: (message: string) => void\n /** Called once when the socket closes (cleanly or not). */\n onClosed?: (connection: BridgeConnection) => void\n /** Releases an unauthenticated connection slot and updates failure state. */\n onAuthenticationSettled?: (ok: boolean, reason: 'success' | 'invalid-proof' | 'timeout' | 'closed') => void\n /** Emits a privacy-preserving audit event after a valid hello. */\n onDeviceAuthenticated?: (deviceId: string) => void\n /**\n * Zero-touch push enrollment: fired when a distributed app presents the\n * distributor's shared enrollKey during c2s.push.register. May perform the\n * relay round-trip; the register handler awaits it before evaluating push\n * readiness, so the very first registration can switch the feature on.\n */\n onPushEnrollKey?: (enrollKey: string) => Promise<void> | void\n}\n\n\n/**\n * One connected phone. Implements BridgeSink so the HostBridge can push\n * projected frames and replays. Every socket starts anonymous, receives one\n * server challenge, and must prove possession of a registered P-256 key.\n */\nexport class BridgeConnection implements BridgeSink {\n private authenticated = false\n private authenticationSettled = false\n private closed = false\n private helloTimer: NodeJS.Timeout | undefined\n private readonly openSessions = new Set<string>()\n /**\n * Realtime events that arrive while a session's history snapshot is in\n * flight. The wire contract requires tail first; sending these immediately\n * lets the later tail roll the client back over messages it just rendered.\n */\n private readonly openingSessionEvents = new Map<string, Array<{\n type: string\n payload: unknown\n seq?: number\n }>>()\n /** Sanitized device identity from hello; needed for push registration. */\n private deviceId: string | undefined\n private scopes = new Set<DeviceScope>()\n private widgetClient = false\n private liveActivityRegistrationGeneration = 0\n private pendingLiveActivityId?: string\n private readonly authChallenge: AuthChallenge\n\n constructor(\n private readonly ws: WebSocket,\n private readonly deps: ConnectionStateDeps,\n ) {\n this.authChallenge = createAuthChallenge(deps.audience)\n ws.on('message', (data) => {\n void this.onMessage(String(data)).catch((error) => {\n // A frame must never take down the host process: fail only this\n // socket. Protocol-shape mistakes are handled inside onMessage; this\n // is the last line of defense for unexpected handler errors.\n if (this.deps.debug === true) this.deps.log('frame handler failed: ' + String(error))\n if (this.closed) return\n this.terminate()\n })\n })\n ws.on('close', () => {\n this.onClose()\n deps.onClosed?.(this)\n })\n ws.on('error', () => {\n /* close follows */\n })\n this.helloTimer = setTimeout(() => {\n if (!this.authenticated) {\n this.settleAuthentication(false, 'timeout')\n this.close(4402, 'auth timeout')\n }\n }, AUTH_TIMEOUT_MS)\n this.helloTimer.unref()\n this.send('s2c.auth.challenge', this.authChallenge)\n }\n\n /** Hard-drop the socket (server-side stale sweep). */\n terminate(): void {\n this.ws.terminate()\n }\n\n /** Protocol-compliant idle timeout: let the peer observe a normal 1001 close. */\n closeIdle(): void {\n this.close(1001, 'idle timeout')\n }\n\n /** Announce an orderly plugin/data-plane shutdown before closing the socket. */\n closeForServerStop(): void {\n this.fail(undefined, 'E_INTERNAL', 'server stopping')\n this.close(1001, 'server stopping')\n }\n\n /** Used by dependency-lifecycle cleanup to avoid closing a replacement bridge. */\n isAttachedTo(bridge: HostBridge): boolean {\n return this.deps.bridge === bridge\n }\n\n /** Device identity once hello succeeded; undefined before that. */\n get connectedDeviceId(): string | undefined {\n return this.authenticated ? this.deviceId : undefined\n }\n\n get suppressesAlertPush(): boolean { return !this.widgetClient }\n\n // ---------- BridgeSink ----------\n\n /** S→C permission gate consulted by the bridge for every broadcast/replay\n * frame: a device only receives what its scopes grant (R1/P2). */\n canReceive(scope: DeviceScope): boolean {\n return this.scopes.has(scope)\n }\n\n push(type: string, payload: unknown, seq?: number): void {\n if (type === 's2c.notify') payload = { ...(payload as object), hostAudience: this.deps.audience }\n if (type === 's2c.session.event') {\n const sessionId = (payload as { sessionId?: unknown } | undefined)?.sessionId\n if (typeof sessionId === 'string') {\n const buffered = this.openingSessionEvents.get(sessionId)\n if (buffered) {\n buffered.push({ type, payload, ...(seq !== undefined ? { seq } : {}) })\n return\n }\n }\n }\n if (this.deps.debug === true) this.deps.log('push ' + type + ' seq=' + String(seq))\n this.send(type, payload, undefined, seq)\n }\n\n replay(entries: Array<{ seq: number; type: string; payload: unknown }>): void {\n for (const entry of entries) this.push(entry.type, entry.payload, entry.seq)\n }\n\n replayDone(): void {\n this.push('s2c.resume.done', {})\n }\n\n resync(): void {\n this.push('s2c.resync', { reason: 'gap' })\n }\n\n lastCursor(): number {\n return this.deps.bridge.currentCursor()\n }\n\n // ---------- lifecycle ----------\n\n private onClose(): void {\n if (this.closed) return\n this.closed = true\n if (!this.authenticationSettled) this.settleAuthentication(false, 'closed')\n if (this.helloTimer !== undefined) clearTimeout(this.helloTimer)\n for (const id of this.openSessions) {\n this.deps.bridge.markSinkClosed(this, id)\n }\n this.openSessions.clear()\n this.openingSessionEvents.clear()\n this.deps.bridge.dropSinkSessions(this)\n if (this.authenticated) this.deps.bridge.removeSink(this)\n }\n\n private settleAuthentication(ok: boolean, reason: 'success' | 'invalid-proof' | 'timeout' | 'closed'): void {\n if (this.authenticationSettled) return\n this.authenticationSettled = true\n this.deps.onAuthenticationSettled?.(ok, reason)\n }\n\n private close(code: number, reason: string): void {\n if (this.closed) return\n try {\n this.ws.close(code, reason)\n } catch {\n this.ws.terminate()\n }\n }\n\n private send(type: string, payload: unknown, id?: string, seq?: number): void {\n const envelope: Envelope = {\n v: PROTOCOL_VERSION,\n type,\n ts: Date.now(),\n ...(id !== undefined ? { id } : {}),\n ...(seq !== undefined ? { seq } : {}),\n payload,\n }\n if (this.ws.readyState !== this.ws.OPEN) return\n if (this.ws.bufferedAmount > MAX_OUTBOUND_BUFFER_BYTES) {\n this.close(1013, 'client too slow')\n return\n }\n this.ws.send(JSON.stringify(envelope))\n }\n\n private fail(id: string | undefined, code: keyof typeof ERROR_CODES, message: string): void {\n this.send('s2c.error', { code, message }, id)\n }\n\n // ---------- dispatch ----------\n\n private lastActivity = Date.now()\n\n /** True when no inbound frame arrived within maxIdleMs. */\n isStale(now: number, maxIdleMs: number): boolean {\n return now - this.lastActivity > maxIdleMs\n }\n\n private async onMessage(raw: string): Promise<void> {\n this.lastActivity = Date.now()\n // Cheap length guard before the JSON parse: pre-auth frames are tiny\n // (hello/ping), so anything over 64 KiB is either junk or an attempt\n // to make us spend CPU before the auth deadline. Reject without\n // trying to parse, so the cost is just the length check.\n if (!this.authenticated && raw.length > PRE_AUTH_FRAME_BYTES) {\n this.close(1009, 'pre-auth frame too large')\n return\n }\n let env: Envelope\n try {\n const parsed: unknown = JSON.parse(raw)\n if (!isEnvelope(parsed)) {\n this.fail(undefined, 'E_PROTOCOL', 'malformed frame')\n return\n }\n env = parsed\n } catch {\n this.fail(undefined, 'E_PROTOCOL', 'frame is not valid JSON')\n return\n }\n if (env.v !== PROTOCOL_VERSION) {\n this.fail(env.id, 'E_UNSUPPORTED', 'unsupported protocol version')\n this.close(4500, 'protocol version mismatch')\n return\n }\n if (!this.authenticated) {\n if (env.type === 'c2s.ping') {\n this.send('s2c.pong', { serverTime: Date.now() }, env.id)\n return\n }\n if (env.type === 'c2s.auth.prove') {\n await this.prove(env)\n return\n }\n this.fail(env.id, 'E_PROTOCOL', 'authenticate first')\n return\n }\n if (this.widgetClient && ![\n 'c2s.ping', 'c2s.sessions.list', 'c2s.pending.list', 'c2s.widget.push.register',\n ].includes(env.type)) {\n return this.fail(env.id, 'E_FORBIDDEN', 'widget connection is read-only')\n }\n const required = requiredScope(env.type)\n if (required !== undefined && !this.scopes.has(required)) {\n this.fail(env.id, 'E_FORBIDDEN', `scope ${required} required`)\n return\n }\n const invalid = validateRequest(env.type, env.payload)\n if (invalid) return this.fail(env.id, 'E_PROTOCOL', invalid)\n switch (env.type) {\n case 'c2s.ping': {\n this.send('s2c.pong', { serverTime: Date.now() }, env.id)\n return\n }\n case 'c2s.sessions.list': {\n this.send('s2c.sessions.snapshot', { full: true, sessions: this.deps.bridge.listSessions() }, env.id)\n return\n }\n case 'c2s.pending.list': {\n this.send('s2c.pending.snapshot', this.deps.bridge.pendingSnapshot(), env.id)\n return\n }\n case 'c2s.workspaces.list': {\n if (!this.deps.bridge.capabilities.projectSelection) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'project selection unavailable on this host version')\n }\n const result = await this.deps.bridge.listWorkspaces()\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.workspaces.snapshot', { workspaces: result.value }, env.id)\n return\n }\n case 'c2s.directory.list': {\n const p = env.payload as { path?: unknown } | undefined\n if (p?.path !== undefined && typeof p.path !== 'string') {\n return this.fail(env.id, 'E_PROTOCOL', 'path must be a string')\n }\n const result = await this.deps.bridge.listDirectory(p?.path as string | undefined)\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.directory.listing', result.value, env.id)\n return\n }\n case 'c2s.directory.pick': {\n const result = await this.deps.bridge.pickDirectory()\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.directory.picked', { path: result.value }, env.id)\n return\n }\n case 'c2s.workspace.create': {\n const p = env.payload as { path?: unknown } | undefined\n const path = typeof p?.path === 'string' ? p.path.trim() : ''\n if (!path) return this.fail(env.id, 'E_PROTOCOL', 'non-empty path required')\n if (!this.deps.bridge.capabilities.projectSelection) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'project selection unavailable on this host version')\n }\n const result = await this.deps.bridge.createWorkspace(path)\n if (!result.ok) return this.fail(env.id, managementErrorCode(result.kind), result.message)\n this.send('s2c.workspace.created', result.value, env.id)\n return\n }\n case 'c2s.session.open': {\n const p = env.payload as { sessionId?: string; tailCount?: number }\n if (!p?.sessionId || typeof p.sessionId !== 'string') return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n const sessionId = p.sessionId\n const bufferedEvents: Array<{ type: string; payload: unknown; seq?: number }> = []\n this.openingSessionEvents.set(sessionId, bufferedEvents)\n const ok = await this.deps.bridge.openSession(this, sessionId, p.tailCount ?? 100)\n if (!ok) {\n if (this.openingSessionEvents.get(sessionId) === bufferedEvents) {\n this.openingSessionEvents.delete(sessionId)\n }\n return this.fail(env.id, 'E_NOT_FOUND', 'session history unavailable')\n }\n // A concurrent close or replacement open invalidates this attempt.\n // Its tail has already been sent, but it must not reactivate realtime\n // delivery after the user left the screen.\n if (this.openingSessionEvents.get(sessionId) !== bufferedEvents) return\n this.openSessions.add(sessionId)\n this.deps.bridge.markSinkOpen(this, sessionId)\n this.openingSessionEvents.delete(sessionId)\n for (const frame of bufferedEvents) {\n this.push(frame.type, frame.payload, frame.seq)\n }\n return\n }\n case 'c2s.session.close': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n this.openingSessionEvents.delete(p.sessionId)\n this.openSessions.delete(p.sessionId)\n this.deps.bridge.markSinkClosed(this, p.sessionId)\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.session.create': {\n const p = env.payload as { workspaceId?: unknown; cwd?: unknown } | undefined\n const workspaceId = typeof p?.workspaceId === 'string' ? p.workspaceId.trim() : ''\n const cwd = typeof p?.cwd === 'string' ? p.cwd.trim() : ''\n if (workspaceId && cwd) return this.fail(env.id, 'E_PROTOCOL', 'workspaceId and cwd are mutually exclusive')\n const newId = await this.deps.bridge.createSession({\n ...(workspaceId ? { workspaceId } : {}),\n ...(cwd ? { cwd } : {}),\n })\n if (!newId) return this.fail(env.id, 'E_INTERNAL', 'session create failed')\n this.send('s2c.ack', { sessionId: newId }, env.id)\n return\n }\n case 'c2s.session.rename': {\n const p = env.payload as { sessionId?: string; title?: string }\n const title = typeof p?.title === 'string' ? p.title.trim() : ''\n if (!p?.sessionId || title.length === 0) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and non-empty title required')\n }\n if (!this.deps.bridge.capabilities.sessionManagement) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'session management unavailable on this host version')\n }\n const result = await this.deps.bridge.renameSession(p.sessionId, title)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.renamed', { sessionId: p.sessionId, title: result.value }, env.id)\n return\n }\n case 'c2s.session.archive': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n if (!this.deps.bridge.capabilities.sessionManagement) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'session management unavailable on this host version')\n }\n const result = await this.deps.bridge.archiveSession(p.sessionId)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.archived', { sessionId: p.sessionId }, env.id)\n return\n }\n case 'c2s.session.cancel': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n const result = await this.deps.bridge.cancelSession(p.sessionId)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.ack', { sessionId: p.sessionId }, env.id)\n return\n }\n case 'c2s.session.history': {\n const p = env.payload as { sessionId?: string; beforeSeq?: number; limit?: number }\n if (!p?.sessionId || typeof p.beforeSeq !== 'number') {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and beforeSeq required')\n }\n const page = await this.deps.bridge.historyPage(p.sessionId, p.beforeSeq, Math.min(p.limit ?? 100, 500))\n if (!page) return this.fail(env.id, 'E_NOT_FOUND', 'history unavailable')\n this.send('s2c.history.page', page, env.id)\n return\n }\n case 'c2s.session.attachment': {\n const p = env.payload as { sessionId?: string; attachmentId?: string }\n if (!p?.sessionId || typeof p.attachmentId !== 'string' || p.attachmentId.length === 0) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and attachmentId required')\n }\n const image = await this.deps.bridge.attachmentData(p.sessionId, p.attachmentId)\n if (!image) return this.fail(env.id, 'E_NOT_FOUND', 'attachment unavailable')\n this.send('s2c.ack', image, env.id)\n return\n }\n case 'c2s.session.models': {\n const p = env.payload as { sessionId?: string }\n if (!p?.sessionId) return this.fail(env.id, 'E_PROTOCOL', 'sessionId required')\n if (!this.deps.bridge.capabilities.models) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'model selection unavailable on this host version')\n }\n const result = await this.deps.bridge.sessionModels(p.sessionId)\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'unavailable' ? 'E_NOT_FOUND'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.models', { sessionId: p.sessionId, ...result.value }, env.id)\n return\n }\n case 'c2s.session.selectModel': {\n const p = env.payload as {\n sessionId?: string\n provider?: string\n model?: string\n reasoningEffort?: string\n }\n if (!p?.sessionId || !p.provider?.trim() || !p.model?.trim()) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId, provider and model required')\n }\n if (!this.deps.bridge.capabilities.models) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'model selection unavailable on this host version')\n }\n const result = await this.deps.bridge.selectSessionModel(p.sessionId, {\n provider: p.provider.trim(),\n model: p.model.trim(),\n ...(p.reasoningEffort?.trim() ? { reasoningEffort: p.reasoningEffort.trim() } : {}),\n })\n if (!result.ok) {\n const code = result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'busy' ? 'E_BUSY'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED'\n : result.kind === 'unavailable' ? 'E_NOT_FOUND'\n : 'E_INTERNAL'\n return this.fail(env.id, code, result.message)\n }\n this.send('s2c.session.modelSelected', { sessionId: p.sessionId, selected: result.value }, env.id)\n return\n }\n case 'c2s.session.delivery': {\n const p = env.payload as { sessionId: string; clientSendId: string }\n this.send('s2c.ack', this.deps.bridge.promptDeliveries.lookup(this.deviceId!, p.sessionId, p.clientSendId), env.id)\n return\n }\n case 'c2s.session.sendPrompt': {\n const p = env.payload as {\n sessionId?: string\n text?: string\n clientSendId?: string\n images?: Array<{ mediaType?: string; data?: string; name?: string }>\n documents?: Array<{ mediaType?: string; name?: string; text?: string; truncated?: boolean }>\n }\n const text = typeof p?.text === 'string' ? p.text : ''\n const rawImages = Array.isArray(p?.images) ? p.images : []\n const rawDocuments = Array.isArray(p?.documents) ? p.documents : []\n if (!p?.sessionId || (text.trim().length === 0 && rawImages.length === 0 && rawDocuments.length === 0)) {\n return this.fail(env.id, 'E_PROTOCOL', 'sessionId and prompt content required')\n }\n if (text.length > MAX_PROMPT_TEXT_CHARS) {\n return this.fail(env.id, 'E_PROTOCOL', 'prompt text too long')\n }\n if (rawImages.length > MAX_PROMPT_IMAGES) {\n return this.fail(env.id, 'E_PROTOCOL', 'too many images')\n }\n if (rawDocuments.length > MAX_PROMPT_DOCUMENTS || rawImages.length + rawDocuments.length > MAX_PROMPT_IMAGES) {\n return this.fail(env.id, 'E_PROTOCOL', 'too many prompt attachments')\n }\n const images: Array<{\n mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'\n data: string\n name?: string\n }> = []\n for (const image of rawImages) {\n if (!IMAGE_MEDIA_TYPES.has(String(image?.mediaType)) ||\n typeof image?.data !== 'string' || image.data.length === 0 ||\n image.data.length > MAX_BASE64_CHARS_PER_IMAGE) {\n return this.fail(env.id, 'E_PROTOCOL', 'invalid image attachment')\n }\n images.push({\n mediaType: image.mediaType as 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif',\n data: image.data,\n ...(typeof image.name === 'string' && sanitizeImageName(image.name).length > 0\n ? { name: sanitizeImageName(image.name) }\n : {}),\n })\n }\n const documents: Array<{ mediaType: string; name: string; text: string; truncated?: boolean }> = []\n for (const document of rawDocuments) {\n if (typeof document?.name !== 'string' || typeof document?.mediaType !== 'string' ||\n typeof document?.text !== 'string' || document.text.length === 0 ||\n document.text.length > MAX_DOCUMENT_TEXT_CHARS) {\n return this.fail(env.id, 'E_PROTOCOL', 'invalid document attachment')\n }\n const name = sanitizeDocumentField(document.name, MAX_DOCUMENT_NAME_CHARS)\n const mediaType = sanitizeDocumentField(document.mediaType, MAX_DOCUMENT_MEDIA_TYPE_CHARS).toLowerCase()\n if (!name || !mediaType || mediaType.startsWith('image/')) {\n return this.fail(env.id, 'E_PROTOCOL', 'invalid document attachment')\n }\n documents.push({ name, mediaType, text: document.text, ...(document.truncated === true ? { truncated: true } : {}) })\n }\n if (p.clientSendId) {\n const receipt = await this.deps.bridge.promptDeliveries.dispatch(this.deviceId!, p.sessionId, p.clientSendId,\n { text, images, documents }, () => this.deps.bridge.sendPrompt(p.sessionId!, text, images, documents))\n this.send('s2c.ack', receipt, env.id)\n return\n }\n const userSeq = await this.deps.bridge.sendPrompt(p.sessionId, text, images, documents)\n if (!userSeq.ok) return this.fail(env.id, managementErrorCode(userSeq.kind), userSeq.message)\n this.send('s2c.ack', { userSeq: userSeq.value }, env.id)\n return\n }\n case 'c2s.approval.respond': {\n const p = env.payload as { requestId?: string; decision?: string; reason?: string }\n if (!p?.requestId || (p.decision !== 'allow' && p.decision !== 'deny')) {\n return this.fail(env.id, 'E_PROTOCOL', 'requestId and decision required')\n }\n // The optional deny reason must reach the host so the\n // model learns why its tool call was refused.\n const outcome = await this.deps.bridge.respondApproval(\n p.requestId,\n p.decision,\n typeof p.reason === 'string' ? p.reason : undefined,\n )\n if (!outcome.ok) return this.fail(env.id, pendingResponseErrorCode(outcome.reason), pendingResponseMessage('approval', outcome.reason))\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.question.respond': {\n const p = env.payload as { requestId?: string; answers?: unknown }\n if (!p?.requestId || !Array.isArray(p.answers)) {\n return this.fail(env.id, 'E_PROTOCOL', 'requestId and answers required')\n }\n const outcome = await this.deps.bridge.respondQuestion(p.requestId, p.answers)\n if (!outcome.ok) return this.fail(env.id, pendingResponseErrorCode(outcome.reason), pendingResponseMessage('question', outcome.reason))\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.liveActivity.unregister': {\n const p = env.payload as { activityId: string }\n if (this.pendingLiveActivityId === p.activityId) {\n this.liveActivityRegistrationGeneration += 1\n this.pendingLiveActivityId = undefined\n }\n this.deps.devices.clearLiveActivity(this.deviceId!, p.activityId)\n this.send('s2c.ack', {}, env.id)\n return\n }\n case 'c2s.liveActivity.register': {\n const p = env.payload as { activityId: string; sessionId: string; deviceToken: string; environment: ApnsEnvironment; enrollKey?: string }\n const initial = this.deviceId && this.deps.devices.authorized(this.deviceId)\n if (!initial || !['notifications.register', 'sessions.read', 'interactions.respond'].every(scope => initial.scopes?.includes(scope as DeviceScope))) {\n return this.fail(env.id, 'E_FORBIDDEN', 'live activity permissions required')\n }\n const generation = ++this.liveActivityRegistrationGeneration\n this.pendingLiveActivityId = p.activityId\n if (p.enrollKey) await this.deps.onPushEnrollKey?.(p.enrollKey)\n if (generation !== this.liveActivityRegistrationGeneration) {\n return this.fail(env.id, 'E_BUSY', 'live activity registration superseded')\n }\n const record = this.deviceId && this.deps.devices.authorized(this.deviceId)\n if (this.closed || !record || !['notifications.register', 'sessions.read', 'interactions.respond'].every(scope => record.scopes?.includes(scope as DeviceScope))) {\n return this.fail(env.id, 'E_FORBIDDEN', 'live activity permissions required')\n }\n if (!this.deps.bridge.listSessions().some(row => row.id === p.sessionId)) {\n return this.fail(env.id, 'E_NOT_FOUND', 'session not found')\n }\n const previous = record.liveActivity\n if (previous?.activityId === p.activityId && previous.sessionId !== p.sessionId) {\n return this.fail(env.id, 'E_PROTOCOL', 'activity is bound to another session')\n }\n this.deps.devices.setLiveActivity(record.deviceId, {\n activityId: p.activityId, sessionId: p.sessionId, token: p.deviceToken.toLowerCase(),\n environment: p.environment, updatedAt: Date.now(), expiresAt: Date.now() + 8 * 60 * 60 * 1000,\n })\n this.deps.bridge.refreshLiveActivities()\n this.send('s2c.ack', { enabled: this.deps.bridge.capabilities.push }, env.id)\n return\n }\n case 'c2s.widget.push.register':\n case 'c2s.push.register': {\n const widget = env.type === 'c2s.widget.push.register'\n const p = env.payload as { deviceToken?: unknown; environment?: unknown; categories?: unknown; enrollKey?: unknown }\n const token = typeof p?.deviceToken === 'string' ? p.deviceToken.trim() : ''\n if (!isValidApnsToken(token)) {\n return this.fail(env.id, 'E_PROTOCOL', 'hex deviceToken (32-512 chars) required')\n }\n const environment: ApnsEnvironment = p?.environment === 'production' ? 'production' : 'development'\n const categories = typeof p?.categories === 'object' && p.categories !== null\n ? p.categories as Record<string, boolean>\n : undefined\n if (!this.deviceId || !this.authenticated) {\n return this.fail(env.id, 'E_PROTOCOL', 'authenticate first')\n }\n // Zero-touch enrollment MUST run before the capability gate: a fresh,\n // unconfigured bridge receives its first register precisely when push\n // is not yet enabled, and the key itself flips relay mode on. The\n // relay round-trip is awaited so readiness reflects reality.\n if (typeof p?.enrollKey === 'string') {\n const enrollKey = p.enrollKey.trim().replace(/[^\\x20-\\x7e]/g, '').slice(0, 128)\n if (enrollKey.length >= 8 && enrollKey.length <= 128) {\n await this.deps.onPushEnrollKey?.(enrollKey)\n }\n }\n // Store the registration BEFORE the readiness gate: if push is still\n // mid-bootstrap (or the relay is temporarily down), the token is\n // already on file for when it recovers — no extra register needed.\n // Enrollment is asynchronous. Re-check authority after awaiting it.\n const record = this.deps.devices.authorized(this.deviceId)\n if (this.closed || !record?.scopes?.includes('notifications.register')) {\n return this.fail(env.id, 'E_FORBIDDEN', 'device authorization changed')\n }\n if (widget) {\n if (!record.scopes.includes('sessions.read') || !record.scopes.includes('interactions.respond')) {\n return this.fail(env.id, 'E_FORBIDDEN', 'widget overview permissions required')\n }\n this.deps.devices.setWidgetPushToken(this.deviceId, token, environment, Date.now())\n } else {\n this.deps.devices.setPushToken(this.deviceId, token, environment, categories, Date.now())\n }\n if (!this.deps.bridge.capabilities.push) {\n if (this.deps.debug === true) this.deps.log('push register held: bridge not ready')\n return this.fail(env.id, 'E_UNSUPPORTED', 'push is not configured on this bridge')\n }\n if (this.deps.debug === true) {\n this.deps.log('push token registered env=' + environment)\n }\n // `enabled` lets the app flip its local capability immediately instead\n // of waiting for the next handshake.\n this.send('s2c.ack', { enabled: true }, env.id)\n return\n }\n default:\n this.fail(env.id, 'E_PROTOCOL', 'unknown type: ' + env.type)\n }\n }\n\n private async prove(env: Envelope): Promise<void> {\n const p = (env.payload ?? {}) as Partial<AuthProofPayload>\n if (!p.deviceId) {\n this.fail(env.id, 'E_PROTOCOL', 'deviceId required')\n this.close(4403, 'deviceId required')\n return\n }\n const deviceId = sanitizeDeviceField(p.deviceId, MAX_DEVICE_ID_CHARS)\n if (!deviceId) {\n this.fail(env.id, 'E_PROTOCOL', 'deviceId required')\n this.close(4403, 'deviceId required')\n return\n }\n const deviceName = sanitizeDeviceField(p.deviceName, MAX_DEVICE_NAME_CHARS) || 'unknown'\n const appVersion = sanitizeDeviceField(p.appVersion, MAX_APP_VERSION_CHARS) || 'unknown'\n const challenge = this.authChallenge\n const record = this.deps.devices.authorized(deviceId)\n const resumeCursor = typeof p.resumeCursor === 'number' && Number.isInteger(p.resumeCursor) && p.resumeCursor >= 0\n ? p.resumeCursor\n : undefined\n const challengeMatches = p.nonce === challenge.nonce &&\n p.audience === challenge.audience &&\n p.issuedAt === challenge.issuedAt &&\n p.expiresAt === challenge.expiresAt &&\n Date.now() <= challenge.expiresAt\n const proofValid = record?.publicKey !== undefined && typeof p.signature === 'string' && challengeMatches &&\n verifyAuthProof(record.publicKey, {\n deviceId,\n deviceName,\n appVersion,\n resumeCursor,\n ...challenge,\n }, p.signature)\n if (!proofValid || record === undefined) {\n this.fail(env.id, 'E_AUTH', 'device proof missing or invalid')\n this.settleAuthentication(false, 'invalid-proof')\n this.close(4401, 'invalid device proof')\n return\n }\n this.settleAuthentication(true, 'success')\n this.authenticated = true\n this.deviceId = deviceId\n this.widgetClient = p.clientRole === 'widget'\n this.scopes = new Set(record.scopes ?? [])\n if (this.helloTimer !== undefined) clearTimeout(this.helloTimer)\n if (!this.widgetClient) this.deps.devices.markAuthenticated(deviceId, deviceName, appVersion, Date.now())\n this.deps.onDeviceAuthenticated?.(deviceId)\n\n const cursor = this.widgetClient ? undefined : resumeCursor\n // Each replayed business frame is authorized separately by HostBridge.\n const canResume = cursor !== undefined && this.deps.bridge.canResumeFrom(cursor)\n // Welcome strictly precedes any replayed pushes.\n this.send('s2c.welcome', {\n protocolVersion: PROTOCOL_VERSION,\n serverVersion: this.deps.serverVersion,\n deviceId,\n scopes: [...this.scopes],\n capabilities: this.deps.bridge.capabilities,\n cursor: this.deps.bridge.currentCursor(),\n resumed: canResume,\n }, env.id)\n if (!this.widgetClient) this.deps.bridge.addSink(this)\n if (cursor !== undefined) {\n if (canResume) {\n this.deps.bridge.resumeFrom(cursor, this)\n } else {\n this.resync()\n }\n }\n }\n}\n","import type { SessionSummary } from './protocol.ts'\nimport type { DeviceScope } from './device-auth.ts'\nimport type { PushNotification } from './protocol.ts'\n\n/* Minimal structural faces over the host apiProxy service. The real types\n * live in @deepseek-ai/dsh-host-apiproxy; keeping them structural lets this\n * plugin compile and degrade independently of host package versions. */\n\ninterface RpcOk<T> { ok: true; value: T }\ninterface RpcErr { ok: false; error: { code: string; message?: string } }\ntype RpcResult<T> = RpcOk<T> | RpcErr\n\ninterface RpcRequestLike<T> { rpcId?: string; payload?: T }\ninterface RpcResponseLike<T> { result?: RpcResult<T> }\n\ninterface SessionsApiLike {\n list(req?: RpcRequestLike<{ cursor?: string }>): Promise<RpcResponseLike<{ items: PhoneSessionRow[] }>>\n history(req: RpcRequestLike<{ sessionId: string; beforeSeq?: number; maxMessages?: number }>):\n Promise<RpcResponseLike<HistoryResult>>\n prompt(req: RpcRequestLike<PromptArgs>): Promise<RpcResponseLike<{ accepted: true }>>\n create(req: RpcRequestLike<{ workspaceId?: string; cwd?: string; agentPreset?: string }>): Promise<RpcResponseLike<{ sessionId: string; agentPreset?: string }>>\n models?(req: RpcRequestLike<{ sessionId: string }>): Promise<RpcResponseLike<HostSessionModels>>\n selectModel?(req: RpcRequestLike<{\n sessionId: string\n provider: string\n model: string\n reasoningEffort?: string\n }>): Promise<RpcResponseLike<{ selected: HostModelSelection }>>\n rename?(req: RpcRequestLike<{ sessionId: string; title: string }>):\n Promise<RpcResponseLike<{ title: string; seq: number }>>\n cancel?(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<Record<string, unknown> | undefined>>\n /** Reads one durable image back after the host verifies the session log references its id. */\n attachment?(req: RpcRequestLike<{ sessionId: string; attachmentId: string }>):\n Promise<RpcResponseLike<{ attachment: { mediaType?: string }; data: string }>>\n}\n\ninterface WorkspaceApiLike {\n list?(req: RpcRequestLike<Record<string, never>>):\n Promise<RpcResponseLike<{ items: WorkspaceViewLike[]; archivedSessionIds: string[] }>>\n create?(req: RpcRequestLike<{ path: string }>):\n Promise<RpcResponseLike<{ workspace: WorkspaceViewLike; created: boolean }>>\n archiveSession?(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ archivedSessionIds: string[] }>>\n}\n\ninterface HostApiLike {\n listDirectory?(req: RpcRequestLike<{ path?: string }>, signal?: AbortSignal):\n Promise<RpcResponseLike<DirectoryListingLike>>\n pickDirectory?(req: RpcRequestLike<Record<string, never>>, signal?: AbortSignal):\n Promise<RpcResponseLike<{ path: string | null }>>\n}\n\nexport interface WorkspaceViewLike {\n workspaceId: string\n path: string\n title: string\n sessionIds: string[]\n createdAt?: string\n updatedAt?: string\n}\n\nexport interface DirectoryEntryLike {\n name: string\n path: string\n hidden: boolean\n}\n\nexport interface DirectoryListingLike {\n path: string\n home: string\n crumbs: DirectoryEntryLike[]\n entries: DirectoryEntryLike[]\n truncated: boolean\n}\n\nexport interface HostModelSelection {\n provider: string\n model: string\n reasoningEffort?: string\n}\n\nexport interface HostSessionModels {\n current: HostModelSelection\n routable: boolean\n groups: Array<{\n id: string\n name: string\n models: Array<{\n id: string\n name: string\n description?: string\n reasoning?: {\n efforts: Array<{ id: string; name: string; description?: string }>\n defaultEffort?: string\n }\n }>\n }>\n failures: Array<{ id: string; name: string; message: string }>\n}\n\nexport type ModelBridgeResult<T> =\n | { ok: true; value: T }\n | { ok: false; kind: 'unsupported' | 'not-found' | 'busy' | 'unavailable' | 'internal'; message: string }\n\nexport type SessionManagementResult<T> =\n | { ok: true; value: T }\n | { ok: false; kind: 'unsupported' | 'not-found' | 'busy' | 'invalid' | 'internal'; message: string }\n\nexport interface PromptArgs {\n sessionId: string\n mode: 'queue' | 'steer'\n content: Array<\n | { type: 'text'; text: string }\n | { type: 'image'; mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; data: string; name?: string }\n >\n clientTimeZone?: string\n}\n\nexport interface PhoneSessionRow {\n sessionId: string\n updatedAt: number\n running: boolean\n /** Host marks never-prompted sessions as blank; informational only — the\n * summary projects them as idle (see toSummary) so phones can send. */\n blank?: boolean\n cwd?: string\n origin?: string\n parentSessionId?: string\n projections?: { asOfSeq?: number; values?: Record<string, unknown> }\n}\n\n/**\n * Subagent sessions are host-internal workers of a parent conversation.\n * They must never surface on the phone: not in the project/session list,\n * and not as turn-completion pushes for a session the device cannot open.\n */\nexport function isSubagentRow(row: PhoneSessionRow): boolean {\n return row.origin === 'subagent' ||\n (typeof row.parentSessionId === 'string' && row.parentSessionId.length > 0);\n}\n\nexport interface HistoryResult {\n events: Array<{ event: SessionEventLike; view?: unknown }>\n hasMore: boolean\n projections?: { values?: Record<string, unknown> }\n}\n\nexport interface SessionEventLike {\n type: string\n seq: number\n time?: number\n data?: unknown\n}\n\nexport interface MuxFrameLike {\n type: string\n rpcId?: string\n payload?: any\n sessionId?: string\n event?: SessionEventLike\n key?: string\n value?: unknown\n approvalId?: string\n toolName?: string\n reason?: string\n questions?: unknown\n questionRpcId?: string\n running?: boolean\n}\n\n/**\n * apiProxy stream items are server-request envelopes: the frame lives in\n * `payload`, while the stable request id used to answer approval/question\n * waits lives beside it. Flattening only `payload` loses that id and makes\n * both interactions silently disappear.\n */\nexport interface ApiStreamItemLike {\n rpcId?: string\n payload: MuxFrameLike\n}\n\nexport function unwrapStreamItem(item: MuxFrameLike | ApiStreamItemLike): MuxFrameLike {\n const nested = item.payload\n if (nested && typeof nested === 'object' && typeof nested.type === 'string') {\n // The envelope id identifies the server request that must be answered.\n // Preserve it even if a future nested payload happens to carry another id.\n return item.rpcId ? { ...nested, rpcId: item.rpcId } : nested\n }\n return item as MuxFrameLike\n}\n\nexport interface ApiProxyLike {\n sessions: SessionsApiLike\n workspace?: WorkspaceApiLike\n host?: HostApiLike\n respond(message: { type: 'client-response'; rpcId: string; result: RpcResult<unknown> }):\n Promise<{ accepted: boolean; reason?: string }>\n events: {\n mux(req: RpcRequestLike<Record<string, never>>, signal: AbortSignal): AsyncIterable<MuxFrameLike | ApiStreamItemLike>\n host(req: RpcRequestLike<Record<string, never>>, signal: AbortSignal): AsyncIterable<MuxFrameLike | ApiStreamItemLike>\n }\n}\n\n/**\n * Outcome of answering a pending approval/question. The host distinguishes\n * \"never/no longer pending\" from \"payload rejected\", and collapsing both into\n * a boolean made every rejection read as `question not pending` on the phone.\n */\nexport type PendingResponseOutcome =\n | { ok: true }\n | { ok: false; reason: 'not-pending' | 'bad-response' | 'transport' }\n\n/** Downward sink every connected phone registers (one per WebSocket). */\nexport interface BridgeSink {\n push(type: string, payload: unknown, seq?: number): void\n lastCursor(): number\n replay(entries: Array<{ seq: number; type: string; payload: unknown }>): void\n replayDone(): void\n resync(): void\n /**\n * S→C permission gate (R1/P2): whether this sink may receive broadcast or\n * replayed frames that require `scope`. The bridge consults this before\n * every push/replay delivery; unknown broadcast types are denied.\n */\n canReceive(scope: DeviceScope): boolean\n}\n\n/**\n * Offline push fan-out (F-9 离线推送). The bridge forwards every\n * notification-worthy event here; the outlet decides which paired devices\n * (token holders without a live socket) receive an APNs delivery.\n */\nexport interface PushOutlet {\n fanOut(notification: PushNotification): void\n widgetChanged?(): void\n liveActivityChanged?(sessions: SessionSummary[]): void\n /**\n * Whether offline push is currently configured and usable. Drives the\n * welcome capability bit: advertising push while no APNs credentials are\n * loaded would make clients suppress their own local banners and lose\n * notifications entirely.\n */\n isAvailable(): boolean\n}\n","export interface PromptDocument {\n name: string\n mediaType: string\n text: string\n truncated?: boolean\n}\n\ninterface DocumentMarker {\n v: 1\n name: string\n mediaType: string\n truncated?: boolean\n}\n\nconst PREFIX = '[DeepPilot document:'\nconst SUFFIX = ']'\n\n/**\n * DSH 0.1.2 has durable image attachments but no generic file content block.\n * Documents therefore travel as a bounded, explicitly-labelled text block.\n * The marker lets the canonical phone row recover an attachment chip without\n * exposing the complete document body as ordinary user-authored bubble text.\n */\nexport function documentPromptBlock(document: PromptDocument): string {\n const marker: DocumentMarker = {\n v: 1,\n name: document.name,\n mediaType: document.mediaType,\n ...(document.truncated ? { truncated: true } : {}),\n }\n const encoded = Buffer.from(JSON.stringify(marker), 'utf8').toString('base64url')\n return `${PREFIX}${encoded}${SUFFIX}\\nAttached document: ${document.name}\\n\\n${document.text}`\n}\n\nexport function projectedDocument(text: string): PromptDocument | undefined {\n if (!text.startsWith(PREFIX)) return undefined\n const end = text.indexOf(SUFFIX, PREFIX.length)\n if (end < 0) return undefined\n try {\n const decoded = JSON.parse(Buffer.from(text.slice(PREFIX.length, end), 'base64url').toString('utf8')) as Partial<DocumentMarker>\n if (decoded.v !== 1 || typeof decoded.name !== 'string' || typeof decoded.mediaType !== 'string') return undefined\n if (!decoded.name.trim() || !decoded.mediaType.trim()) return undefined\n return {\n name: decoded.name,\n mediaType: decoded.mediaType,\n text: text.slice(end + SUFFIX.length).replace(/^\\nAttached document:[^\\n]*\\n\\n/, ''),\n ...(decoded.truncated === true ? { truncated: true } : {}),\n }\n } catch {\n return undefined\n }\n}\n","import type { MessageProjection, SessionEventKind } from './protocol.ts'\nimport type { SessionEventLike } from './host-api.ts'\nimport { projectedDocument } from './document-payload.ts'\n\nexport const MAX_MESSAGE_PROJECTION_BYTES = 256 * 1024\n/// Aggregate message-array budget for one tail/history frame. The complete\n/// envelope stays below the legacy iOS 1 MB decoder cap with ample metadata\n/// headroom, while each individual projection keeps its 256 KB allowance.\nexport const MAX_SESSION_PAGE_MESSAGES_BYTES = 900 * 1024\n\n/** One durable host event sequence becomes exactly one phone message row.\n * Keep the last projection when a host history response repeats an event. */\nexport function canonicalSessionMessages(messages: MessageProjection[]): MessageProjection[] {\n const bySequence = new Map<number, MessageProjection>()\n for (const message of messages) bySequence.set(message.seq, message)\n return [...bySequence.values()].sort((a, b) => a.seq - b.seq)\n}\n\nexport function limitSessionPageMessages(messages: MessageProjection[]): {\n messages: MessageProjection[]\n dropped: number\n} {\n const canonical = canonicalSessionMessages(messages)\n let bytes = 2 // JSON array brackets\n const kept: MessageProjection[] = []\n for (let index = canonical.length - 1; index >= 0; index -= 1) {\n const message = canonical[index]!\n const candidateBytes = jsonBytes(message) + (kept.length > 0 ? 1 : 0)\n if (bytes + candidateBytes > MAX_SESSION_PAGE_MESSAGES_BYTES) break\n kept.unshift(message)\n bytes += candidateBytes\n }\n return { messages: kept, dropped: canonical.length - kept.length }\n}\n\nexport function projectEvent(sessionId: string, event: SessionEventLike): { kind: SessionEventKind; data: Record<string, unknown> } | null {\n switch (event.type) {\n case 'turn/start':\n return { kind: 'turn.start', data: {} };\n case 'turn/end': {\n const data = event.data as { reason?: { kind?: string } } | undefined;\n return { kind: 'turn.end', data: { ok: data?.reason?.kind === 'completed' } };\n }\n case 'system/message': {\n // DSH 0.1.5 (session format V3) records the system prompt in message\n // history as a native surface event: {turn, step, message: SystemMessage}.\n // The SystemMessage content is model-facing prompt prose, not\n // conversation content — projecting it onto the phone's message list\n // would duplicate it on every page and leak prompt internals the user\n // never typed. Skip it explicitly (rather than via `default`) so a\n // future shape change forces a deliberate decision here.\n return null;\n }\n case 'user/message':\n return {\n kind: 'message.final',\n data: { ...limitMessageProjection({\n seq: event.seq,\n role: userRoleOf(event.data),\n text: messageText(event.data),\n ...attachmentProjection(event.data),\n ...(contextProjectionOf(event.data)),\n ts: tsOf(event),\n }) },\n };\n case 'assistant/chunk': {\n if (chunkTypeOf(event.data) === 'reasoning-delta') {\n return { kind: 'thinking.delta', data: limitRealtimeText({ text: chunkText(event.data), ts: tsOf(event) }) };\n }\n return { kind: 'message.delta', data: limitRealtimeText({ text: chunkText(event.data), ts: tsOf(event) }) };\n }\n case 'assistant/message': {\n const text = messageText(event.data);\n const thinking = messageThinking(event.data);\n // Pure-reasoning or tool-only steps carry no visible answer; emitting\n // them produced empty bubbles on the phone.\n if (!text.trim() && !thinking.trim()) return null;\n return {\n kind: 'message.final',\n data: { ...limitMessageProjection({ seq: event.seq, role: 'assistant', text, ...(thinking ? { thinking } : {}), ts: tsOf(event) }) },\n };\n }\n case 'tool/call': {\n const data = event.data as { name?: string; arguments?: string; callId?: string } | undefined;\n return {\n kind: 'tool.start',\n data: {\n seq: event.seq,\n role: 'tool',\n tool: {\n name: String(data?.name ?? 'tool'),\n state: 'running',\n summary: summarizeArgs(data?.arguments),\n // Echo the invocation id so clients can pair the later result with\n // this exact row instead of guessing.\n ...(data?.callId ? { callId: String(data.callId) } : {}),\n },\n ts: tsOf(event)\n }\n };\n }\n case 'tool/result': {\n const data = event.data as { callId?: string; error?: unknown } | undefined;\n return {\n kind: 'tool.end',\n data: {\n seq: event.seq,\n role: 'tool',\n ok: !event.data || data?.error === undefined,\n // The seq above identifies this result event; callId is what ties it\n // back to the originating tool/call row on the client.\n ...(data?.callId ? { callId: String(data.callId) } : {}),\n ts: tsOf(event)\n }\n };\n }\n default:\n return null;\n }\n}\n\nfunction tsOf(event: SessionEventLike): number {\n return typeof event.time === 'number' ? event.time : Date.now();\n}\n\n// ---------- user-role source classification ----------\n//\n// The DSH host logs every model-visible user-role message as `user/message`,\n// but only some of them are human prompts: synthetic `agent.inject()` context\n// (runtime-context snapshots, background-job notices, workspace instructions,\n// skill content, …) rides the same event type. The durable message carries a\n// `source` whose `kind` tells them apart, and the host's own trajectory view\n// renders only `source.kind === 'user'` as a human prompt — everything else is\n// injected context. The bridge mirrors that classification so the phone can\n// keep the two apart instead of guessing from text shapes.\n\n/** Read the durable message source off one user/message payload. Handles both\n * bare-message payloads and older `{message: {...}}` wrappers; undefined when\n * the shape carries no readable source (legacy hosts). */\nfunction userMessageSource(data: unknown): Record<string, unknown> | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const obj = data as { source?: unknown; message?: { source?: unknown } };\n if (obj.source && typeof obj.source === 'object') {\n return obj.source as Record<string, unknown>;\n }\n if (obj.message && typeof obj.message === 'object' &&\n obj.message.source && typeof obj.message.source === 'object') {\n return obj.message.source as Record<string, unknown>;\n }\n return undefined;\n}\n\n/** Wire role for one user/message payload. A payload without any readable\n * source degrades to 'user' so history written by older hosts stays visible;\n * a present source follows the host's own trajectory rule — anything whose\n * `kind` is not 'user' is injected context and projects as 'system'. */\nfunction userRoleOf(data: unknown): 'user' | 'system' {\n const source = userMessageSource(data);\n if (!source) return 'user';\n return source.kind === 'user' ? 'user' : 'system';\n}\n\n/** Producer name of one injected-context source, mirroring how the DSH client\n * runtime derives its trajectory label: plugin name, skill name, instruction\n * paths, session-reference labels, or the raw kind as fallback. */\nfunction contextLabelOf(source: Record<string, unknown>): string | undefined {\n const kind = typeof source.kind === 'string' ? source.kind : '';\n const joined = (member: string): string | undefined => {\n const list = source[member];\n if (!Array.isArray(list)) return undefined;\n const names = list.flatMap((entry) => {\n if (!entry || typeof entry !== 'object') return [];\n const record = entry as Record<string, unknown>;\n return [typeof record.label === 'string' ? record.label :\n (typeof record.path === 'string' ? record.path : '')];\n }).filter((name) => name.length > 0);\n return names.length > 0 ? names.join(', ') : undefined;\n };\n switch (kind) {\n case 'session-reference':\n return joined('references') ?? (kind || undefined);\n case 'agent-instructions':\n return joined('changes') ?? (kind || undefined);\n case 'plugin':\n return typeof source.plugin === 'string' && source.plugin.length > 0 ? source.plugin : kind || undefined;\n case 'skill-invocation':\n return typeof source.name === 'string' && source.name.length > 0 ? source.name : kind || undefined;\n default:\n return kind || undefined;\n }\n}\n\n/** Semantic ContextForm declared by the producer ('snapshot', 'notice', …);\n * anything unrecognized stays undefined so clients render it opaque. */\nfunction contextFormOf(source: Record<string, unknown>): string | undefined {\n if (typeof source.form !== 'string' || source.form.length === 0) return undefined;\n // Same known-vocabulary guard as the host's trajectory UI.\n const known = ['instructions', 'catalog', 'snapshot', 'notice', 'relay', 'recall'];\n return known.includes(source.form) ? source.form : undefined;\n}\n\n/** Optional `context` metadata for one system row; {} on user rows. */\nfunction contextProjectionOf(data: unknown): { context?: { label?: string; form?: string } } {\n if (userRoleOf(data) !== 'system') return {};\n const source = userMessageSource(data);\n if (!source) return {};\n const label = contextLabelOf(source);\n const form = contextFormOf(source);\n if (!label && !form) return {};\n return { context: { ...(label ? { label } : {}), ...(form ? { form } : {}) } };\n}\n\n/** Extract plain text from user/assistant message payloads across shapes. */\nexport function messageText(data: unknown): string {\n if (typeof data === 'string') return data;\n if (!data || typeof data !== 'object') return '';\n const obj = data as { content?: unknown; text?: unknown; message?: unknown };\n if (typeof obj.text === 'string') return obj.text;\n // Session events wrap the message: {turn, step, message: {role, content}}\n if (obj.message && typeof obj.message === 'object') return messageText(obj.message);\n return contentText(obj.content);\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content.map(part => {\n if (typeof part === 'string') return part;\n if (part && typeof part === 'object') {\n const piece = part as { type?: string; text?: string };\n if (piece.type === 'text' && typeof piece.text === 'string') {\n return projectedDocument(piece.text) ? '' : piece.text\n }\n }\n return '';\n }).join('');\n }\n return '';\n}\n\nfunction messageAttachments(data: unknown): Array<{\n kind: 'image' | 'document'\n name?: string\n mediaType?: string\n attachmentId?: string\n width?: number\n height?: number\n truncated?: boolean\n}> {\n if (!data || typeof data !== 'object') return [];\n const obj = data as { content?: unknown; message?: unknown };\n if (obj.message && typeof obj.message === 'object') return messageAttachments(obj.message);\n if (!Array.isArray(obj.content)) return [];\n const attachments: Array<{\n kind: 'image' | 'document'\n name?: string\n mediaType?: string\n attachmentId?: string\n width?: number\n height?: number\n truncated?: boolean\n }> = []\n for (const part of obj.content) {\n if (!part || typeof part !== 'object') continue\n // The host normalizes uploaded bytes into an ImageAttachmentRef\n // (attachmentId/mediaType/bytes/width/height...); the id is what clients\n // need to read the image back through c2s.session.attachment.\n const block = part as {\n type?: string\n text?: unknown\n attachment?: {\n name?: unknown\n mediaType?: unknown\n attachmentId?: unknown\n width?: unknown\n height?: unknown\n }\n };\n if (block.type === 'text' && typeof block.text === 'string') {\n const document = projectedDocument(block.text)\n if (document) {\n attachments.push({\n kind: 'document',\n name: document.name,\n mediaType: document.mediaType,\n ...(document.truncated ? { truncated: true } : {}),\n })\n }\n continue\n }\n if (block.type !== 'image' || !block.attachment) continue\n const attachmentId = typeof block.attachment.attachmentId === 'string' && block.attachment.attachmentId.length > 0\n ? block.attachment.attachmentId\n : undefined;\n const width = typeof block.attachment.width === 'number' && Number.isFinite(block.attachment.width)\n ? block.attachment.width\n : undefined;\n const height = typeof block.attachment.height === 'number' && Number.isFinite(block.attachment.height)\n ? block.attachment.height\n : undefined;\n attachments.push({\n kind: 'image',\n ...(typeof block.attachment.name === 'string' ? { name: block.attachment.name } : {}),\n ...(typeof block.attachment.mediaType === 'string' ? { mediaType: block.attachment.mediaType } : {}),\n ...(attachmentId ? { attachmentId } : {}),\n ...(width !== undefined ? { width } : {}),\n ...(height !== undefined ? { height } : {}),\n })\n }\n return attachments\n}\n\nfunction attachmentProjection(data: unknown): { attachments?: ReturnType<typeof messageAttachments> } {\n const attachments = messageAttachments(data);\n return attachments.length > 0 ? { attachments } : {};\n}\n\n/** Extract reasoning (\"thinking\") text from assistant message payloads. */\nfunction messageThinking(data: unknown): string {\n if (!data || typeof data !== 'object') return '';\n const obj = data as { content?: unknown; message?: unknown };\n // Session events wrap the message: {turn, step, message: {role, content}}\n if (obj.message && typeof obj.message === 'object') return messageThinking(obj.message);\n return reasoningContent(obj.content);\n}\n\nfunction reasoningContent(content: unknown): string {\n if (!Array.isArray(content)) return '';\n return content.map(part => {\n if (part && typeof part === 'object') {\n const piece = part as { type?: string; text?: string };\n if (piece.type === 'reasoning' && typeof piece.text === 'string') return piece.text;\n }\n return '';\n }).join('');\n}\n\n/** Stream chunk type of an assistant/chunk payload ('' when unwrapped). */\nfunction chunkTypeOf(data: unknown): string {\n if (!data || typeof data !== 'object') return '';\n const obj = data as { chunk?: unknown };\n if (obj.chunk && typeof obj.chunk === 'object') {\n return String((obj.chunk as { type?: unknown }).type ?? '');\n }\n // Unwrapped payloads carry plain text deltas.\n return 'text-delta';\n}\n\nfunction chunkText(data: unknown): string {\n if (!data || typeof data !== 'object') return '';\n // StreamChunk shape: {turn, step, chunk: {type: 'text-delta'|'reasoning-delta', text}}\n const obj = data as { chunk?: unknown };\n if (obj.chunk && typeof obj.chunk === 'object') {\n const inner = obj.chunk as { type?: string; text?: string };\n if ((inner.type === 'text-delta' || inner.type === 'reasoning-delta') && typeof inner.text === 'string') {\n return inner.text;\n }\n return '';\n }\n const direct = data as { text?: unknown };\n return typeof direct.text === 'string' ? direct.text : '';\n}\n\nfunction summarizeArgs(raw: unknown): string {\n if (typeof raw !== 'string' || raw.length === 0) return '';\n try {\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n const parts: string[] = [];\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value === 'string') parts.push(key + '=' + truncate(value.replace(/\\s+/g, ' '), 60));\n }\n return truncate(parts.join(' '), 90);\n } catch {\n return truncate(raw, 90);\n }\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : text.slice(0, max - 1) + '…';\n}\n\nexport function projectHistory(events: Array<{ event: SessionEventLike; view?: unknown }>): MessageProjection[] {\n const messages: MessageProjection[] = [];\n const toolByCall = new Map<string, MessageProjection>();\n for (const entry of events) {\n const event = entry.event;\n const base = { seq: event.seq, ts: tsOf(event) };\n switch (event.type) {\n // DSH 0.1.5 (session format V3) records the system prompt in message\n // history as a native `system/message` surface event. It is\n // model-facing prompt prose, not conversation content — see\n // projectEvent for the rationale. Skip explicitly.\n case 'system/message':\n break;\n case 'user/message':\n messages.push({\n ...base,\n role: userRoleOf(event.data),\n text: messageText(event.data),\n ...attachmentProjection(event.data),\n ...(contextProjectionOf(event.data)),\n });\n break;\n case 'assistant/message': {\n const text = messageText(event.data);\n const thinking = messageThinking(event.data);\n if (!text.trim() && !thinking.trim()) break;\n messages.push({ ...base, role: 'assistant', text, ...(thinking ? { thinking } : {}) });\n break;\n }\n case 'tool/call': {\n const data = event.data as { name?: string; arguments?: string; callId?: string } | undefined;\n const row: MessageProjection = {\n ...base,\n role: 'tool',\n tool: { name: String(data?.name ?? 'tool'), state: 'running', summary: summarizeArgs(data?.arguments) },\n };\n messages.push(row);\n if (data?.callId) toolByCall.set(String(data.callId), row);\n break;\n }\n case 'tool/result': {\n const data = event.data as { callId?: string; message?: { content?: unknown }; error?: unknown } | undefined;\n const callId = data?.callId ? String(data.callId) : undefined;\n const target = callId ? toolByCall.get(callId) : undefined;\n const failed = data?.error !== undefined;\n const summary = failed ? '失败' : summarizeResult(data?.message?.content);\n if (target?.tool) {\n target.tool = { ...target.tool, state: failed ? 'error' : 'ok', summary };\n } else {\n messages.push({ ...base, role: 'tool', tool: { name: 'result', state: failed ? 'error' : 'ok', summary } });\n }\n break;\n }\n default:\n break;\n }\n }\n return canonicalSessionMessages(messages.map(limitMessageProjection));\n}\n\n/**\n * Enforce PROTOCOL.md's per-message 256 KB ceiling by UTF-8 JSON byte size.\n * Keep structural identity and attachment references intact; progressively\n * shorten human-readable fields until the serialized projection fits.\n */\nexport function limitMessageProjection(message: MessageProjection): MessageProjection {\n if (jsonBytes(message) <= MAX_MESSAGE_PROJECTION_BYTES) return message\n const next: MessageProjection = {\n ...message,\n ...(message.tool ? {\n tool: {\n ...message.tool,\n name: truncateUtf8(message.tool.name, 4 * 1024),\n summary: truncateUtf8(message.tool.summary, 64 * 1024),\n },\n } : {}),\n ...(message.attachments ? {\n attachments: message.attachments.slice(0, 16).map((attachment) => ({\n ...attachment,\n ...(attachment.name ? { name: truncateUtf8(attachment.name, 4 * 1024) } : {}),\n ...(attachment.mediaType ? { mediaType: truncateUtf8(attachment.mediaType, 256) } : {}),\n ...(attachment.attachmentId ? { attachmentId: truncateUtf8(attachment.attachmentId, 4 * 1024) } : {}),\n })),\n } : {}),\n ...(message.context ? {\n context: {\n ...(message.context.label ? { label: truncateUtf8(message.context.label, 8 * 1024) } : {}),\n ...(message.context.form ? { form: truncateUtf8(message.context.form, 256) } : {}),\n },\n } : {}),\n truncated: true,\n }\n\n const textFields: Array<{\n get: () => string\n set: (value: string) => void\n }> = []\n if (typeof next.text === 'string') textFields.push({\n get: () => next.text ?? '',\n set: (value) => { next.text = value },\n })\n if (typeof next.thinking === 'string') textFields.push({\n get: () => next.thinking ?? '',\n set: (value) => { next.thinking = value },\n })\n if (next.tool) textFields.push({\n get: () => next.tool?.summary ?? '',\n set: (value) => { if (next.tool) next.tool.summary = value },\n })\n if (next.context?.label) textFields.push({\n get: () => next.context?.label ?? '',\n set: (value) => { if (next.context) next.context.label = value },\n })\n\n while (jsonBytes(next) > MAX_MESSAGE_PROJECTION_BYTES) {\n const largest = textFields\n .map((field) => ({ field, bytes: Buffer.byteLength(field.get(), 'utf8') }))\n .sort((a, b) => b.bytes - a.bytes)[0]\n if (largest && largest.bytes > 0) {\n largest.field.set(truncateUtf8(largest.field.get(), Math.floor(largest.bytes / 2)))\n continue\n }\n if (next.attachments && next.attachments.length > 0) {\n next.attachments = next.attachments.slice(0, -1)\n continue\n }\n break\n }\n return next\n}\n\nfunction limitRealtimeText(data: { text: string; ts: number }): Record<string, unknown> {\n if (jsonBytes(data) <= MAX_MESSAGE_PROJECTION_BYTES) return data\n let text = data.text\n const next: Record<string, unknown> = { ...data, truncated: true }\n while (jsonBytes(next) > MAX_MESSAGE_PROJECTION_BYTES && text.length > 0) {\n text = truncateUtf8(text, Math.floor(Buffer.byteLength(text, 'utf8') / 2))\n next.text = text\n }\n return next\n}\n\nfunction jsonBytes(value: unknown): number {\n return Buffer.byteLength(JSON.stringify(value), 'utf8')\n}\n\nfunction truncateUtf8(value: string, maxBytes: number): string {\n if (maxBytes <= 0) return ''\n if (Buffer.byteLength(value, 'utf8') <= maxBytes) return value\n let low = 0\n let high = value.length\n while (low < high) {\n const mid = Math.ceil((low + high) / 2)\n const candidate = value.slice(0, mid)\n if (Buffer.byteLength(candidate, 'utf8') <= maxBytes) low = mid\n else high = mid - 1\n }\n let end = low\n if (end > 0 && /[\\uD800-\\uDBFF]/.test(value[end - 1]!)) end -= 1\n return value.slice(0, end)\n}\n\nfunction summarizeResult(content: unknown): string {\n const text = contentText(content).replace(/\\s+/g, ' ').trim();\n return truncate(text, 90);\n}\n","import { PromptDeliveryJournal, openDeliveryJournal } from './prompt-delivery.ts'\nimport { randomUUID } from 'node:crypto'\nimport type { Envelope, MessageProjection, NotifyCategory, PendingSnapshotPayload, PushNotification, SessionEventKind, SessionSummary, SessionTodoItem, SessionTodoStatus, SessionUsageStats } from './protocol.ts'\nimport {\n isSubagentRow,\n unwrapStreamItem,\n} from './host-api.ts'\nimport type {\n ApiProxyLike,\n BridgeSink,\n DirectoryListingLike,\n HostModelSelection,\n HostSessionModels,\n PendingResponseOutcome,\n PhoneSessionRow,\n PromptArgs,\n PushOutlet,\n SessionEventLike,\n SessionManagementResult,\n ModelBridgeResult,\n MuxFrameLike,\n WorkspaceViewLike,\n} from './host-api.ts'\nexport * from './host-api.ts'\nimport {\n MAX_MESSAGE_PROJECTION_BYTES,\n MAX_SESSION_PAGE_MESSAGES_BYTES,\n canonicalSessionMessages,\n limitMessageProjection,\n limitSessionPageMessages,\n messageText,\n projectEvent,\n projectHistory,\n} from './host-event-projection.ts'\nimport { documentPromptBlock, type PromptDocument } from './document-payload.ts'\nimport { pushScopeFor } from './connection-policy.ts'\n\nexport {\n MAX_MESSAGE_PROJECTION_BYTES,\n MAX_SESSION_PAGE_MESSAGES_BYTES,\n canonicalSessionMessages,\n limitMessageProjection,\n limitSessionPageMessages,\n projectEvent,\n projectHistory,\n} from './host-event-projection.ts'\n\ninterface PendingApproval {\n rpcId: string\n sessionId: string\n toolName: string\n reason: string\n}\n\ninterface PendingQuestion {\n rpcId: string\n sessionId: string\n questions: unknown\n}\n\nconst MAX_RING_DEFAULT = 2000;\n\n/**\n * Process-wide bridge state: session mirror, pending approvals/questions,\n * and the per-device replay ring. Consumes the in-process mux/host streams\n * and fans projected pushes out to every registered sink.\n */\nlet BRIDGE_SEQ = 0;\n\nexport class HostBridge {\n readonly id = ++BRIDGE_SEQ;\n private summaries = new Map<string, SessionSummary>()\n private approvals = new Map<string, PendingApproval>()\n private questions = new Map<string, PendingQuestion>()\n private archivedSessionIds = new Set<string>()\n private subagentSessionIds = new Set<string>()\n private sinks = new Set<BridgeSink>()\n private ring: Array<{ seq: number; type: string; payload: unknown }> = []\n private cursor = 0;\n private userReceiptSeq = 0;\n private abort = new AbortController();\n private started = false\n private disposed = false\n\n readonly promptDeliveries: PromptDeliveryJournal\n\n constructor(\n private readonly apiProxy: ApiProxyLike,\n private readonly historyBufferMax: number = MAX_RING_DEFAULT,\n deliveryJournalPath?: string,\n ) { this.promptDeliveries = openDeliveryJournal(deliveryJournalPath) }\n\n private pushOutlet: PushOutlet | undefined;\n private widgetFingerprint = ''\n\n /**\n * Wire the offline-push fan-out. Present ⇒ welcome advertises the `push`\n * capability and notify-worthy events are mirrored to APNs.\n */\n setPushOutlet(outlet: PushOutlet | undefined): void {\n this.pushOutlet = outlet;\n }\n\n get capabilities() {\n return {\n historyPaging: true,\n replay: true,\n approvals: true,\n questions: true,\n pendingSnapshot: true,\n promptDelivery: true,\n notifyAllCategories: true,\n models: typeof this.apiProxy.sessions.models === 'function' &&\n typeof this.apiProxy.sessions.selectModel === 'function',\n sessionManagement: typeof this.apiProxy.sessions.rename === 'function' &&\n typeof this.apiProxy.workspace?.archiveSession === 'function',\n projectSelection: typeof this.apiProxy.workspace?.list === 'function' &&\n typeof this.apiProxy.workspace?.create === 'function',\n push: this.pushOutlet?.isAvailable() === true,\n widgetPush: true,\n liveActivityPush: true,\n };\n }\n\n diagnostic(message: string): void {\n console.log('[deeppilot] ' + message);\n }\n\n currentCursor(): number {\n return this.cursor;\n }\n\n // ---------- sinks ----------\n\n addSink(sink: BridgeSink): void {\n this.sinks.add(sink);\n }\n\n removeSink(sink: BridgeSink): void {\n this.sinks.delete(sink);\n }\n\n /** Whether the ring still holds everything after the cursor. */\n canResumeFrom(cursor: number): boolean {\n const oldest = this.ring.length > 0 ? this.ring[0]!.seq : this.cursor + 1;\n // A cursor ahead of this process belongs to an older bridge lifetime.\n // Treat it as a gap instead of incorrectly claiming a successful resume.\n return cursor <= this.cursor && cursor + 1 >= oldest;\n }\n\n private sinkSessions = new Map<BridgeSink, Set<string>>();\n private lastAssistantText = new Map<string, string>();\n\n /** Mark a sink as actively viewing a session (suppresses its turn notifications). */\n markSinkOpen(sink: BridgeSink, sessionId: string): void {\n let set = this.sinkSessions.get(sink);\n if (!set) { set = new Set(); this.sinkSessions.set(sink, set); }\n set.add(sessionId);\n }\n\n markSinkClosed(sink: BridgeSink, sessionId: string): void {\n this.sinkSessions.get(sink)?.delete(sessionId);\n }\n\n dropSinkSessions(sink: BridgeSink): void {\n this.sinkSessions.delete(sink);\n }\n\n private isViewedBy(sink: BridgeSink, sessionId: string): boolean {\n return this.sinkSessions.get(sink)?.has(sessionId) ?? false;\n }\n\n /** F-9: when a notification-worthy event fires, mirror it to every\n * online device that is not currently viewing the session (the s2c.notify\n * frame counts toward the seq cursor and joins the replay ring per\n * PROTOCOL §6 + §7), then fan the same payload out to offline devices\n * holding an APNs token. */\n private emitNotify(args: {\n sessionId: string\n category: NotifyCategory\n title: string\n body: string\n notificationId: string\n }): void {\n if (this.subagentSessionIds.has(args.sessionId)) return;\n const body = args.body.length > 120 ? args.body.slice(0, 119) + '…' : args.body;\n this.record(\n 's2c.notify',\n {\n notificationId: args.notificationId,\n category: args.category,\n sessionId: args.sessionId,\n title: args.title,\n body,\n ts: Date.now(),\n },\n (sink) => this.isViewedBy(sink, args.sessionId),\n );\n this.fanOutPush({\n notificationId: args.notificationId,\n category: args.category,\n sessionId: args.sessionId,\n title: args.title,\n body,\n });\n }\n\n /** F-9: when a turn completes, notify every device not viewing the session. */\n private emitTurnCompletedNotify(sessionId: string, ok: boolean): void {\n if (this.subagentSessionIds.has(sessionId)) return;\n\n const row = this.summaries.get(sessionId);\n const title = ok ? '任务完成' : '任务异常结束';\n const body = this.lastAssistantText.get(sessionId) ?? row?.title ?? '';\n this.emitNotify({\n sessionId,\n category: ok ? 'turn.completed' : 'session.error',\n title,\n body,\n notificationId: 'n-' + (this.cursor + 1),\n });\n }\n\n /**\n * Mirror one notification-worthy event to offline devices. Fire-and-forget:\n * push failures must never block or break the WS data plane.\n */\n private fanOutPush(notification: PushNotification): void {\n try {\n this.pushOutlet?.fanOut(notification);\n } catch {\n // outlet misbehavior must not take down the bridge\n }\n }\n\n\n /** Remember the latest assistant text so notifications can quote it. */\n private captureAssistantText(sessionId: string, event: SessionEventLike): void {\n\n if (event.type !== 'assistant/message') return;\n\n const text = messageText(event.data).trim();\n\n if (text.length > 0) this.lastAssistantText.set(sessionId, text.slice(-160));\n }\n\n /**\n * Replay buffered pushes after the given cursor; false when the gap is\n * unrecoverable. Frames go to `target` only — replaying into every sink\n * duplicated the whole window onto devices that never asked for it.\n * Each frame is filtered by the S→C permission policy per sink, so a\n * reader without interactions.respond never gets the missed approval\n * frames back (R1/P2).\n */\n resumeFrom(cursor: number, target?: BridgeSink): boolean {\n const oldest = this.ring.length > 0 ? this.ring[0]!.seq : this.cursor + 1;\n if (cursor + 1 < oldest) return false;\n const receivers = target !== undefined ? [target] : [...this.sinks];\n for (const entry of this.ring) {\n if (entry.seq > cursor) {\n for (const sink of receivers) {\n const need = pushScopeFor(entry.type, entry.payload)\n if (need === undefined || !sink.canReceive(need)) continue\n sink.replay([entry]);\n }\n }\n }\n for (const sink of receivers) sink.replayDone();\n return true;\n }\n\n refreshLiveActivities(): void {\n try { this.pushOutlet?.liveActivityChanged?.(this.listSessions()) } catch { /* independent delivery */ }\n }\n\n private record(type: string, payload: unknown, except?: (sink: BridgeSink) => boolean): void {\n if (this.disposed) return\n if (type === 's2c.sessions.delta') this.refreshLiveActivities()\n if (type === 's2c.sessions.delta' || type.startsWith('s2c.pending.')) {\n const fingerprint = JSON.stringify([\n this.listSessions().map(({ id, title, status, lastActivityTs, todos, todoItems, pendingApproval, pendingQuestion }) =>\n ({ id, title, status, lastActivityTs, todos, todoItems, pendingApproval, pendingQuestion })),\n this.approvals.size, this.questions.size,\n ])\n if (fingerprint !== this.widgetFingerprint) {\n this.widgetFingerprint = fingerprint\n try { this.pushOutlet?.widgetChanged?.() } catch { /* push cannot break the data plane */ }\n }\n }\n this.cursor += 1;\n const entry = { seq: this.cursor, type, payload };\n this.ring.push(entry);\n if (this.ring.length > this.historyBufferMax) {\n this.ring.splice(0, this.ring.length - this.historyBufferMax);\n }\n const need = pushScopeFor(type, payload)\n for (const sink of this.sinks) {\n if (need === undefined || !sink.canReceive(need)) continue\n if (except && except(sink)) continue\n sink.push(type, payload, entry.seq);\n }\n }\n\n\n // ---------- lifecycle ----------\n\n /** Start consuming host + mux streams. Idempotent; aborts on dispose(). */\n start(): void {\n if (this.started || this.disposed) return\n this.started = true\n void this.runHostStream();\n void this.runMuxStream();\n void this.refreshSummaries();\n }\n\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.abort.abort();\n this.sinks.clear();\n this.sinkSessions.clear();\n this.pushOutlet = undefined;\n }\n\n private async runHostStream(): Promise<void> {\n try {\n for await (const item of this.apiProxy.events.host({ rpcId: randomUUID() }, this.abort.signal)) {\n const frame = unwrapStreamItem(item);\n this.onHostFrame(frame);\n }\n } catch {\n // stream ended (dispose or host shutdown); bridges degrade to RPC-only\n }\n }\n\n private async runMuxStream(): Promise<void> {\n try {\n for await (const item of this.apiProxy.events.mux({ rpcId: randomUUID() }, this.abort.signal)) {\n const frame = unwrapStreamItem(item);\n this.onMuxFrame(frame);\n }\n } catch {\n // ditto\n }\n }\n\n private onHostFrame(frame: MuxFrameLike): void {\n switch (frame.type) {\n case 'host/session-added':\n case 'host/session-removed':\n case 'host/workspace-changed':\n case 'host/workspace-removed':\n case 'host/workspace-order-changed':\n void this.refreshSummaries();\n break;\n case 'host/archived-sessions-changed': {\n const archived = (frame as { archivedSessionIds?: unknown }).archivedSessionIds\n if (Array.isArray(archived)) {\n this.archivedSessionIds = new Set(archived.map(String))\n }\n void this.refreshSummaries();\n break;\n }\n case 'host/session-status': {\n const p = frame as { sessionId?: string; running?: boolean };\n const row = this.summaries.get(String(p.sessionId));\n if (row && typeof p?.running === 'boolean') {\n row.status = p.running ? 'running' : 'idle';\n this.pushSummary(row);\n }\n break;\n }\n default:\n break;\n }\n }\n\n private onMuxFrame(frame: MuxFrameLike): void {\n switch (frame.type) {\n case 'session/event': {\n const event = frame.event as SessionEventLike | undefined;\n const sessionId = String(frame.sessionId ?? '');\n if (!event || !sessionId) break;\n this.noteActivity(sessionId, event);\n this.captureAssistantText(sessionId, event);\n const projection = projectEvent(sessionId, event);\n if (projection) {\n this.record('s2c.session.event', { sessionId, kind: projection.kind, seq: event.seq, data: projection.data });\n }\n if (projection?.kind === 'turn.end') {\n this.emitTurnCompletedNotify(sessionId, projection.data.ok === true);\n }\n break;\n }\n case 'session/projection': {\n const p = frame as { sessionId?: string; key?: string; value?: unknown };\n if (!p.sessionId) break;\n this.applyProjection(p.sessionId, String(p.key ?? ''), p.value);\n break;\n }\n case 'approval/requested': {\n const p = frame as { sessionId?: string; approvalId?: string; toolName?: string; reason?: string };\n if (!p.approvalId || !frame.rpcId) break;\n const toolName = String(p.toolName ?? 'tool');\n const summary = String(p.reason ?? '');\n const sessionId = String(p.sessionId ?? '');\n this.approvals.set(p.approvalId, {\n rpcId: frame.rpcId,\n sessionId,\n toolName,\n reason: summary,\n });\n this.record('s2c.pending.approval', {\n requestId: p.approvalId,\n sessionId,\n toolName,\n summary,\n riskLevel: riskOf(toolName),\n });\n this.emitNotify({\n sessionId,\n category: 'approval.required',\n title: '需要批准',\n body: toolName + ': ' + summary,\n notificationId: 'apr-' + p.approvalId,\n });\n this.bumpPendingFlags(sessionId);\n break;\n }\n case 'approval/resolved': {\n const p = frame as { approvalId?: string };\n if (!p.approvalId) break;\n const pending = this.approvals.get(p.approvalId);\n this.approvals.delete(p.approvalId);\n this.record('s2c.pending.cleared', { requestId: p.approvalId });\n if (pending) this.bumpPendingFlags(pending.sessionId);\n break;\n }\n case 'question/requested': {\n const p = frame as { sessionId?: string; questions?: unknown };\n if (!frame.rpcId) break;\n const requestId = 'q-' + frame.rpcId;\n const sessionId = String(p?.sessionId ?? '');\n this.questions.set(requestId, { rpcId: frame.rpcId, sessionId, questions: p?.questions });\n this.record('s2c.pending.question', { requestId, sessionId, questions: p?.questions ?? [] });\n this.emitNotify({\n sessionId,\n category: 'question.asked',\n title: '有问题需要回答',\n body: firstQuestionText(p?.questions),\n notificationId: requestId,\n });\n this.bumpPendingFlags(sessionId);\n break;\n }\n case 'question/resolved': {\n const p = frame as { questionRpcId?: string };\n if (!p.questionRpcId) break;\n const requestId = 'q-' + p.questionRpcId;\n const pending = this.questions.get(requestId);\n this.questions.delete(requestId);\n this.record('s2c.pending.cleared', { requestId });\n if (pending) this.bumpPendingFlags(pending.sessionId);\n break;\n }\n default:\n break;\n }\n }\n\n\n // ---------- session mirror ----------\n\n async refreshSummaries(): Promise<void> {\n try {\n const response = await this.apiProxy.sessions.list({ rpcId: randomUUID(), payload: {} });\n if (!response.result || !response.result.ok) {\n this.diagnostic('sessions.list rejected: ' + JSON.stringify(response.result ?? null).slice(0, 200));\n return;\n }\n let workspaces: WorkspaceViewLike[] = []\n const workspaceList = this.apiProxy.workspace?.list\n if (typeof workspaceList === 'function') {\n const workspaceResponse = await workspaceList.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: {},\n })\n if (workspaceResponse.result?.ok) {\n workspaces = workspaceResponse.result.value.items ?? []\n this.archivedSessionIds = new Set(\n (workspaceResponse.result.value.archivedSessionIds ?? []).map(String),\n )\n }\n }\n const previousIds = new Set(this.summaries.keys())\n const workspaceBySession = new Map<string, WorkspaceViewLike>()\n for (const workspace of workspaces) {\n for (const sessionId of workspace.sessionIds ?? []) {\n workspaceBySession.set(String(sessionId), workspace)\n }\n }\n const next = new Map<string, SessionSummary>();\n const subagentIds = new Set<string>();\n for (const row of response.result.value.items ?? []) {\n if (this.archivedSessionIds.has(row.sessionId)) continue\n if (isSubagentRow(row)) {\n subagentIds.add(row.sessionId);\n continue;\n }\n next.set(row.sessionId, toSummary(row, this.approvals, this.questions, workspaceBySession.get(row.sessionId)));\n }\n this.subagentSessionIds = subagentIds;\n this.summaries = next;\n const removedIds = [...previousIds].filter((id) => !next.has(id))\n // sessions.list is authoritative. This also removes assistant snippets\n // captured for child/subagent event streams that never enter summaries.\n for (const id of this.lastAssistantText.keys()) {\n if (!next.has(id)) this.lastAssistantText.delete(id)\n }\n this.record('s2c.sessions.delta', { upserted: [...next.values()], removedIds });\n } catch {\n // apiProxy absent or transient failure; keep last mirror\n }\n }\n\n /** Cold sessions may lack a title projection; fall back to first user text. */\n private deriveTitleFallback(sessionId: string, messages: MessageProjection[]): void {\n const row = this.summaries.get(sessionId);\n if (!row || row.title.length > 0) return;\n const firstUser = messages.find(m => m.role === 'user' && (m.text ?? '').trim().length > 0);\n if (!firstUser) return;\n row.title = firstUser!.text!.replace(/\\s+/g, ' ').trim().slice(0, 60);\n this.pushSummary(row);\n }\n\n private noteActivity(sessionId: string, event?: SessionEventLike): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n // Recency must reflect USER-VISIBLE milestones only: a new prompt moves\n // a session to the top and a finished turn settles it into place. Token\n // chunks / tool calls / per-step assistant messages fire constantly while\n // an agent works; counting them made concurrently running sessions fight\n // over the top slot in every recency-sorted list.\n switch (event?.type) {\n case 'user/message':\n case 'turn/start':\n case 'turn/end':\n break;\n default:\n return;\n }\n row.lastActivityTs = Date.now();\n this.pushSummary(row);\n }\n\n private applyProjection(sessionId: string, key: string, value: unknown): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n if (key === 'title') {\n row.title = typeof value === 'string' ? value : '';\n } else if (key === 'todos') {\n const items = Array.isArray(value) ? value as Array<{ content?: unknown; status?: unknown }> : null;\n const sanitized = sanitizeTodoItems(items);\n row.todoItems = sanitized.length > 0 ? sanitized : null;\n row.todos = sanitized.length > 0\n ? { done: sanitized.filter(i => i.status === 'completed').length, total: sanitized.length }\n : null;\n } else if (key === 'sessionListMetadata') {\n const meta = value as { lastPromptAt?: number } | null;\n if (meta?.lastPromptAt) row.lastActivityTs = Math.max(row.lastActivityTs, meta.lastPromptAt);\n } else if (key === 'sessionStats' || key === 'tokenUsage') {\n // Host usage projections arrive as two independent keys over the mux\n // stream; merge each patch into the summary's stats snapshot so a\n // sessionStats-only or tokenUsage-only host still shows partial data.\n const patch = sanitizeUsageStatsPatch(key, value);\n if (!patch) return;\n row.stats = { ...emptyUsageStats, ...(row.stats ?? {}), ...patch };\n } else {\n return;\n }\n this.pushSummary(row);\n }\n\n private bumpPendingFlags(sessionId: string): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n let approval = false;\n for (const pending of this.approvals.values()) {\n if (pending.sessionId === sessionId) approval = true;\n }\n let question = false;\n for (const pending of this.questions.values()) {\n if (pending.sessionId === sessionId) question = true;\n }\n row.pendingApproval = approval;\n row.pendingQuestion = question;\n this.pushSummary(row);\n }\n\n private pushSummary(row: SessionSummary): void {\n this.record('s2c.sessions.delta', { upserted: [row], removedIds: [] });\n }\n\n listSessions(): SessionSummary[] {\n return [...this.summaries.values()].sort((a, b) => b.lastActivityTs - a.lastActivityTs);\n }\n\n /**\n * Complete transient interaction state. Unlike the replay ring, this remains\n * authoritative after a long disconnect and is rehydrated by apiProxy's mux\n * stream when the bridge itself restarts.\n */\n pendingSnapshot(): PendingSnapshotPayload {\n return {\n approvals: [...this.approvals.entries()].map(([requestId, pending]) => ({\n requestId,\n sessionId: pending.sessionId,\n toolName: pending.toolName,\n summary: pending.reason,\n riskLevel: riskOf(pending.toolName),\n })),\n questions: [...this.questions.entries()].map(([requestId, pending]) => ({\n requestId,\n sessionId: pending.sessionId,\n questions: Array.isArray(pending.questions)\n ? pending.questions as PendingSnapshotPayload['questions'][number]['questions']\n : [],\n })),\n };\n }\n\n // ---------- data operations ----------\n\n /** Tail history for an opened session; pushes s2c.session.tail to the sink. */\n async openSession(sink: BridgeSink, sessionId: string, tailCount: number): Promise<boolean> {\n try {\n const response = await this.apiProxy.sessions.history({\n rpcId: randomUUID(),\n payload: { sessionId, maxMessages: clampTail(tailCount) },\n });\n if (!response.result || !response.result.ok) return false;\n const result = response.result.value;\n const projected = projectHistory(result.events ?? []);\n const page = limitSessionPageMessages(projected);\n const messages = page.messages;\n const oldestSeq = messages.length > 0 ? messages[0]!.seq : 0;\n sink.push('s2c.session.tail', {\n sessionId,\n messages,\n oldestSeq,\n hasMore: Boolean(result.hasMore) || page.dropped > 0,\n });\n this.deriveTitleFallback(sessionId, messages);\n return true;\n } catch {\n return false;\n }\n }\n\n async historyPage(\n sessionId: string,\n beforeSeq: number,\n limit: number,\n ): Promise<{ sessionId: string; messages: MessageProjection[]; hasMore: boolean } | null> {\n try {\n const response = await this.apiProxy.sessions.history({\n rpcId: randomUUID(),\n payload: { sessionId, beforeSeq, maxMessages: clampTail(limit) },\n });\n if (!response.result || !response.result.ok) return null;\n const result = response.result.value;\n // Some host versions include the boundary event even though beforeSeq\n // is exclusive. Enforce the phone protocol here so a client can never\n // request and append the same page indefinitely.\n const projected = projectHistory(result.events ?? [])\n .filter((message) => message.seq < beforeSeq);\n const page = limitSessionPageMessages(projected);\n return {\n sessionId,\n messages: page.messages,\n // An empty exclusive page cannot advance beforeSeq. Advertising more\n // here would make the client request the same boundary forever.\n hasMore: page.messages.length > 0 && (Boolean(result.hasMore) || page.dropped > 0),\n };\n } catch {\n return null;\n }\n }\n\n /** Result of one attachment read-back for the phone. */\n async attachmentData(\n sessionId: string,\n attachmentId: string,\n ): Promise<{ mediaType?: string; data: string } | null> {\n const read = this.apiProxy.sessions.attachment\n if (typeof read !== 'function') return null;\n try {\n const response = await read.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId, attachmentId },\n });\n if (!response.result || !response.result.ok) return null;\n const data = response.result.value.data;\n if (typeof data !== 'string' || data.length === 0) return null;\n return {\n ...(typeof response.result.value.attachment?.mediaType === 'string'\n ? { mediaType: response.result.value.attachment.mediaType as string }\n : {}),\n data,\n };\n } catch {\n return null;\n }\n }\n\n async sessionModels(sessionId: string): Promise<ModelBridgeResult<HostSessionModels>> {\n const models = this.apiProxy.sessions.models\n if (typeof models !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'model catalog unavailable on this host version' }\n }\n try {\n const response = await models.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'model catalog returned no result' }\n if (!response.result.ok) return hostModelError(response.result.error)\n return { ok: true, value: projectSessionModels(response.result.value) }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async selectSessionModel(\n sessionId: string,\n selection: HostModelSelection,\n ): Promise<ModelBridgeResult<HostModelSelection>> {\n const selectModel = this.apiProxy.sessions.selectModel\n if (typeof selectModel !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'model selection unavailable on this host version' }\n }\n try {\n const response = await selectModel.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: {\n sessionId,\n provider: selection.provider,\n model: selection.model,\n ...(selection.reasoningEffort ? { reasoningEffort: selection.reasoningEffort } : {}),\n },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'model selection returned no result' }\n if (!response.result.ok) return hostModelError(response.result.error)\n return { ok: true, value: { ...response.result.value.selected } }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async renameSession(sessionId: string, title: string): Promise<SessionManagementResult<string>> {\n const rename = this.apiProxy.sessions.rename\n if (typeof rename !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session rename unavailable on this host version' }\n }\n try {\n const response = await rename.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId, title },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session rename returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n const acceptedTitle = String(response.result.value.title)\n const row = this.summaries.get(sessionId)\n if (row) {\n row.title = acceptedTitle\n this.pushSummary(row)\n }\n return { ok: true, value: acceptedTitle }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async archiveSession(sessionId: string): Promise<SessionManagementResult<true>> {\n const archive = this.apiProxy.workspace?.archiveSession\n if (typeof archive !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session archive unavailable on this host version' }\n }\n try {\n const response = await archive.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session archive returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n this.archivedSessionIds = new Set(\n (response.result.value.archivedSessionIds ?? []).map(String),\n )\n this.summaries.delete(sessionId)\n this.lastAssistantText.delete(sessionId)\n this.record('s2c.sessions.delta', { upserted: [], removedIds: [sessionId] })\n return { ok: true, value: true }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async cancelSession(sessionId: string): Promise<SessionManagementResult<true>> {\n const cancel = this.apiProxy.sessions.cancel\n if (typeof cancel !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session cancel unavailable on this host version' }\n }\n try {\n const response = await cancel.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session cancel returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: true }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async listWorkspaces(): Promise<SessionManagementResult<Array<{\n id: string; title: string; path: string; sessionIds: string[]\n }>>> {\n const list = this.apiProxy.workspace?.list\n if (typeof list !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'workspace list unavailable on this host version' }\n }\n try {\n const response = await list.call(this.apiProxy.workspace, { rpcId: randomUUID(), payload: {} })\n if (!response.result) return { ok: false, kind: 'internal', message: 'workspace list returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: (response.result.value.items ?? []).map(projectWorkspace) }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async createWorkspace(path: string): Promise<SessionManagementResult<{\n workspace: { id: string; title: string; path: string; sessionIds: string[] }; created: boolean\n }>> {\n const create = this.apiProxy.workspace?.create\n if (typeof create !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'workspace create unavailable on this host version' }\n }\n try {\n const response = await create.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: { path },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'workspace create returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n await this.refreshSummaries()\n return {\n ok: true,\n value: { workspace: projectWorkspace(response.result.value.workspace), created: response.result.value.created === true },\n }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async listDirectory(path?: string): Promise<SessionManagementResult<DirectoryListingLike>> {\n const list = this.apiProxy.host?.listDirectory\n if (typeof list !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'directory browsing unavailable on this host version' }\n }\n try {\n const response = await list.call(this.apiProxy.host, {\n rpcId: randomUUID(),\n payload: path && path.trim().length > 0 ? { path } : {},\n }, this.abort.signal)\n if (!response.result) return { ok: false, kind: 'internal', message: 'directory list returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: response.result.value }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async pickDirectory(): Promise<SessionManagementResult<string | null>> {\n const pick = this.apiProxy.host?.pickDirectory\n if (typeof pick !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'native directory picker unavailable on this host version' }\n }\n try {\n const response = await pick.call(this.apiProxy.host, {\n rpcId: randomUUID(),\n payload: {},\n }, this.abort.signal)\n if (!response.result) return { ok: false, kind: 'internal', message: 'directory picker returned no result' }\n if (!response.result.ok) return hostSessionManagementError(response.result.error)\n return { ok: true, value: response.result.value.path }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n /** Create a fresh blank session in an existing workspace or legacy cwd. */\n async createSession(destination: { workspaceId?: string; cwd?: string } = {}): Promise<string | null> {\n try {\n const response = await this.apiProxy.sessions.create({\n rpcId: randomUUID(),\n payload: {\n ...(destination.workspaceId?.trim() ? { workspaceId: destination.workspaceId.trim() } : {}),\n ...(destination.cwd?.trim() ? { cwd: destination.cwd.trim() } : {}),\n },\n });\n if (!response.result || !response.result.ok) return null;\n const sessionId = response.result.value.sessionId;\n await this.refreshSummaries();\n return sessionId;\n } catch {\n return null;\n }\n }\n\n async sendPrompt(\n sessionId: string,\n text: string,\n images: Array<{ mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; data: string; name?: string }> = [],\n documents: PromptDocument[] = [],\n ): Promise<SessionManagementResult<number>> {\n try {\n const content: PromptArgs['content'] = [];\n if (text.trim().length > 0) content.push({ type: 'text', text });\n for (const image of images) content.push({ type: 'image', ...image });\n for (const document of documents) content.push({ type: 'text', text: documentPromptBlock(document) });\n const response = await this.apiProxy.sessions.prompt({\n rpcId: randomUUID(),\n payload: {\n sessionId,\n mode: 'queue',\n content,\n clientTimeZone: localTimeZone(),\n },\n });\n if (!response.result) return { ok: false, kind: 'internal', message: 'prompt returned no result' };\n // Preserve the host's error kind so the phone can tell \"retry later\"\n // (E_BUSY) from \"session is gone\" (E_NOT_FOUND) instead of mapping\n // every failure onto E_BUSY.\n if (!response.result.ok) return hostSessionManagementError(response.result.error);\n const row = this.summaries.get(sessionId);\n if (row) {\n row.lastActivityTs = Date.now();\n this.pushSummary(row);\n }\n this.userReceiptSeq += 1;\n return { ok: true, value: this.userReceiptSeq };\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) };\n }\n }\n\n\n async respondApproval(\n requestId: string,\n decision: 'allow' | 'deny',\n reason?: string,\n ): Promise<PendingResponseOutcome> {\n const pending = this.approvals.get(requestId);\n if (!pending) return { ok: false, reason: 'not-pending' };\n // Claim the pending entry before responding: a second phone (or a double\n // tap) must not fire another client-response for the same rpcId while the\n // resolved frame is still in flight.\n this.approvals.delete(requestId);\n const outcome = decision === 'allow' ? 'allowed-once' : 'rejected';\n const denialReason = typeof reason === 'string' ? reason.trim().slice(0, 500) : '';\n try {\n const receipt = await this.apiProxy.respond({\n type: 'client-response',\n rpcId: pending.rpcId,\n result: {\n ok: true,\n value: {\n sessionId: pending.sessionId,\n approvalId: requestId,\n outcome,\n // PROTOCOL v2: a deny may carry the user's explanation so the\n // model can adjust course instead of blindly retrying.\n ...(denialReason.length > 0 ? { reason: denialReason } : {}),\n },\n },\n });\n const accepted = Boolean(receipt?.accepted);\n if (!accepted) {\n const failure = receiptFailureReason(receipt);\n // Restore only what the user can retry: `not-pending` means the host\n // already settled the request, and restoring would strand a ghost\n // entry that no future resolved frame will ever clear.\n if (failure !== 'not-pending' && !this.approvals.has(requestId)) {\n this.approvals.set(requestId, pending);\n }\n return { ok: false, reason: failure };\n }\n // The claim above removed the entry, so the upcoming approval/resolved\n // frame finds nothing left to bump — refresh the summary flags here or\n // the session badge stays \"pending\" until an unrelated refresh.\n this.bumpPendingFlags(pending.sessionId);\n return { ok: true };\n } catch {\n // Transport-level failure: give the request back so the user can retry.\n if (!this.approvals.has(requestId)) this.approvals.set(requestId, pending);\n return { ok: false, reason: 'transport' };\n }\n }\n\n async respondQuestion(requestId: string, answers: unknown): Promise<PendingResponseOutcome> {\n const pending = this.questions.get(requestId);\n if (!pending) return { ok: false, reason: 'not-pending' };\n this.questions.delete(requestId);\n try {\n const receipt = await this.apiProxy.respond({\n type: 'client-response',\n rpcId: pending.rpcId,\n result: { ok: true, value: { sessionId: pending.sessionId, answer: { answers: normalizeAnswerItems(answers, pending.questions) } } },\n });\n const accepted = Boolean(receipt?.accepted);\n if (!accepted) {\n const failure = receiptFailureReason(receipt);\n // Same ghost-entry rule as approvals: `not-pending` is final, never\n // restore — the host has no record left to resolve against.\n if (failure !== 'not-pending' && !this.questions.has(requestId)) {\n this.questions.set(requestId, pending);\n }\n return { ok: false, reason: failure };\n }\n // Mirror the approval path: the claimed entry cannot bump flags when the\n // resolved frame arrives, so recompute them right after acceptance.\n this.bumpPendingFlags(pending.sessionId);\n return { ok: true };\n } catch {\n if (!this.questions.has(requestId)) this.questions.set(requestId, pending);\n return { ok: false, reason: 'transport' };\n }\n }\n}\n\n/**\n * The host validates question answers strictly (core dsh-user-questions via\n * apiProxy): a present-but-empty `custom` fails `matchesQuestions`, and a\n * single-select question rejects `custom` combined with a selection. Clients\n * may send lenient shapes (the phone historically always attached\n * `\"custom\": \"\"`, which made EVERY option-only answer fail), so normalize to\n * exactly what the host accepts before forwarding.\n */\nexport function normalizeAnswerItems(\n raw: unknown,\n questions?: unknown,\n): Array<{ id: string; selected: string[]; custom?: string }> {\n if (!Array.isArray(raw)) return [];\n const askedById = new Map<string, { multiSelect?: unknown }>();\n if (Array.isArray(questions)) {\n for (const q of questions) {\n if (typeof q === 'object' && q !== null && typeof (q as { id?: unknown }).id === 'string') {\n askedById.set((q as { id: string }).id, q as { multiSelect?: unknown });\n }\n }\n }\n const items: Array<{ id: string; selected: string[]; custom?: string }> = [];\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue;\n const r = entry as { id?: unknown; selected?: unknown; custom?: unknown };\n if (typeof r.id !== 'string') continue;\n // De-duplicate while preserving order; duplicate labels are rejected by the host.\n const selected = [...new Set(\n Array.isArray(r.selected) ? r.selected.filter((s): s is string => typeof s === 'string') : [],\n )];\n const customText = typeof r.custom === 'string' ? r.custom : '';\n let custom: string | undefined;\n if (customText.trim().length > 0) custom = customText;\n // A single-select answer must be either options or free text, never both.\n if (custom !== undefined && selected.length > 0 && askedById.get(r.id)?.multiSelect !== true) {\n custom = undefined;\n }\n items.push({ id: r.id, selected, ...(custom !== undefined ? { custom } : {}) });\n }\n return items;\n}\n\n/** Map an apiProxy respond receipt onto the failure vocabulary. */\nfunction receiptFailureReason(receipt: { accepted: boolean; reason?: string } | undefined):\n 'not-pending' | 'bad-response' {\n return receipt?.reason === 'not-pending' ? 'not-pending' : 'bad-response';\n}\n\n// ---------- projection helpers ----------\n\nfunction clampTail(n: number): number {\n if (!Number.isFinite(n)) return 100;\n return Math.max(10, Math.min(500, Math.floor(n)));\n}\n\nfunction localTimeZone(): string | undefined {\n try {\n return new Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction riskOf(toolName: string): 'read' | 'write' | 'destructive' {\n if (/bash|pwsh|terminal/.test(toolName)) return 'write';\n if (/edit|write|str_replace|create/.test(toolName)) return 'write';\n if (/delete|remove|kill/.test(toolName)) return 'destructive';\n return 'read';\n}\n\n/** First question's text for the push banner; the questions payload shape is\n * host-version dependent, so extract defensively. */\nexport function firstQuestionText(questions: unknown): string {\n if (!Array.isArray(questions) || questions.length === 0) return 'Agent 等待你的输入';\n const first = questions[0] as { question?: unknown } | undefined;\n const text = String(first?.question ?? '').trim();\n return text || 'Agent 等待你的输入';\n}\n\nconst TODO_STATUSES = new Set(['pending', 'in_progress', 'completed']);\n\n/** Validate a host todo projection once; progress counts and the full\n * checklist both derive from this sanitized list so they never disagree. */\nfunction sanitizeTodoItems(items: Array<{ content?: unknown; status?: unknown }> | null): SessionTodoItem[] {\n if (!items) return [];\n return items\n .map(i => ({ content: String(i.content ?? '').trim(), status: String(i.status ?? '') }))\n .filter(i => i.content.length > 0 && TODO_STATUSES.has(i.status))\n .slice(0, 100)\n .map(i => ({ content: i.content, status: i.status as SessionTodoStatus }));\n}\n\n/** Zero-value stats snapshot used as the merge base for partial patches. */\nconst emptyUsageStats: SessionUsageStats = {\n turns: 0,\n steps: 0,\n llmMs: 0,\n toolMs: 0,\n ttftMs: 0,\n ttftSteps: 0,\n decodeMs: 0,\n decodeTokens: 0,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n};\n\n/** Coerce one host counter to a non-negative integer; junk becomes 0. */\nfunction usageCounter(value: unknown): number {\n const n = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(n) || n < 0) return 0;\n return Math.floor(n);\n}\n\nconst SESSION_STATS_COUNTERS = [\n 'turns', 'steps', 'llmMs', 'toolMs',\n 'ttftMs', 'ttftSteps', 'decodeMs', 'decodeTokens',\n] as const;\n\nconst TOKEN_USAGE_COUNTERS = [\n 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens',\n] as const;\n\n/** Sanitize one `sessionStats` / `tokenUsage` projection value into the wire\n * stats fields; undefined when the payload carries nothing readable. Host\n * field names differ between the two projections (tokenUsage reports\n * `uncachedInputTokens`, the wire mirrors it as `inputTokens`). */\nfunction sanitizeUsageStatsPatch(key: string, value: unknown): Partial<SessionUsageStats> | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const raw = value as Record<string, unknown>;\n const patch: Partial<SessionUsageStats> = {};\n if (key === 'sessionStats') {\n for (const field of SESSION_STATS_COUNTERS) {\n if (field in raw) patch[field] = usageCounter(raw[field]);\n }\n } else {\n if ('uncachedInputTokens' in raw) patch.inputTokens = usageCounter(raw.uncachedInputTokens);\n for (const field of TOKEN_USAGE_COUNTERS) {\n if (field in raw) patch[field] = usageCounter(raw[field]);\n }\n }\n return Object.keys(patch).length > 0 ? patch : undefined;\n}\n\n/** Combine one session's `sessionStats` + `tokenUsage` projection values into\n * a complete wire stats object; undefined when neither carries anything. */\nfunction usageStatsOf(sessionStats: unknown, tokenUsage: unknown): SessionUsageStats | undefined {\n const patches = [\n sanitizeUsageStatsPatch('sessionStats', sessionStats),\n sanitizeUsageStatsPatch('tokenUsage', tokenUsage),\n ].filter((patch): patch is Partial<SessionUsageStats> => patch !== undefined);\n if (patches.length === 0) return undefined;\n return Object.assign({}, emptyUsageStats, ...patches);\n}\n\nfunction toSummary(\n row: PhoneSessionRow,\n approvals: Map<string, PendingApproval>,\n questions: Map<string, PendingQuestion>,\n workspace?: WorkspaceViewLike,\n): SessionSummary {\n const values = row.projections?.values ?? {};\n const todos = Array.isArray(values.todos) ? values.todos as Array<{ content?: unknown; status?: unknown }> : null;\n let pendingApproval = false;\n for (const pending of approvals.values()) {\n if (pending.sessionId === row.sessionId) pendingApproval = true;\n }\n let pendingQuestion = false;\n for (const pending of questions.values()) {\n if (pending.sessionId === row.sessionId) pendingQuestion = true;\n }\n const cwd = typeof row.cwd === 'string' ? row.cwd : '';\n const label = workspace?.title ?? (cwd ? cwd.split('/').filter(Boolean).pop() : undefined);\n const todoItems = sanitizeTodoItems(todos);\n const stats = usageStatsOf(values.sessionStats, values.tokenUsage);\n return {\n id: row.sessionId,\n title: typeof values.title === 'string' ? values.title : '',\n // A blank session has never run a turn, and the running flag above\n // already covers the live case. Reporting `unknown` here made the phone\n // treat the composer as \"still syncing\" forever: nothing ever converges\n // the state back because the first prompt is exactly what the disabled\n // button cannot send. Idle is truthful for every non-running blank row.\n status: row.running ? 'running' : 'idle',\n lastActivityTs: Number(row.updatedAt ?? Date.now()),\n todos: todoItems.length > 0\n ? {\n done: todoItems.filter(i => i.status === 'completed').length,\n total: todoItems.length,\n }\n : null,\n todoItems: todoItems.length > 0 ? todoItems : null,\n pendingApproval,\n pendingQuestion,\n ...(stats ? { stats } : {}),\n workspaceLabel: label ?? null,\n workspaceId: workspace?.workspaceId ?? null,\n workspacePath: workspace?.path ?? (cwd || null),\n };\n}\n\nfunction projectWorkspace(workspace: WorkspaceViewLike): {\n id: string; title: string; path: string; sessionIds: string[]\n} {\n return {\n id: String(workspace.workspaceId),\n title: String(workspace.title),\n path: String(workspace.path),\n sessionIds: (workspace.sessionIds ?? []).map(String),\n }\n}\n\n/** Project one raw session event into a protocol push, when it maps to one. */\n\nfunction hostModelError(error: { code: string; message?: string }): ModelBridgeResult<never> {\n const message = error.message ?? error.code\n switch (error.code) {\n case 'session-not-found':\n return { ok: false, kind: 'not-found', message }\n case 'agent-busy':\n case 'session-conflict':\n return { ok: false, kind: 'busy', message }\n case 'model-unavailable':\n return { ok: false, kind: 'unavailable', message }\n default:\n return { ok: false, kind: 'internal', message }\n }\n}\n\nfunction hostSessionManagementError(\n error: { code: string; message?: string },\n): SessionManagementResult<never> {\n const message = error.message ?? error.code\n switch (error.code) {\n case 'session-not-found':\n return { ok: false, kind: 'not-found', message }\n case 'agent-busy':\n case 'session-conflict':\n return { ok: false, kind: 'busy', message }\n case 'title-invalid':\n case 'workspace-invalid-path':\n case 'workspace-name-conflict':\n case 'directory-unreadable':\n case 'directory-exists':\n case 'directory-create-failed':\n return { ok: false, kind: 'invalid', message }\n case 'directory-picker-unavailable':\n return { ok: false, kind: 'unsupported', message }\n case 'workspace-not-found':\n return { ok: false, kind: 'not-found', message }\n default:\n return { ok: false, kind: 'internal', message }\n }\n}\n\nfunction projectSessionModels(value: HostSessionModels): HostSessionModels {\n return {\n current: {\n provider: String(value.current.provider),\n model: String(value.current.model),\n ...(value.current.reasoningEffort ? { reasoningEffort: String(value.current.reasoningEffort) } : {}),\n },\n routable: value.routable === true,\n groups: (value.groups ?? []).map((group) => ({\n id: String(group.id),\n name: String(group.name),\n models: (group.models ?? []).map((model) => ({\n id: String(model.id),\n name: String(model.name),\n ...(model.description ? { description: String(model.description) } : {}),\n ...(model.reasoning ? {\n reasoning: {\n efforts: (model.reasoning.efforts ?? []).map((effort) => ({\n id: String(effort.id),\n name: String(effort.name),\n ...(effort.description ? { description: String(effort.description) } : {}),\n })),\n ...(model.reasoning.defaultEffort\n ? { defaultEffort: String(model.reasoning.defaultEffort) }\n : {}),\n },\n } : {}),\n })),\n })),\n failures: (value.failures ?? []).map((failure) => ({\n id: String(failure.id),\n name: String(failure.name),\n message: String(failure.message),\n })),\n }\n}\n\n/** Project a history page (raw events) into MessageProjection rows. */\n","/**\n * Resident DSH 0.1.2-alpha.3 Remote Events client for phone interactions.\n *\n * The Host-side `approval/request` and `user-questions/request` events are\n * owned once by DSH API Remotes. API Gateway then fans each pending waterfall\n * out to every connected Client and settles the first result. DeepPilot joins\n * that official Client plane in-process instead of registering a competing\n * Host waterfall listener or replacing the official Web composer.\n */\nimport { Context } from '@deepseek-ai/cordis'\nimport * as Cordis from '@deepseek-ai/cordis'\n\ninterface FetchHandlerLike {\n fetch(request: Request): Promise<Response>\n}\n\ninterface HostConnectionLike {\n createSharedFetchHandler(channel: '/api'): FetchHandlerLike\n}\n\ninterface HostGatewayLike {\n wireStream: {\n open(endpoint: string, payload: unknown, signal: AbortSignal): Promise<AsyncIterable<unknown>>\n }\n}\n\ninterface ClientTransportHooksLike {\n fetch(input: URL, init: RequestInit): Promise<Response>\n openStream(endpoint: string, payload: unknown, signal: AbortSignal): AsyncIterable<unknown>\n ownsHost: true\n}\n\ninterface ClientRemoteLike {\n $on(event: string, listener: (this: Context, request: any, next: () => Promise<unknown>) => unknown): () => void\n}\n\ninterface ClientTypertLike {\n contexts: {\n registerClient(key: string, adapter: {\n identity(candidate: Context): string | undefined\n resolve(identity: string): Context\n }): () => void\n }\n}\n\ninterface ClientPluginModule {\n apply(ctx: Context): void\n}\n\nexport interface RemoteApprovalRequest {\n toolName?: string\n callId?: string\n reason?: string\n signal?: AbortSignal\n}\n\nexport interface RemoteQuestionRequest {\n questions?: unknown\n signal?: AbortSignal\n}\n\nexport interface Dsh012RemoteInteractionHandlers {\n approval(sessionId: string, request: RemoteApprovalRequest, next: () => Promise<unknown>): unknown\n question(sessionId: string, request: RemoteQuestionRequest, next: () => Promise<unknown>): unknown\n}\n\ntype TransportGlobal = typeof globalThis & {\n __DSH_TRANSPORT__?: ClientTransportHooksLike\n}\n\ninterface ClientBundleDefinition {\n id: string\n factory(require: (id: string) => unknown): unknown\n}\n\ntype ClientBundleWindow = {\n __ModuleLoader__: {\n load(definition: ClientBundleDefinition): void\n }\n}\n\ntype LoaderGlobal = {\n window?: ClientBundleWindow\n}\n\ninterface ClientFaces {\n typert: ClientPluginModule\n connection: ClientPluginModule\n gateway: ClientPluginModule\n}\n\nlet clientFaces: Promise<ClientFaces> | undefined\n\n/**\n * Load DSH's browser-distributed Client faces into a tiny Host-side module\n * table. Published `lib/client.js` files register with `window.__ModuleLoader__`\n * rather than exporting ESM values, so a normal Node import cannot consume\n * them. The shim runs only while the three official bundles register; their\n * apply functions then operate against a non-browser Cordis Context.\n */\nfunction pluginModule(value: unknown, specifier: string): ClientPluginModule {\n if (typeof value !== 'object' || value === null) throw new Error(`${specifier} Client bundle returned no exports`)\n const record = value as Record<string, unknown>\n if (typeof record.apply !== 'function') throw new Error(`${specifier} has no Client apply() export`)\n return value as unknown as ClientPluginModule\n}\n\nasync function loadClientFaces(): Promise<ClientFaces> {\n clientFaces ??= (async () => {\n const modules = new Map<string, unknown>([['@deepseek-ai/cordis', Cordis]])\n const loaderGlobal = globalThis as unknown as LoaderGlobal\n const previousWindow = loaderGlobal.window\n loaderGlobal.window = {\n __ModuleLoader__: {\n load: definition => {\n const exports = definition.factory((id) => {\n if (!modules.has(id)) throw new Error(`resident DSH Client cannot resolve ${JSON.stringify(id)}`)\n return modules.get(id)\n })\n modules.set(definition.id, exports)\n },\n },\n }\n try {\n // Use variable specifiers to preserve DSH's Host/Client TypeScript face\n // split; static imports would merge incompatible Context declarations.\n for (const specifier of [\n '@deepseek-ai/dsh-typert-registry/client',\n '@deepseek-ai/dsh-client-connection/client',\n '@deepseek-ai/dsh-api-gateway/client',\n ]) await import(specifier)\n } finally {\n if (previousWindow === undefined) delete loaderGlobal.window\n else loaderGlobal.window = previousWindow\n }\n return {\n typert: pluginModule(modules.get('@deepseek-ai/dsh-typert-registry'), '@deepseek-ai/dsh-typert-registry/client'),\n connection: pluginModule(modules.get('@deepseek-ai/dsh-client-connection'), '@deepseek-ai/dsh-client-connection/client'),\n gateway: pluginModule(modules.get('@deepseek-ai/dsh-api-gateway'), '@deepseek-ai/dsh-api-gateway/client'),\n }\n })()\n return clientFaces\n}\n\nconst agentScopeKey = Symbol('deeppilot.dsh-client.agent-scope')\n\ntype AgentContext = Context & { [agentScopeKey]?: string }\n\nfunction scopeOf(ctx: Context): string | undefined {\n return (ctx as AgentContext)[agentScopeKey]\n}\n\nfunction createAgentScope(ctx: Context, identity: string): Context {\n const fiber = ctx.plugin(function deeppilotAgentScope() {})\n return fiber.ctx.extend({\n [agentScopeKey]: identity,\n [Context.filter](listenerCtx: Context) {\n const listenerIdentity = scopeOf(listenerCtx)\n return listenerIdentity === undefined || listenerIdentity === identity\n },\n })\n}\n\nfunction inProcessStream(\n gateway: HostGatewayLike,\n endpoint: string,\n payload: unknown,\n signal: AbortSignal,\n): AsyncIterable<unknown> {\n return (async function* () {\n const source = await gateway.wireStream.open(endpoint, payload, signal)\n yield* source\n })()\n}\n\n/**\n * Start one headless official DSH Client backed by the Host's in-process\n * Connection and Gateway carriers.\n *\n * The returned disposer tears down the Remote Events generation, all pending\n * listeners, and every lazily minted Agent scope.\n */\nexport async function startDsh012RemoteInteractions(\n hostCtx: Context,\n handlers: Dsh012RemoteInteractionHandlers,\n): Promise<() => Promise<void>> {\n const connection = hostCtx.get('connection') as HostConnectionLike | undefined\n const gateway = hostCtx.get('typertGateway') as HostGatewayLike | undefined\n if (connection === undefined) throw new Error('dsh 0.1.2-alpha.3 Host connection is unavailable')\n if (gateway === undefined) throw new Error('dsh 0.1.2-alpha.3 typertGateway is unavailable')\n\n const faces = await loadClientFaces()\n\n const client = new Context()\n const fetchHandler = connection.createSharedFetchHandler('/api')\n const transport: ClientTransportHooksLike = {\n fetch: (input, init) => fetchHandler.fetch(new Request(input, init)),\n openStream: (endpoint, payload, signal) => inProcessStream(gateway, endpoint, payload, signal),\n ownsHost: true,\n }\n\n try {\n faces.typert.apply(client)\n\n // Client Connection reads this hook once during apply() and retains the\n // concrete functions. Restore the process global immediately afterward so\n // no unrelated Client composition inherits DeepPilot's carrier.\n const transportGlobal = globalThis as TransportGlobal\n const previousTransport = transportGlobal.__DSH_TRANSPORT__\n transportGlobal.__DSH_TRANSPORT__ = transport\n try {\n faces.connection.apply(client)\n } finally {\n if (previousTransport === undefined) delete transportGlobal.__DSH_TRANSPORT__\n else transportGlobal.__DSH_TRANSPORT__ = previousTransport\n }\n\n const typert = client.get('typert') as ClientTypertLike | undefined\n if (typert === undefined) throw new Error('resident DSH Client typert service was not installed')\n const scopes = new Map<string, Context>()\n typert.contexts.registerClient('agent', {\n identity: candidate => scopeOf(candidate),\n resolve: identity => {\n let scope = scopes.get(identity)\n if (scope === undefined) {\n scope = createAgentScope(client, identity)\n scopes.set(identity, scope)\n }\n return scope\n },\n })\n\n // The Gateway opens its Remote Events generation asynchronously. Register\n // both listeners immediately after apply so a replayed pending request is\n // claimed before the first stream item can be dispatched.\n faces.gateway.apply(client)\n const remote = client.get('remote') as ClientRemoteLike | undefined\n if (remote === undefined) throw new Error('resident DSH Client remote service was not installed')\n remote.$on('approval/request', function (request, next) {\n return handlers.approval(scopeOf(this) ?? '', request as RemoteApprovalRequest, next)\n })\n remote.$on('user-questions/request', function (request, next) {\n return handlers.question(scopeOf(this) ?? '', request as RemoteQuestionRequest, next)\n })\n\n return async () => {\n await client.fiber.dispose()\n }\n } catch (error) {\n await client.fiber.dispose()\n throw error\n }\n}\n","/**\n * Compatibility façade for the DSH 0.1.2 controller API.\n *\n * DeepPilot's phone protocol deliberately speaks one stable in-process\n * `apiProxy` vocabulary. Harness 0.1.2 removed that service in favor of\n * direct Session/Workspace controllers plus Gateway-backed Remote Events.\n * This adapter rebuilds the small subset the bridge needs from those public\n * controllers and joins the official Client interaction plane in-process,\n * keeping the phone protocol isolated from the Host API migration.\n */\nimport { randomUUID } from 'node:crypto'\nimport type { Context } from '@deepseek-ai/cordis'\nimport {\n startDsh012RemoteInteractions,\n type RemoteApprovalRequest,\n type RemoteQuestionRequest,\n} from './dsh012-remote-interactions.ts'\nimport { isSubagentRow } from './host-api.ts'\nimport { projectHistory } from './host-event-projection.ts'\nimport type {\n ApiProxyLike,\n DirectoryListingLike,\n HistoryResult,\n HostSessionModels,\n MuxFrameLike,\n PhoneSessionRow,\n WorkspaceViewLike,\n} from './host-api.ts'\n\ninterface RpcOk<T> { ok: true; value: T }\ninterface RpcErr { ok: false; error: { code: string; message?: string } }\ntype RpcResult<T> = RpcOk<T> | RpcErr\n\ninterface SessionControllerLike {\n list(request: { cursor?: string }, signal: AbortSignal): Promise<{ items: readonly unknown[] }>\n inspect(sessionId: string, signal?: AbortSignal): Promise<{ events: readonly unknown[] }>\n create(request: Record<string, unknown>): Promise<{ sessionId: string; agentPreset?: string }>\n modelCatalog(): Promise<unknown>\n selectModel(request: Record<string, unknown>): Promise<{ selected: { provider: string; model: string; reasoningEffort?: string } }>\n rename(request: { sessionId: string; title: string }): Promise<{ title: string; seq: number }>\n prompt(request: Record<string, unknown>, signal: AbortSignal): Promise<{ accepted: true }>\n attachment(request: { sessionId: string; attachmentId: string }): Promise<{ attachment: { mediaType?: string }; data: string }>\n cancel(request: { sessionId: string }): { accepted: true }\n}\n\ninterface WorkspaceControllerLike {\n create(request: { path: string }): Promise<{ workspace: unknown; created: boolean }>\n archiveSession(request: { sessionId: string }): Promise<{ archivedSessionIds: readonly string[] }>\n follow(signal: AbortSignal): AsyncIterable<{ type: string; value?: unknown }>\n}\n\ninterface DirectoryPickerControllerLike {\n list(path: string | undefined, signal: AbortSignal): Promise<DirectoryListingLike>\n pick(signal: AbortSignal): Promise<string | null>\n}\n\ninterface DeferredInteraction {\n resolve(value: unknown): void\n /** Convert the stable phone-protocol response into the 0.1.2 waterfall result. */\n map(value: unknown): unknown\n}\n\n/** Which DSH 0.1.2 first-answer-wins interaction a phone may surface. */\nexport type DshInteractionKind = 'approval' | 'question'\n\nexport interface Dsh012ApiProxyOptions {\n /**\n * Decide whether the resident DeepPilot Remote Client represents a usable\n * phone surface. Returning false delegates only this Client delivery; API\n * Gateway keeps the official Web delivery independent.\n */\n shouldSurfaceInteraction?: (kind: DshInteractionKind) => boolean\n}\n\n/** Direct-controller facade with the exact legacy shape HostBridge consumes. */\nexport class Dsh012ApiProxy implements ApiProxyLike {\n private readonly session: SessionControllerLike\n private readonly workspaceController: WorkspaceControllerLike | undefined\n private readonly directoryPicker: DirectoryPickerControllerLike | undefined\n private readonly interactions = new Map<string, DeferredInteraction>()\n private readonly shouldSurfaceInteraction: (kind: DshInteractionKind) => boolean\n\n constructor(private readonly ctx: Context, options: Dsh012ApiProxyOptions = {}) {\n const session = ctx.get('sessionController') as SessionControllerLike | undefined\n if (session === undefined) throw new Error('dsh 0.1.2 sessionController is unavailable')\n this.session = session\n this.workspaceController = ctx.get('workspaceController') as WorkspaceControllerLike | undefined\n this.directoryPicker = ctx.get('directoryPickerController') as DirectoryPickerControllerLike | undefined\n this.shouldSurfaceInteraction = options.shouldSurfaceInteraction ?? (() => true)\n }\n\n /**\n * Decide whether this Gateway Client can surface a phone card. The decision\n * fails open to false so a broken device registry delegates this delivery\n * while the official Web Client remains able to answer.\n */\n private canSurfaceInteraction(kind: DshInteractionKind): boolean {\n try {\n return this.shouldSurfaceInteraction(kind)\n } catch {\n return false\n }\n }\n\n readonly sessions: ApiProxyLike['sessions'] = {\n list: async () => this.call(async () => {\n const value = await this.session.list({}, new AbortController().signal)\n // A list row can outlive a corrupt/unsupported persisted log. Do not\n // advertise it to a phone that cannot later open its history.\n return {\n // DeepPilot intentionally never exposes subagent workers to a phone.\n // In 0.1.2 their durable read address additionally requires a parent.\n items: value.items.map(toPhoneSessionRow).filter(row => !isSubagentRow(row)),\n }\n }),\n history: async (request) => this.call(async () => {\n const sessionId = request.payload!.sessionId\n let inspected: { events: readonly unknown[] }\n try {\n inspected = await this.session.inspect(sessionId)\n } catch (error) {\n // No message data is logged: only the opaque session id and Host's\n // safe error chain, enough to distinguish an unsupported legacy log\n // from a bridge regression.\n console.warn(`[deeppilot] session history unavailable for ${JSON.stringify(sessionId)}: ${toError(error).code}: ${toError(error).message}`)\n throw error\n }\n const before = request.payload?.beforeSeq\n const limit = Math.max(1, request.payload?.maxMessages ?? 100)\n const source = inspected.events\n .filter((event): event is HistoryResult['events'][number]['event'] =>\n typeof event === 'object' && event !== null\n && typeof (event as { type?: unknown }).type === 'string'\n && typeof (event as { seq?: unknown }).seq === 'number')\n .filter(event => before === undefined || event.seq < before)\n let end = source.length\n let events: HistoryResult['events'] = []\n while (end > 0 && projectHistory(events).length < limit) {\n const start = Math.max(0, end - limit)\n events = [\n ...source.slice(start, end).map(event => ({ event })),\n ...events,\n ]\n end = start\n }\n let trimmed = false\n while (events.length > 0 && projectHistory(events).length > limit) {\n events = events.slice(1)\n trimmed = true\n }\n return { events, hasMore: end > 0 || trimmed }\n }),\n prompt: async (request) => this.call(() => this.session.prompt({\n ...request.payload!,\n requestId: request.rpcId ?? randomUUID(),\n }, new AbortController().signal)),\n create: async (request) => this.call(() => this.session.create(request.payload ?? {})),\n models: async (request) => this.call(async () => projectModels(\n await this.session.modelCatalog(),\n String(request.payload?.sessionId ?? ''),\n await this.session.list({}, new AbortController().signal),\n )),\n selectModel: async (request) => this.call(() => this.session.selectModel(request.payload ?? {})),\n rename: async (request) => this.call(() => this.session.rename(request.payload!)),\n cancel: async (request) => this.call(() => this.session.cancel(request.payload!)),\n attachment: async (request) => this.call(() => this.session.attachment(request.payload!)),\n }\n\n readonly workspace: ApiProxyLike['workspace'] = {\n list: async () => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const baseline = await readWorkspaceBaseline(this.workspaceController)\n return {\n items: baseline.items.map(toWorkspaceView),\n archivedSessionIds: baseline.archivedSessionIds.map(String),\n }\n }),\n create: async (request) => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const value = await this.workspaceController.create(request.payload!)\n return { workspace: toWorkspaceView(value.workspace), created: value.created === true }\n }),\n archiveSession: async (request) => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const value = await this.workspaceController.archiveSession(request.payload!)\n return { archivedSessionIds: [...value.archivedSessionIds] }\n }),\n }\n\n readonly host: ApiProxyLike['host'] = {\n listDirectory: async (request, signal) => this.call(async () => {\n if (this.directoryPicker === undefined) throw unavailable('directory picker unavailable')\n return await this.directoryPicker.list(request.payload?.path, signal ?? new AbortController().signal)\n }),\n pickDirectory: async (_request, signal) => this.call(async () => {\n if (this.directoryPicker === undefined) throw unavailable('directory picker unavailable')\n return { path: await this.directoryPicker.pick(signal ?? new AbortController().signal) }\n }),\n }\n\n readonly events: ApiProxyLike['events'] = {\n mux: (_request, signal) => this.mux(signal),\n host: (_request, signal) => this.hostEvents(signal),\n }\n\n async respond(message: { type: 'client-response'; rpcId: string; result: RpcResult<unknown> }): Promise<{ accepted: boolean; reason?: string }> {\n const pending = this.interactions.get(message.rpcId)\n if (pending === undefined) return { accepted: false, reason: 'not-pending' }\n if (!message.result.ok) return { accepted: false, reason: 'bad-response' }\n this.interactions.delete(message.rpcId)\n pending.resolve(pending.map(message.result.value))\n return { accepted: true }\n }\n\n private async *mux(signal: AbortSignal): AsyncIterable<MuxFrameLike> {\n const queue = new AsyncFrameQueue(signal)\n const offEvent = this.ctx.on('session/event' as never, ((session: { id: string }, event: unknown) => {\n queue.push({ type: 'session/event', sessionId: String(session.id), event: event as MuxFrameLike['event'] })\n }) as never, { global: true })\n const projections = this.ctx.get('sessionProjections') as {\n onChanged?(listener: (session: { id: string }, key: string, value: unknown) => void): () => void\n } | undefined\n const offProjection = projections?.onChanged?.((session, key, value) => {\n queue.push({ type: 'session/projection', sessionId: String(session.id), key, value })\n })\n\n let disposeInteractions: (() => Promise<void>) | undefined\n try {\n disposeInteractions = await startDsh012RemoteInteractions(this.ctx, {\n approval: (sessionId, request, next) => this.answerApproval(queue, sessionId, request, next),\n question: (sessionId, request, next) => this.answerQuestion(queue, sessionId, request, next),\n })\n } catch (error) {\n console.warn(`[deeppilot] DSH Remote interaction client unavailable: ${toError(error).message}`)\n }\n\n try {\n yield* queue.iterate()\n } finally {\n offEvent()\n offProjection?.()\n await disposeInteractions?.()\n queue.close()\n }\n }\n\n private answerApproval(\n queue: AsyncFrameQueue,\n sessionId: string,\n request: RemoteApprovalRequest,\n next: () => Promise<unknown>,\n ): Promise<unknown> {\n if (!this.canSurfaceInteraction('approval')) return next()\n const rpcId = randomUUID()\n const response = deferred<unknown>()\n const abort = (): void => response.resolve('cancelled')\n request.signal?.addEventListener('abort', abort, { once: true })\n this.interactions.set(rpcId, {\n resolve: response.resolve,\n map: value => {\n const outcome = (value as { outcome?: unknown } | undefined)?.outcome\n return outcome === 'allowed-once' || outcome === 'rejected' ? outcome : 'unavailable'\n },\n })\n queue.push({\n type: 'approval/requested', rpcId, sessionId, approvalId: rpcId,\n toolName: String(request.toolName ?? 'tool'), reason: String(request.reason ?? ''),\n })\n return response.promise.finally(() => {\n request.signal?.removeEventListener('abort', abort)\n this.interactions.delete(rpcId)\n queue.push({ type: 'approval/resolved', approvalId: rpcId })\n })\n }\n\n private answerQuestion(\n queue: AsyncFrameQueue,\n sessionId: string,\n request: RemoteQuestionRequest,\n next: () => Promise<unknown>,\n ): Promise<unknown> {\n if (!this.canSurfaceInteraction('question')) return next()\n const rpcId = randomUUID()\n const response = deferred<unknown>()\n const abort = (): void => response.reject(new Error('question cancelled'))\n request.signal?.addEventListener('abort', abort, { once: true })\n this.interactions.set(rpcId, {\n resolve: response.resolve,\n map: value => (value as { answer?: unknown } | undefined)?.answer ?? value,\n })\n queue.push({ type: 'question/requested', rpcId, sessionId, questions: request.questions ?? [] })\n return response.promise.finally(() => {\n request.signal?.removeEventListener('abort', abort)\n this.interactions.delete(rpcId)\n queue.push({ type: 'question/resolved', questionRpcId: rpcId })\n })\n }\n\n private async *hostEvents(signal: AbortSignal): AsyncIterable<MuxFrameLike> {\n const queue = new AsyncFrameQueue(signal)\n const listen = (event: string, type: string, project?: (...args: unknown[]) => Record<string, unknown>) =>\n this.ctx.on(event as never, ((...args: unknown[]) => queue.push({ type, ...(project?.(...args) ?? {}) })) as never, { global: true })\n const off = [\n listen('api-session/added', 'host/session-added'),\n listen('api-session/removed', 'host/session-removed'),\n listen('api-session/status', 'host/session-status', (sessionId, running) => ({ sessionId: String(sessionId), running: running === true })),\n listen('api-session/activity', 'host/session-added'),\n ]\n const workspaceAbort = new AbortController()\n const stop = (): void => workspaceAbort.abort()\n signal.addEventListener('abort', stop, { once: true })\n const workspaceTask = this.workspaceController === undefined ? undefined : (async () => {\n try {\n for await (const frame of this.workspaceController!.follow(workspaceAbort.signal)) {\n if (frame.type === 'archived') queue.push({ type: 'host/archived-sessions-changed', archivedSessionIds: (frame as { archivedSessionIds?: unknown }).archivedSessionIds } as MuxFrameLike)\n else if (frame.type !== 'baseline') queue.push({ type: 'host/workspace-changed' })\n }\n } catch { /* Host shutdown / withdrawn controller ends the stream. */ }\n })()\n try {\n yield* queue.iterate()\n } finally {\n for (const dispose of off) dispose()\n signal.removeEventListener('abort', stop)\n workspaceAbort.abort()\n void workspaceTask\n queue.close()\n }\n }\n\n private async call<T>(invoke: () => T | Promise<T>): Promise<{ result: RpcResult<T> }> {\n try { return { result: { ok: true, value: await invoke() } } }\n catch (error) { return { result: { ok: false, error: toError(error) } } }\n }\n}\n\nfunction deferred<T>(): { promise: Promise<T>; resolve(value: T): void; reject(reason: unknown): void } {\n let resolve!: (value: T) => void\n let reject!: (reason: unknown) => void\n const promise = new Promise<T>((ok, fail) => { resolve = ok; reject = fail })\n return { promise, resolve, reject }\n}\n\nclass AsyncFrameQueue {\n private readonly frames: MuxFrameLike[] = []\n private wake: (() => void) | undefined\n private closed = false\n constructor(signal: AbortSignal) {\n signal.addEventListener('abort', () => this.close(), { once: true })\n }\n push(frame: MuxFrameLike): void { if (!this.closed) { this.frames.push(frame); this.wake?.() } }\n close(): void { if (!this.closed) { this.closed = true; this.wake?.() } }\n async *iterate(): AsyncIterable<MuxFrameLike> {\n while (!this.closed) {\n const frame = this.frames.shift()\n if (frame !== undefined) { yield frame; continue }\n await new Promise<void>(resolve => { this.wake = resolve })\n this.wake = undefined\n }\n }\n}\n\nfunction unavailable(message: string): Error & { code: string } {\n return Object.assign(new Error(message), { code: 'directory-picker-unavailable' })\n}\nfunction toError(error: unknown): { code: string; message: string } {\n const value = error as { code?: unknown; message?: unknown }\n return { code: typeof value?.code === 'string' ? value.code : 'internal', message: typeof value?.message === 'string' ? value.message : String(error) }\n}\nfunction toPhoneSessionRow(value: unknown): PhoneSessionRow {\n const row = value as Record<string, unknown>\n return {\n sessionId: String(row.sessionId ?? ''), updatedAt: Number(row.updatedAt ?? Date.now()), running: row.running === true,\n ...(row.blank === true ? { blank: true } : {}), ...(typeof row.cwd === 'string' ? { cwd: row.cwd } : {}),\n ...(typeof row.origin === 'string' ? { origin: row.origin } : {}), ...(typeof row.parentSessionId === 'string' ? { parentSessionId: row.parentSessionId } : {}),\n ...(row.projections && typeof row.projections === 'object' ? { projections: row.projections as PhoneSessionRow['projections'] } : {}),\n }\n}\nfunction toWorkspaceView(value: unknown): WorkspaceViewLike {\n const row = value as Record<string, unknown>\n return { workspaceId: String(row.workspaceId ?? ''), title: String(row.title ?? ''), path: String(row.path ?? ''), sessionIds: Array.isArray(row.sessionIds) ? row.sessionIds.map(String) : [] }\n}\nasync function readWorkspaceBaseline(controller: WorkspaceControllerLike): Promise<{ items: WorkspaceViewLike[]; archivedSessionIds: string[] }> {\n const abort = new AbortController()\n const iterator = controller.follow(abort.signal)[Symbol.asyncIterator]()\n try {\n const first = await iterator.next()\n const baseline = first.value as { type?: string; value?: { items?: unknown[]; archivedSessionIds?: unknown[] } } | undefined\n if (baseline?.type !== 'baseline') throw new Error('workspace follow did not provide a baseline')\n return { items: (baseline.value?.items ?? []).map(toWorkspaceView), archivedSessionIds: (baseline.value?.archivedSessionIds ?? []).map(String) }\n } finally { abort.abort(); await iterator.return?.() }\n}\nasync function projectModels(catalog: unknown, sessionId: string, list: { items: readonly unknown[] }): Promise<HostSessionModels> {\n const value = catalog as { default?: { provider?: string; model?: string; reasoningEffort?: string }; groups?: unknown[]; failures?: unknown[] }\n const row = list.items.map(toPhoneSessionRow).find(item => item.sessionId === sessionId)\n const selected = (row?.projections?.values?.modelSelection as { next?: unknown } | undefined)?.next as { provider?: string; model?: string; reasoningEffort?: string } | undefined\n return {\n current: { provider: String(selected?.provider ?? value.default?.provider ?? ''), model: String(selected?.model ?? value.default?.model ?? ''), ...(typeof selected?.reasoningEffort === 'string' ? { reasoningEffort: selected.reasoningEffort } : {}) },\n routable: true,\n groups: Array.isArray(value.groups) ? value.groups as HostSessionModels['groups'] : [],\n failures: Array.isArray(value.failures) ? value.failures as HostSessionModels['failures'] : [],\n }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'\nimport type { DeviceScope } from './device-auth.ts'\nimport type { DeepPilotReport, PairingGrantSnapshot, PushTestResult, RelayTestResult } from './report-wire.ts'\n\n/** Async snapshot source wired by the plugin entry. */\nexport type ReportSnapshot = () => Promise<DeepPilotReport>\n\nexport type PairingStarter = () => Promise<PairingGrantSnapshot>\nexport type DeviceRevoker = (deviceId: string) => Promise<boolean>\nexport type DeviceScopeUpdater = (deviceId: string, scopes: DeviceScope[]) => Promise<DeviceScope[]>\n\n/** Runs the relay connectivity self-test (health + enrollment round-trip). */\nexport type RelayTester = () => Promise<RelayTestResult>\n\n/** Forces one synthetic notification down the active push pathway. */\nexport type PushTester = () => Promise<PushTestResult>\n\n/**\n * The Typert receiver the Gateway resolves for the DeepPilot Bridge report.\n * Snapshot data stays non-secret; the token crosses the boundary only through\n * the explicit, user-triggered revealToken/rotateToken invocations.\n */\nexport class DeepPilotReportService extends TypertRemoteService {\n private readonly snapshot: ReportSnapshot\n private readonly pairingStarter: PairingStarter\n private readonly deviceRevoker: DeviceRevoker\n private readonly deviceScopeUpdater: DeviceScopeUpdater\n\n private readonly relayTester: RelayTester\n private readonly pushTester: PushTester\n\n constructor(\n ctx: Context,\n snapshot: ReportSnapshot,\n pairingStarter: PairingStarter,\n deviceRevoker: DeviceRevoker,\n deviceScopeUpdater: DeviceScopeUpdater,\n relayTester: RelayTester,\n pushTester: PushTester,\n ) {\n super(ctx, 'deeppilotReport', { namespace: 'deeppilot' })\n this.snapshot = snapshot\n this.pairingStarter = pairingStarter\n this.deviceRevoker = deviceRevoker\n this.deviceScopeUpdater = deviceScopeUpdater\n this.relayTester = relayTester\n this.pushTester = pushTester\n }\n\n async report(): Promise<DeepPilotReport> {\n return this.snapshot()\n }\n\n async beginPairing(): Promise<PairingGrantSnapshot> {\n return this.pairingStarter()\n }\n\n async revokeDevice(deviceId: string): Promise<boolean> {\n return this.deviceRevoker(deviceId)\n }\n\n async setDeviceScopes(deviceId: string, scopes: DeviceScope[]): Promise<DeviceScope[]> {\n return this.deviceScopeUpdater(deviceId, scopes)\n }\n\n async testRelay(): Promise<RelayTestResult> {\n return this.relayTester()\n }\n\n async testPush(): Promise<PushTestResult> {\n return this.pushTester()\n }\n}\n","/**\n * Wire contract for the DeepPilot report Remote (`deeppilot/report`).\n *\n * The web settings page needs the bridge's live facts (paired devices,\n * connections, token state) — those live Host-side. This module is the single\n * source both halves share: the strict result codec (hand-rolled, so the\n * client bundle needs no schema library) and the exact descriptor object.\n *\n * @module dsh-deeppilot/report-wire\n */\n\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport { DEVICE_SCOPES, normalizeDeviceScopes, type DeviceScope } from './device-auth.ts'\n\nexport interface PairingGrantSnapshot {\n code: string\n expiresAt: number\n audience: string\n}\n\n/** One paired device row in the report. */\nexport interface ReportDevice {\n deviceId: string\n deviceName: string\n appVersion: string\n firstSeenTs: number\n lastSeenTs: number\n fingerprint: string\n scopes: DeviceScope[]\n revokedAt?: number\n /** Present once the device registered an APNs token (token itself never leaves the host). */\n apns?: { environment: 'development' | 'production'; updatedAt: number }\n}\n\n/** One step of the relay connectivity self-test. */\nexport interface RelayTestStep {\n id: 'health' | 'enroll'\n ok: boolean\n message: string\n latencyMs?: number\n}\n\n/** Result of deeppilot/testRelay. */\nexport interface RelayTestResult {\n url: string\n overall: 'ok' | 'failed'\n tokenIssued: boolean\n steps: RelayTestStep[]\n}\n\n/** Per-device delivery result of deeppilot/testPush. */\nexport interface PushTestDeviceResult {\n name: string\n environment: string\n /** sent | invalid-token | failed — mirrors the dispatch outcome contract. */\n outcome: string\n /** Apple's raw rejection reason when present (BadDeviceToken, …). */\n reason?: string\n /** First 10 hex chars of the stored token, for freshness verification. */\n tokenFingerprint?: string\n}\n\nexport interface PushTestResult {\n transport: 'apns' | 'relay' | 'none'\n /** sent = at least one accepted delivery; no-targets / not-configured / failed. */\n overall: 'sent' | 'failed' | 'no-targets' | 'not-configured'\n message?: string\n results: PushTestDeviceResult[]\n}\n\n/** Everything the settings page renders for the bridge. */\nexport interface DeepPilotReport {\n protocolVersion: number\n serverVersion: string\n /** Host plugin version (from package.json). Same value as serverVersion,\n * surfaced under a stable name so the wire contract does not change if\n * the legacy field is ever repurposed. */\n pluginVersion: string\n /** True once the host's background GitHub check has confirmed a newer\n * stable release exists. Undefined / false ⇒ the UI shows only the\n * version line, never the \"new version\" hint. */\n updateAvailable?: boolean\n /** GitHub release page URL, when an update is available. */\n releaseUrl?: string\n /** Whether the master bridge switch is on. */\n enabled: boolean\n /** Absolute protocol-v2 identity registry path. */\n identityPath: string\n /** Whether host identity and the device registry are ready. */\n pairingReady: boolean\n /** Currently connected phone sockets. */\n activeConnections: number\n historyBufferMax: number\n debug: boolean\n /** Private IPv4 candidates for local QR pairing. */\n lanAddresses: string[]\n /** Independent LAN listener; this never represents DSH's own web port. */\n local: {\n phase: 'disabled' | 'starting' | 'online' | 'error' | 'stopped'\n port: number\n endpoints: string[]\n message?: string\n updatedAt: number\n }\n remote: {\n provider: 'tailscale-funnel'\n phase: 'disabled' | 'starting' | 'login_required' | 'online' | 'error' | 'unavailable' | 'stopped'\n publicURL?: string\n authURL?: string\n message?: string\n updatedAt: number\n }\n devices: ReportDevice[]\n}\n\n/** The npm package identity both contribution registrations claim. */\nexport const REPORT_REMOTE_PACKAGE = 'dsh-deeppilot'\n\n/** Canonical `<namespace>/<method>` endpoint of the report Remote. */\nexport const REPORT_ENDPOINT = 'deeppilot/report'\n\nexport const BEGIN_PAIRING_ENDPOINT = 'deeppilot/beginPairing'\nexport const REVOKE_DEVICE_ENDPOINT = 'deeppilot/revokeDevice'\nexport const SET_DEVICE_SCOPES_ENDPOINT = 'deeppilot/setDeviceScopes'\n\nfunction reject(field: string): never {\n throw new TypeError(`deeppilot/report result: invalid ${field}`)\n}\n\nfunction str(source: Record<string, unknown>, key: string, field: string): string {\n const value = source[key]\n if (typeof value !== 'string') reject(field)\n return value\n}\n\n/**\n * Non-negative integer: counters and timestamps (activeConnections,\n * historyBufferMax, updatedAt, lastSeenTs, protocolVersion, etc.). A bare\n * `typeof number` check accepts 1.5, -1, and 1e20 — all of which then\n * surface verbatim on the settings page and break any sort or arithmetic\n * the UI does.\n */\nfunction int(source: Record<string, unknown>, key: string, field: string): number {\n const value = source[key]\n if (\n typeof value !== 'number' ||\n !Number.isFinite(value) ||\n !Number.isInteger(value) ||\n value < 0\n ) reject(field)\n return value\n}\nfunction bool(source: Record<string, unknown>, key: string, field: string): boolean {\n const value = source[key]\n if (typeof value !== 'boolean') reject(field)\n return value\n}\nfunction rec(value: unknown, field: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) reject(field)\n return value as Record<string, unknown>\n}\n\nfunction parseDevice(value: unknown): ReportDevice {\n const s = rec(value, 'device')\n let apns: ReportDevice['apns']\n if (s.apns !== undefined) {\n const a = rec(s.apns, 'device.apns')\n const environment = str(a, 'environment', 'device.apns.environment')\n if (environment !== 'development' && environment !== 'production') reject('device.apns.environment')\n apns = { environment, updatedAt: int(a, 'updatedAt', 'device.apns.updatedAt') }\n }\n return {\n deviceId: str(s, 'deviceId', 'device.deviceId'),\n deviceName: str(s, 'deviceName', 'device.deviceName'),\n appVersion: str(s, 'appVersion', 'device.appVersion'),\n firstSeenTs: int(s, 'firstSeenTs', 'device.firstSeenTs'),\n lastSeenTs: int(s, 'lastSeenTs', 'device.lastSeenTs'),\n fingerprint: str(s, 'fingerprint', 'device.fingerprint'),\n scopes: normalizeDeviceScopes(s.scopes),\n ...(s.revokedAt !== undefined ? { revokedAt: int(s, 'revokedAt', 'device.revokedAt') } : {}),\n ...(apns ? { apns } : {}),\n }\n}\n\nfunction parseRemote(value: unknown): DeepPilotReport['remote'] {\n const s = rec(value, 'remote')\n const provider = str(s, 'provider', 'remote.provider')\n const phase = str(s, 'phase', 'remote.phase')\n if (provider !== 'tailscale-funnel') reject('remote.provider')\n const phases = ['disabled', 'starting', 'login_required', 'online', 'error', 'unavailable', 'stopped']\n if (!phases.includes(phase)) reject('remote.phase')\n const publicURL = s.publicURL\n const authURL = s.authURL\n const message = s.message\n if (publicURL !== undefined && typeof publicURL !== 'string') reject('remote.publicURL')\n if (authURL !== undefined && typeof authURL !== 'string') reject('remote.authURL')\n if (message !== undefined && typeof message !== 'string') reject('remote.message')\n return {\n provider,\n phase: phase as DeepPilotReport['remote']['phase'],\n ...(typeof publicURL === 'string' ? { publicURL } : {}),\n ...(typeof authURL === 'string' ? { authURL } : {}),\n ...(typeof message === 'string' ? { message } : {}),\n updatedAt: int(s, 'updatedAt', 'remote.updatedAt'),\n }\n}\n\nfunction parseLocal(value: unknown): DeepPilotReport['local'] {\n const s = rec(value, 'local')\n const phase = str(s, 'phase', 'local.phase')\n const phases = ['disabled', 'starting', 'online', 'error', 'stopped']\n if (!phases.includes(phase)) reject('local.phase')\n const endpoints = s.endpoints\n if (!Array.isArray(endpoints) || endpoints.some((entry) => typeof entry !== 'string')) reject('local.endpoints')\n const message = s.message\n if (message !== undefined && typeof message !== 'string') reject('local.message')\n return {\n phase: phase as DeepPilotReport['local']['phase'],\n port: int(s, 'port', 'local.port'),\n endpoints: endpoints as string[],\n ...(typeof message === 'string' ? { message } : {}),\n updatedAt: int(s, 'updatedAt', 'local.updatedAt'),\n }\n}\n\nfunction parseRelayTestStep(value: unknown): RelayTestStep {\n const st = rec(value, 'step')\n const id = str(st, 'id', 'step.id')\n if (id !== 'health' && id !== 'enroll') reject('step.id')\n const latencyMs = st.latencyMs\n if (latencyMs !== undefined) {\n // Same int() check the report uses for counters: latency is always a\n // non-negative whole-millisecond number; a NaN/Infinity/negative arrives\n // from a buggy host and must not silently render as `(NaNms)`.\n if (\n typeof latencyMs !== 'number' ||\n !Number.isFinite(latencyMs) ||\n !Number.isInteger(latencyMs) ||\n latencyMs < 0\n ) reject('step.latencyMs')\n }\n return {\n id,\n ok: bool(st, 'ok', 'step.ok'),\n message: str(st, 'message', 'step.message'),\n ...(typeof latencyMs === 'number' ? { latencyMs } : {}),\n }\n}\n\nfunction parseRelayTestResult(value: unknown): RelayTestResult {\n const s = rec(value, 'result')\n const overall = str(s, 'overall', 'overall')\n if (overall !== 'ok' && overall !== 'failed') reject('overall')\n const stepsRaw = s.steps\n if (!Array.isArray(stepsRaw)) reject('steps')\n return {\n url: str(s, 'url', 'url'),\n overall,\n tokenIssued: bool(s, 'tokenIssued', 'tokenIssued'),\n steps: (stepsRaw as unknown[]).map(parseRelayTestStep),\n }\n}\n\nfunction parsePushTestResult(value: unknown): PushTestResult {\n const s = rec(value, 'result')\n const transport = str(s, 'transport', 'transport')\n if (transport !== 'apns' && transport !== 'relay' && transport !== 'none') reject('transport')\n const overall = str(s, 'overall', 'overall')\n const overalls = ['sent', 'failed', 'no-targets', 'not-configured']\n if (!overalls.includes(overall)) reject('overall')\n const resultsRaw = s.results\n if (!Array.isArray(resultsRaw)) reject('results')\n const results = (resultsRaw as unknown[]).map((value) => {\n const r = rec(value, 'device result')\n const reason = r.reason\n const tokenFingerprint = r.tokenFingerprint\n return {\n name: str(r, 'name', 'result.name'),\n environment: str(r, 'environment', 'result.environment'),\n outcome: str(r, 'outcome', 'result.outcome'),\n ...(typeof reason === 'string' && reason.length > 0 ? { reason } : {}),\n ...(typeof tokenFingerprint === 'string' && /^[0-9a-f]{10}$/.test(tokenFingerprint)\n ? { tokenFingerprint }\n : {}),\n }\n })\n const message = s.message\n return {\n transport,\n overall: overall as PushTestResult['overall'],\n ...(typeof message === 'string' && message.length > 0 ? { message } : {}),\n results,\n }\n}\n\nfunction parseReport(value: unknown): DeepPilotReport {\n const s = rec(value, 'report')\n const devices = s.devices\n const lanAddresses = s.lanAddresses\n if (!Array.isArray(devices)) reject('devices')\n if (!Array.isArray(lanAddresses) || lanAddresses.some((value) => typeof value !== 'string')) reject('lanAddresses')\n // Update fields are optional: an older Host (without the background\n // GitHub check) won't include them, and the UI must keep rendering.\n const releaseUrl = s.releaseUrl\n return {\n protocolVersion: int(s, 'protocolVersion', 'protocolVersion'),\n serverVersion: str(s, 'serverVersion', 'serverVersion'),\n pluginVersion: str(s, 'pluginVersion', 'pluginVersion'),\n ...(s.updateAvailable === true ? { updateAvailable: true } : {}),\n ...(typeof releaseUrl === 'string' && releaseUrl.length > 0\n ? { releaseUrl } : {}),\n enabled: bool(s, 'enabled', 'enabled'),\n identityPath: str(s, 'identityPath', 'identityPath'),\n pairingReady: bool(s, 'pairingReady', 'pairingReady'),\n activeConnections: int(s, 'activeConnections', 'activeConnections'),\n historyBufferMax: int(s, 'historyBufferMax', 'historyBufferMax'),\n debug: bool(s, 'debug', 'debug'),\n lanAddresses: lanAddresses as string[],\n local: parseLocal(s.local),\n remote: parseRemote(s.remote),\n devices: (devices as unknown[]).map(parseDevice),\n }\n}\n\nexport const reportSchema: TypertSchema<DeepPilotReport> = { parse: parseReport }\n\nexport const relayTestSchema: TypertSchema<RelayTestResult> = { parse: parseRelayTestResult }\n\nexport const pushTestSchema: TypertSchema<PushTestResult> = { parse: parsePushTestResult }\n\nexport const pairingGrantSchema: TypertSchema<PairingGrantSnapshot> = {\n parse(value: unknown): PairingGrantSnapshot {\n const s = rec(value, 'pairing grant')\n const code = str(s, 'code', 'pairingGrant.code')\n if (code.length < 32) reject('pairingGrant.code')\n return {\n code,\n expiresAt: int(s, 'expiresAt', 'pairingGrant.expiresAt'),\n audience: str(s, 'audience', 'pairingGrant.audience'),\n }\n },\n}\n\nconst deviceIdSchema: TypertSchema<string> = {\n parse(value: unknown): string {\n if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{43}$/.test(value)) reject('deviceId')\n return value\n },\n}\n\nconst scopesSchema: TypertSchema<DeviceScope[]> = {\n parse(value: unknown): DeviceScope[] {\n if (!Array.isArray(value) || value.some((scope) => typeof scope !== 'string' || !DEVICE_SCOPES.includes(scope as DeviceScope))) {\n reject('scopes')\n }\n return normalizeDeviceScopes(value)\n },\n}\n\nconst booleanSchema: TypertSchema<boolean> = {\n parse(value: unknown): boolean {\n if (typeof value !== 'boolean') reject('boolean')\n return value\n },\n}\n\n/**\n * Connectivity self-test for the push relay: health probe plus (when an\n * enroll key is on file) a real enrollment round-trip. Doubles as repair —\n * a token it issues is cached by the bridge.\n */\nexport const TEST_RELAY_ENDPOINT = 'deeppilot/testRelay'\n\n/**\n * Real-delivery push test: forces one synthetic notification down the active\n * push pathway to every registered device, ignoring connected/muted filters —\n * an explicit user action must always be able to prove the pipeline works.\n */\nexport const TEST_PUSH_ENDPOINT = 'deeppilot/testPush'\n\nexport const REPORT_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${REPORT_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'report',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeepPilotReport`,\n schema: reportSchema,\n },\n}\n\nexport const BEGIN_PAIRING_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${BEGIN_PAIRING_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'beginPairing',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#PairingGrantSnapshot`,\n schema: pairingGrantSchema,\n },\n}\n\nexport const REVOKE_DEVICE_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${REVOKE_DEVICE_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'revokeDevice',\n invocation: { kind: 'direct' },\n parameters: [{\n name: 'deviceId',\n wire: 'deviceId',\n source: 'json',\n codec: { mode: 'strict', typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceId`, schema: deviceIdSchema },\n }],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#Boolean`,\n schema: booleanSchema,\n },\n}\n\nexport const SET_DEVICE_SCOPES_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${SET_DEVICE_SCOPES_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'setDeviceScopes',\n invocation: { kind: 'direct' },\n parameters: [\n {\n name: 'deviceId', wire: 'deviceId', source: 'json',\n codec: { mode: 'strict', typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceId`, schema: deviceIdSchema },\n },\n {\n name: 'scopes', wire: 'scopes', source: 'json',\n codec: { mode: 'strict', typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceScopes`, schema: scopesSchema },\n },\n ],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#DeviceScopes`,\n schema: scopesSchema,\n },\n}\n\nexport const TEST_RELAY_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${TEST_RELAY_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'testRelay',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#RelayTestResult`,\n schema: relayTestSchema,\n },\n}\n\nexport const TEST_PUSH_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${TEST_PUSH_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'testPush',\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol: `${REPORT_REMOTE_PACKAGE}#PushTestResult`,\n schema: pushTestSchema,\n },\n}\n\nconst INVOCATION_DESCRIPTORS = [\n REPORT_DESCRIPTOR,\n BEGIN_PAIRING_DESCRIPTOR,\n REVOKE_DEVICE_DESCRIPTOR,\n SET_DEVICE_SCOPES_DESCRIPTOR,\n TEST_RELAY_DESCRIPTOR,\n TEST_PUSH_DESCRIPTOR,\n]\n\nexport const REPORT_HOST_CONTRIBUTION = {\n package: REPORT_REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n // Typert contributions in dsh 0.1.2 include reflection metadata even when\n // a hand-written Remote has no generated reflection exports.\n model: { services: [], events: [], objects: [] },\n invocations: INVOCATION_DESCRIPTORS,\n}\n\nexport const REPORT_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: REPORT_REMOTE_PACKAGE,\n descriptors: INVOCATION_DESCRIPTORS,\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { DeepPilotReportService } from './report-service.ts'\nimport type { DeviceRevoker, DeviceScopeUpdater, PairingStarter, PushTester, RelayTester, ReportSnapshot } from './report-service.ts'\nimport { REPORT_HOST_CONTRIBUTION } from './report-wire.ts'\n\ninterface TypertContributionRegistry {\n register(contribution: typeof REPORT_HOST_CONTRIBUTION): () => void | Promise<void>\n}\n\n/**\n * Provide the report service and register its Remote descriptor. Rides an\n * optional `typert` inject: profiles without the web stack never activate it.\n */\nexport function applyReportRemote(\n ctx: Context,\n snapshot: ReportSnapshot,\n pairingStarter: PairingStarter,\n deviceRevoker: DeviceRevoker,\n deviceScopeUpdater: DeviceScopeUpdater,\n relayTester: RelayTester,\n pushTester: PushTester,\n): void {\n ctx.inject(['typert'], (remoteCtx) => {\n new DeepPilotReportService(remoteCtx, snapshot, pairingStarter, deviceRevoker, deviceScopeUpdater, relayTester, pushTester)\n const registry = remoteCtx.typert as unknown as TypertContributionRegistry\n const unregister = registry.register(REPORT_HOST_CONTRIBUTION)\n remoteCtx.effect(() => () => void unregister(), 'dsh-deeppilot: report remote')\n })\n}\n","/**\n * Normalize an operator-configured relay URL without a backtracking regular\n * expression. Scanning from the end keeps even pathological inputs linear.\n */\nexport function normalizeRelayBaseUrl(value: string): string {\n const trimmed = value.trim()\n let end = trimmed.length\n while (end > 0 && trimmed.charCodeAt(end - 1) === 0x2f) end -= 1\n return end === trimmed.length ? trimmed : trimmed.slice(0, end)\n}\n","/**\n * Relay connectivity self-test used by the settings page \"测试中继\" button.\n *\n * Two steps mirror what zero-touch enrollment actually does:\n * 1. health — GET {url}/healthz → is the relay reachable?\n * 2. enroll — POST {url}/v1/enroll → does the shared key grant a token?\n *\n * The enroll step doubles as a repair path: a token it issues is handed back\n * via `onEnrolled` so the bridge caches it and flips push readiness without\n * waiting for the next app registration.\n *\n * Transport is injectable (`fetchImpl`) so tests never touch the network.\n */\n\nimport { normalizeRelayBaseUrl } from './relay-url.ts'\n\nexport interface RelayTestStep {\n id: 'health' | 'enroll'\n ok: boolean\n /** Human-readable, user-facing (zh) outcome; safe to render verbatim. */\n message: string\n latencyMs?: number\n}\n\nexport interface RelayTestResult {\n url: string\n overall: 'ok' | 'failed'\n /** True when the probe produced/cached a usable relay token. */\n tokenIssued: boolean\n steps: RelayTestStep[]\n}\n\nexport interface RelayProbeOptions {\n url: string\n /** Stable per-bridge identity for enrollment; generated upstream if absent. */\n clientId?: string\n /** Distributor's shared key; absent → enroll step reports why it cannot run. */\n enrollKey?: string\n /** True when the user configured relayToken manually (enroll unnecessary). */\n manualToken?: boolean\n timeoutMs?: number\n fetchImpl?: typeof fetch\n /** Called with an issued token so the caller can persist it. */\n onEnrolled?: (token: string) => void\n}\n\nconst DEFAULT_TIMEOUT_MS = 6_000\n\nasync function requestJson(\n fetchImpl: typeof fetch,\n url: string,\n init: RequestInit,\n timeoutMs: number,\n): Promise<{ status: number; body: unknown }> {\n const response = await fetchImpl(url, {\n ...init,\n signal: AbortSignal.timeout(timeoutMs),\n })\n let body: unknown = null\n try {\n body = await response.json()\n } catch {\n // non-JSON body keeps body null; status still drives the verdict\n }\n return { status: response.status, body }\n}\n\nexport async function runRelayProbe(options: RelayProbeOptions): Promise<RelayTestResult> {\n const base = normalizeRelayBaseUrl(options.url)\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const fetchImpl = options.fetchImpl ?? fetch\n const steps: RelayTestStep[] = []\n let tokenIssued = false\n\n // ---- step 1: reachability ----\n try {\n const startedAt = Date.now()\n const { status, body } = await requestJson(\n fetchImpl,\n `${base}/healthz`,\n { method: 'GET' },\n timeoutMs,\n )\n const latencyMs = Date.now() - startedAt\n if (status === 200 && (body as { ok?: unknown })?.ok === true) {\n steps.push({ id: 'health', ok: true, message: '中继服务可达', latencyMs })\n } else {\n steps.push({ id: 'health', ok: false, message: `中继响应异常(HTTP ${status})`, latencyMs })\n }\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n steps.push({ id: 'health', ok: false, message: '无法连接中继:' + reason })\n }\n\n // ---- step 2: enrollment ----\n if ((options.manualToken ?? false)) {\n steps.push({ id: 'enroll', ok: true, message: '已手动配置 relayToken,跳过注册验证' })\n } else if (!options.enrollKey) {\n steps.push({ id: 'enroll', ok: false, message: '尚无注册密钥:等待分发版 App 首次注册后才能验证注册' })\n } else {\n const clientId = options.clientId ?? 'u_' + Math.random().toString(36).slice(2)\n try {\n const startedAt = Date.now()\n const { status, body } = await requestJson(\n fetchImpl,\n `${base}/v1/enroll`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ clientId, enrollKey: options.enrollKey }),\n },\n timeoutMs,\n )\n const latencyMs = Date.now() - startedAt\n const token = (body as { token?: unknown })?.token\n if (status === 200 && typeof token === 'string' && token.startsWith('rl_')) {\n tokenIssued = true\n options.onEnrolled?.(token)\n steps.push({ id: 'enroll', ok: true, message: '注册成功,已取得推送凭证', latencyMs })\n } else if (status === 403) {\n steps.push({ id: 'enroll', ok: false, message: '注册被拒:注册密钥不匹配(检查 App 内 DSPushEnrollKey 与服务器 RELAY_ENROLL_KEY)', latencyMs })\n } else if (status === 429) {\n steps.push({ id: 'enroll', ok: false, message: '尝试过于频繁,稍后再试', latencyMs })\n } else {\n steps.push({ id: 'enroll', ok: false, message: `注册失败(HTTP ${status})`, latencyMs })\n }\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n steps.push({ id: 'enroll', ok: false, message: '注册请求失败:' + reason })\n }\n }\n\n const overall: RelayTestResult['overall'] =\n steps.length > 0 && steps.some((step) => step.id === 'health' && step.ok) &&\n steps.every((step) => step.ok)\n ? 'ok'\n : 'failed'\n return { url: base, overall, tokenIssued, steps }\n}\n","/**\n * Minimal APNs provider client (HTTP/2) with zero npm dependencies.\n *\n * Implements exactly what the bridge needs:\n * - ES256 provider token (JWT) signed with an Apple .p8 key, refreshed under\n * the 1-hour freshness window Apple enforces;\n * - one long-lived HTTP/2 session per environment, recreated transparently\n * after GOAWAY/errors;\n * - alert pushes carrying the notify projection (category/thread/collapse),\n * with `interruption-level: time-sensitive` for approval/question events;\n * - outcome classification so callers can prune dead device tokens.\n *\n * Privacy: logs carry outcomes and masked token prefixes only — never message\n * bodies or full tokens.\n */\n\nimport { connect as http2Connect, type ClientHttp2Session } from 'node:http2'\nimport { createHash, createPrivateKey, sign as cryptoSign, type KeyObject } from 'node:crypto'\nimport { readFile } from 'node:fs/promises'\nimport type { ApnsEnvironment } from './token.ts'\nimport type { PushDelivery, PushNotification } from './protocol.ts'\n\nexport interface ApnsClientOptions {\n teamId: string\n keyId: string\n /** Absolute path to the .p8 private key file. */\n keyPath: string\n bundleId: string\n debug?: boolean\n log: (message: string) => void\n}\n\nexport type ApnsOutcome = 'sent' | 'invalid-token' | 'failed'\n\n/** Outcome plus Apple's rejection reason (when present) for diagnosis. */\nexport interface ApnsSendResult {\n outcome: ApnsOutcome\n reason?: string\n}\n\n/** Classify Apple's reason without losing recoverable configuration errors. */\nexport function classifyApnsReason(reason: string): ApnsOutcome {\n return reason === 'Unregistered' || reason === 'ExpiredToken' ? 'invalid-token' : 'failed'\n}\n\nconst PROVIDER_TOKEN_TTL_MS = 50 * 60 * 1000 // Apple allows 1h; refresh early.\nconst REQUEST_TIMEOUT_MS = 10_000\n\n/** base64url without padding. */\nfunction b64url(input: Buffer | string): string {\n return Buffer.from(input).toString('base64url')\n}\n\n/** Sign one ES256 JWT for the given signing input with a P-256 private key. */\nexport function es256Jwt(signingInput: string, key: KeyObject): string {\n const signature = cryptoSign('sha256', Buffer.from(signingInput, 'utf8'), {\n key,\n // JOSE/ES256 wants raw r||s; node emits DER by default.\n dsaEncoding: 'ieee-p1363',\n })\n return signingInput + '.' + b64url(signature)\n}\n\n/** Strip PEM armor from a .p8 file and decode to PKCS#8 DER. */\nexport function p8ToDer(pem: string): Buffer {\n const body = pem\n .replace(/-----BEGIN PRIVATE KEY-----/, '')\n .replace(/-----END PRIVATE KEY-----/, '')\n .replace(/\\s+/g, '')\n return Buffer.from(body, 'base64')\n}\n\nexport interface LoadedKey {\n key: KeyObject\n}\n\n/** Pure payload builder so tests can assert the wire format without sockets. */\nexport function apnsPayload(notification: PushDelivery): Record<string, unknown> {\n if ('kind' in notification && notification.kind === 'liveactivity') return { aps: {\n timestamp: notification.timestamp, event: notification.event,\n 'content-state': notification.contentState,\n ...(notification.event === 'end' ? { 'dismissal-date': notification.timestamp + 300 } : { 'stale-date': notification.timestamp + 180 }),\n } }\n if ('kind' in notification && notification.kind === 'widget') return { aps: { 'content-changed': true } }\n const alert = notification as PushNotification\n return alertPayload(alert)\n}\n\nfunction alertPayload(notification: PushNotification): Record<string, unknown> {\n const timeSensitive = notification.category === 'approval.required' || notification.category === 'question.asked'\n return {\n aps: {\n alert: {\n title: notification.title.slice(0, 120),\n body: notification.body.slice(0, 200),\n },\n sound: 'default',\n category: notification.category,\n 'thread-id': notification.hostAudience ? createHash('sha256').update(`${notification.hostAudience}:${notification.sessionId}`).digest('hex') : notification.sessionId.slice(0, 64),\n ...(timeSensitive ? { 'interruption-level': 'time-sensitive' } : {}),\n },\n ...(notification.hostAudience ? { hostAudience: notification.hostAudience } : {}),\n sessionId: notification.sessionId,\n notificationId: notification.notificationId,\n kind: notification.category,\n }\n}\n\n/** One delivery request: the notify projection plus its target device token.\n * The environment comes from the device's own registration (its build kind),\n * so one client serves both sandbox and production devices. */\nexport type ApnsSendRequest = PushDelivery & {\n deviceToken: string\n environment: ApnsEnvironment\n}\n\nexport function pushHeaders(bundleId: string, notification: PushDelivery): Record<string, string> {\n if ('kind' in notification && notification.kind === 'liveactivity') return {\n 'apns-topic': bundleId + '.push-type.liveactivity',\n 'apns-push-type': 'liveactivity', 'apns-priority': notification.event === 'end' ? '10' : '5',\n 'apns-expiration': String(notification.timestamp + 180),\n }\n if ('kind' in notification && notification.kind === 'widget') {\n return {\n 'apns-topic': bundleId + '.push-type.widgets',\n 'apns-push-type': 'widgets',\n 'apns-priority': '5',\n 'apns-collapse-id': 'widget-overview',\n }\n }\n return {\n 'apns-topic': bundleId, 'apns-push-type': 'alert', 'apns-priority': '10',\n 'apns-collapse-id': collapseIdFor(notification as PushNotification),\n }\n}\n\n/** collapse-id accepts ≤64 bytes of ASCII; keep it stable per session+event. */\nexport function collapseIdFor(notification: PushNotification): string {\n const raw = `${notification.hostAudience ? notification.hostAudience + ':' : ''}${notification.category}:${notification.sessionId}`\n const readable = raw.replace(/[^a-zA-Z0-9.:-]/g, '')\n const digest = createHash('sha256').update(raw, 'utf8').digest('hex').slice(0, 12)\n return `${readable.slice(0, 51)}:${digest}`\n}\n\nfunction authorityFor(environment: ApnsEnvironment): string {\n return environment === 'production' ? 'api.push.apple.com' : 'api.sandbox.push.apple.com'\n}\n\nexport class ApnsClient {\n private readonly log: (message: string) => void\n private readonly debug: boolean\n private readonly opts: ApnsClientOptions\n\n private providerToken = ''\n private providerTokenIssuedAt = 0\n private key: KeyObject | undefined\n\n constructor(opts: ApnsClientOptions) {\n this.opts = opts\n this.log = opts.log\n this.debug = opts.debug === true\n }\n\n async dispose(): Promise<void> {\n const sessions = [...this.sessions.values()]\n this.sessions.clear()\n await Promise.all(\n sessions\n .filter((session) => !session.destroyed)\n .map((session) => new Promise<void>((resolve) => session.close(() => resolve()))),\n )\n }\n\n // ---------- credentials ----------\n\n private async ensureProviderToken(): Promise<string> {\n if (this.providerToken && Date.now() - this.providerTokenIssuedAt < PROVIDER_TOKEN_TTL_MS) {\n return this.providerToken\n }\n if (!this.key) {\n const pem = await readFile(this.opts.keyPath, 'utf8')\n this.key = createPrivateKey({ key: p8ToDer(pem), format: 'der', type: 'pkcs8' })\n }\n const issuedAt = Math.floor(Date.now() / 1000)\n const header = b64url(JSON.stringify({ alg: 'ES256', kid: this.opts.keyId }))\n const claims = b64url(JSON.stringify({ iss: this.opts.teamId, iat: issuedAt }))\n this.providerToken = es256Jwt(`${header}.${claims}`, this.key)\n this.providerTokenIssuedAt = Date.now()\n return this.providerToken\n }\n\n // ---------- transport ----------\n\n /** One long-lived HTTP/2 session per Apple host (sandbox + production). */\n private readonly sessions = new Map<string, ClientHttp2Session>()\n\n private ensureSession(authority: string): ClientHttp2Session {\n const existing = this.sessions.get(authority)\n if (existing && !existing.destroyed && !existing.closed) return existing\n const session = http2Connect(`https://${authority}`)\n // Keep a handler attached so background errors never become uncaught\n // exceptions; the next send() recreates the session when dead.\n session.on('error', (error) => {\n if (this.debug) this.log('apns session error (' + authority + '): ' + String(error))\n this.sessions.delete(authority)\n })\n this.sessions.set(authority, session)\n return session\n }\n\n /**\n * Deliver one alert. Never throws — every failure path resolves to an\n * outcome so fan-out loops cannot crash the host on a flaky network.\n */\n async send(request: ApnsSendRequest): Promise<ApnsSendResult> {\n const { deviceToken, environment, ...notification } = request\n let stream: ReturnType<ClientHttp2Session['request']> | undefined\n try {\n const token = await this.ensureProviderToken()\n const body = JSON.stringify(apnsPayload(notification))\n const session = this.ensureSession(authorityFor(environment))\n const done = new Promise<ApnsSendResult>((resolve) => {\n const req = session.request({\n [':method']: 'POST',\n [':path']: '/3/device/' + deviceToken,\n authorization: 'bearer ' + token,\n ...pushHeaders(this.opts.bundleId, notification),\n // Stale approvals arriving hours later are worse than none.\n 'apns-expiration': String(Math.floor(Date.now() / 1000) + 3600),\n 'content-type': 'application/json',\n 'content-length': String(Buffer.byteLength(body)),\n })\n stream = req\n let status = 0\n let responseBody = ''\n const settle = (outcome: ApnsOutcome, reason?: string): void => {\n if (this.debug) {\n this.log(`apns ${outcome}${reason ? ' (' + reason + ')' : ''} (${this.maskToken(deviceToken)})`)\n }\n resolve(reason !== undefined && reason !== '' ? { outcome, reason } : { outcome })\n }\n const timer = setTimeout(() => {\n req.close()\n settle('failed')\n }, REQUEST_TIMEOUT_MS)\n timer.unref?.()\n req.on('response', (headers) => {\n status = Number(headers[':status'] ?? 0)\n })\n req.on('data', (chunk: Buffer) => {\n responseBody += chunk.toString('utf8')\n })\n req.on('error', () => {\n clearTimeout(timer)\n settle('failed')\n })\n req.on('end', () => {\n clearTimeout(timer)\n if (status === 200) return settle('sent')\n let reason = ''\n try {\n reason = String((JSON.parse(responseBody) as { reason?: string }).reason ?? '')\n } catch {\n // non-JSON body; fall through with empty reason\n }\n if (status !== 200 && !reason) reason = 'HTTP ' + String(status)\n // Unregistered/ExpiredToken are authoritative lifecycle verdicts.\n // BadDeviceToken can also mean the provider selected the wrong APNs\n // environment; pruning then destroys a valid registration exactly\n // when the operator needs its stored environment to diagnose config.\n const outcome = classifyApnsReason(reason)\n if (outcome === 'invalid-token') return settle(outcome, reason)\n if (this.debug) this.log(`apns rejected status=${status} reason=${reason}`)\n settle('failed', reason)\n })\n req.end(body)\n })\n return await done\n } catch (error) {\n // Credential load failures and dead sessions land here; force both to be\n // rebuilt on the next attempt.\n this.key = undefined\n this.providerToken = ''\n this.sessions.clear()\n if (this.debug) this.log('apns send failed: ' + String(error))\n return { outcome: 'failed', reason: String(error).slice(0, 120) }\n } finally {\n try { stream?.close() } catch { /* already closed */ }\n }\n }\n\n maskToken(token: string): string {\n return token.length <= 10 ? '…' : token.slice(0, 6) + '…' + token.slice(-4)\n }\n}\n","/**\n * Client for the operator-run push relay (relay/server.js). Used when the App\n * is distributed under the operator's team: bridges cannot hold the\n * distributor's .p8, so they forward notify projections over HTTPS and let\n * the relay do APNs.\n *\n * Outcome contract mirrors src/apns.ts exactly so the dispatcher prunes dead\n * tokens identically on either path:\n * sent | invalid-token (terminal Unregistered/ExpiredToken) | failed\n */\n\nimport type { ApnsEnvironment } from './token.ts'\nimport type { PushDelivery } from './protocol.ts'\nimport { normalizeRelayBaseUrl } from './relay-url.ts'\n\nexport interface RelayClientOptions {\n /** Base URL of the relay, e.g. https://relay.example.com */\n url: string\n /** Per-user bearer token issued by the relay operator (or via enroll). */\n token?: string\n timeoutMs?: number\n debug?: boolean\n log: (message: string) => void\n}\n\nexport interface RelaySendRequest {\n deviceToken: string\n environment: ApnsEnvironment\n notification: PushDelivery\n}\n\nexport class RelayClient {\n private readonly base: string\n private readonly token: string\n private readonly timeoutMs: number\n private readonly debug: boolean\n private readonly log: (message: string) => void\n\n constructor(opts: RelayClientOptions) {\n this.base = normalizeRelayBaseUrl(opts.url)\n this.token = (opts.token ?? '').trim()\n this.timeoutMs = opts.timeoutMs ?? 10_000\n this.debug = opts.debug === true\n this.log = opts.log\n }\n\n /**\n * Zero-touch enrollment: exchange the distributor's shared key (baked into\n * the distributed app) for a stable per-bridge bearer token. Idempotent —\n * relays derive the same token for the same clientId. Returns null on any\n * failure; callers treat that as \"not enrolled yet\", not as an error.\n */\n async enroll(clientId: string, enrollKey: string): Promise<string | null> {\n try {\n const response = await fetch(this.base + '/v1/enroll', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ clientId, enrollKey }),\n signal: AbortSignal.timeout(this.timeoutMs),\n })\n if (!response.ok) {\n if (this.debug) this.log(`enroll http ${response.status}`)\n return null\n }\n const body = (await response.json()) as { token?: unknown }\n if (typeof body.token === 'string' && body.token.startsWith('rl_')) return body.token\n if (this.debug) this.log('enroll returned no usable token')\n return null\n } catch (error) {\n if (this.debug) this.log('enroll failed: ' + String(error))\n return null\n }\n }\n\n async send(request: RelaySendRequest): Promise<{ outcome: 'sent' | 'invalid-token' | 'failed'; reason?: string }> {\n try {\n const response = await fetch(this.base + '/v1/push', {\n method: 'POST',\n headers: {\n authorization: 'Bearer ' + this.token,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n deviceToken: request.deviceToken,\n environment: request.environment,\n notification: request.notification,\n }),\n signal: AbortSignal.timeout(this.timeoutMs),\n })\n if (response.status === 401 || response.status === 429) {\n // Credential/quota problems are configuration errors, not token death;\n // surface as failed so the user fixes the config instead of silently\n // losing registrations.\n if (this.debug) this.log(`relay rejected status=${response.status}`)\n return { outcome: 'failed', reason: 'HTTP ' + String(response.status) }\n }\n if (!response.ok) {\n if (this.debug) this.log(`relay http ${response.status}`)\n return { outcome: 'failed', reason: 'HTTP ' + String(response.status) }\n }\n const body = (await response.json()) as { outcome?: string; reason?: string }\n if (body.outcome === 'sent') return { outcome: 'sent' }\n if (body.outcome === 'invalid-token') return { outcome: 'invalid-token', reason: body.reason }\n if (this.debug) this.log('relay outcome=' + String(body.outcome) + ' reason=' + String(body.reason ?? ''))\n return { outcome: 'failed', reason: body.reason }\n } catch (error) {\n if (this.debug) this.log('relay send failed: ' + String(error))\n const message = error instanceof Error ? error.message.slice(0, 120) : String(error).slice(0, 120)\n return { outcome: 'failed', reason: message }\n }\n }\n}\n","export const DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE = 8\nexport const MAX_FUNNEL_CONNECTIONS_PER_SOURCE = 16\n\nexport function normalizeFunnelConnectionLimit(value: unknown): number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= MAX_FUNNEL_CONNECTIONS_PER_SOURCE\n ? value\n : DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { access, mkdir, readdir, rm, writeFile } from 'node:fs/promises'\nimport { constants as fsConstants } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { expandHome } from './token.ts'\nimport { normalizeFunnelConnectionLimit } from './funnel-policy.ts'\n\nexport type RemotePhase =\n | 'disabled'\n | 'starting'\n | 'login_required'\n | 'online'\n | 'error'\n | 'unavailable'\n | 'stopped'\n\nexport interface RemoteStatus {\n provider: 'tailscale-funnel'\n phase: RemotePhase\n publicURL?: string\n authURL?: string\n message?: string\n updatedAt: number\n}\n\nexport interface RemoteSupervisorOptions {\n enabled: boolean\n hostname: string\n statePath: string\n helperPath?: string\n funnelPort?: 443 | 8443 | 10000\n maxConnectionsPerSource?: number\n log: (message: string) => void\n}\n\ninterface HelperEvent {\n phase?: RemotePhase\n publicURL?: string\n authURL?: string\n message?: string\n}\n\nconst RESTART_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000]\n/**\n * When the helper dies with a Go panic, the supervisor keeps only the last\n * 2KB of stderr for the status message — enough for a summary but not for the\n * full goroutine dump that would pinpoint the crash (and be needed to report\n * upstream). Each crash therefore also writes the full stderr into the state\n * directory as crash-<millis>.log (0600), and the log line points at it.\n * Only the newest dumps are retained to bound disk usage.\n */\nexport const MAX_CRASH_DUMPS = 6\n/**\n * Throttle for configuration-level failures (helper binary missing, state dir\n * unwritable). The environment will not self-heal between attempts, so the\n * previous \"1s..30s exponential\" backoff was a CPU/for-loop on a misconfigured\n * Host. 60s matches the APNs sender-failure throttle on the host plugin\n * (index.ts SENDER_FAILURE_RETRY_MS) and the relay enrollment throttle.\n */\nconst UNAVAILABLE_RETRY_MS = 60_000\n\n/**\n * Exposed for tests: the backoff schedule depends on the failure category\n * (unavailable = config, won't self-heal; crash = transient). Tying this to\n * the constants above keeps the public schedule easy to assert against.\n */\nexport function restartDelayMs(kind: 'unavailable' | 'crash', attempt: number): number {\n if (kind === 'unavailable') return UNAVAILABLE_RETRY_MS\n const index = Math.min(attempt, RESTART_DELAYS_MS.length - 1)\n // RESTART_DELAYS_MS is a non-empty literal array, so the indexed value is\n // always defined; the explicit fallback is just to satisfy the strict\n // noUncheckedIndexedAccess setting without a non-null assertion.\n return RESTART_DELAYS_MS[index] ?? RESTART_DELAYS_MS[RESTART_DELAYS_MS.length - 1]!\n}\n\nexport const DEFAULT_REMOTE_HOSTNAME = 'dsh-deeppilot'\n\n/** Preserve custom node names while migrating every pre-DeepPilot default. */\nexport function normalizeRemoteHostname(value: string | undefined): string {\n const hostname = value?.trim() ?? ''\n if (hostname === '' || ['dsh-phone', 'dsh-pocket', 'harnesspocket'].includes(hostname.toLowerCase())) {\n return DEFAULT_REMOTE_HOSTNAME\n }\n return hostname\n}\n\nexport function tunnelHelperArguments(\n originURL: string,\n statePath: string,\n options: Pick<RemoteSupervisorOptions, 'hostname' | 'funnelPort' | 'maxConnectionsPerSource'>,\n): string[] {\n return [\n '--origin', originURL,\n '--hostname', normalizeRemoteHostname(options.hostname),\n '--state-dir', statePath,\n '--port', String(options.funnelPort ?? 443),\n '--max-connections-per-source', String(normalizeFunnelConnectionLimit(options.maxConnectionsPerSource)),\n ]\n}\n\n/**\n * Summarize a fatal helper crash from its stderr tail. Go panics dump the\n * actual reason on the `panic:` line while the trailing stack frames are\n * `file.go:NN +0xOFF` noise — the old behavior of reporting only the final\n * line surfaced exactly that noise (e.g. `.../singleflight.go:194 +0x45c`)\n * and hid the real panic message. Keep the crash header line (a raw\n * `panic:`, a runtime `fatal error:`, or net/http's `http: panic serving`),\n * plus an optional `[signal ...]` continuation and the first non-runtime\n * stack frame's symbol + `file.go:NN` as a location hint. Pointer offsets\n * are not architecture stable, so they are deliberately dropped.\n *\n * The frame symbol sits on the line just above the indented source line in a\n * Go dump, e.g.:\n * tailscale.com/net/dnscache.(*Resolver).lookupIP(0x1400012c000, {...})\n * tailscale.com@v1.102.3/net/dnscache/dnscache.go:604 +0x25c\n * The first symbol (shortened) is used because a bare `file.go:NN` is not\n * unique across tailscale (singleflight.go is one example).\n */\nexport function helperCrashSummary(stderr: string): string {\n const lines = stderr.split(/\\r?\\n/)\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!.trim()\n if (line === '') continue\n // `panic:` line, a runtime `fatal error:`, or net/http's\n // `http: panic serving` (optionally prefixed by Go's log timestamp).\n const logTimestamp = /^(\\d{4}\\/\\d{2}\\/\\d{2} \\d{2}:\\d{2}:\\d{2} )/.exec(line)?.[1] ?? ''\n if (!/^(panic:|fatal error:|http: panic serving)/.test(logTimestamp.length > 0 ? line.slice(logTimestamp.length) : line)) {\n continue\n }\n let summary = logTimestamp.length > 0 ? line.slice(logTimestamp.length) : line\n const next = lines[i + 1]?.trim()\n if (next?.startsWith('[signal')) summary += ' ' + next\n // Walk the dump for the first non-runtime frame: symbol line followed by\n // an indented `path/file.go:NN` source line. Track the last symbol seen\n // before each source line.\n let lastSymbol: string | undefined\n for (let j = i + 1; j < lines.length; j++) {\n const frame = lines[j]!\n const trimmed = frame.trim()\n if (trimmed === '') continue\n // A symbol/argument line: `package.(*Type).method(args)` — not a source\n // line (which is indented and ends with `file.go:NN +0x…`). Take the\n // last symbol preceding a source line; the first source line after the\n // crash header is the crash point.\n const sourceMatch = /^\\s+(\\S+\\.go:\\d+)/.exec(frame)\n if (sourceMatch !== null) {\n const source = sourceMatch[1]!\n if (source.startsWith('runtime/') || source.startsWith('runtime\\\\')) {\n // runtime/debug.Stack() noise — skip to the next frame.\n lastSymbol = undefined\n continue\n }\n const slash = Math.max(source.lastIndexOf('/'), source.lastIndexOf('\\\\'))\n const file = slash >= 0 ? source.slice(slash + 1) : source\n const symbol = lastSymbol !== undefined ? shortenSymbol(lastSymbol) : undefined\n summary += ' @ ' + (symbol !== undefined ? `${symbol} (${file})` : file)\n break\n }\n // Otherwise this is a frame symbol (or a goroutine heading / created-by\n // note); remember the last one so the following source line can pair.\n if (trimmed.includes('(') || trimmed.endsWith(')')) {\n lastSymbol = trimmed\n }\n }\n return summary.replace(/\\s+/g, ' ').trim()\n }\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i]!.trim()\n if (line !== '') return line\n }\n return ''\n}\n\n/** Shrink a Go frame symbol to `pkg.Receiver.method` form (drop module-root\n * path, generic type arguments and the trailing call arguments), so the\n * summary hint stays readable. Keeps a `.funcN` closure suffix when present\n * (e.g. `doCall.func2`), since it identifies the exact closure.\n *\n * A symbol looks like:\n * tailscale.com/util/singleflight.(*Group[...]).doCall.func2(0x…, …)\n * The trailing call arguments form a balanced paren group that starts at\n * the function name — that group is stripped first; generics appear only\n * inside `(*Group[...])` receiver brackets before the final method dot, so\n * they are removed by trimming from the first `[` to the matching `]`.\n */\nexport function shortenSymbol(symbol: string): string {\n const trimmed = symbol.trim()\n let end = trimmed.length\n if (trimmed.endsWith(')')) {\n let depth = 0\n for (let i = trimmed.length - 1; i >= 0; i--) {\n const ch = trimmed[i]!\n if (ch === ')') depth++\n else if (ch === '(') {\n depth--\n if (depth === 0) {\n end = i\n break\n }\n }\n }\n }\n let name = trimmed.slice(0, end).trim()\n // Remove generic instantiations `[...]` inside receiver/type brackets.\n const bracketOpen = name.indexOf('[')\n if (bracketOpen >= 0) {\n const bracketClose = name.indexOf(']', bracketOpen)\n if (bracketClose > bracketOpen) {\n name = name.slice(0, bracketOpen) + name.slice(bracketClose + 1)\n }\n }\n // Keep only the last path segment (after the final /).\n const slash = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\\\'))\n return slash >= 0 ? name.slice(slash + 1) : name\n}\n\n/** A normalized fatal-crash analysis used by the exit handler to produce a\n * bounded status message and, when a full dump is available, persist it. */\nexport interface CrashAnalysis {\n summary: string\n dumpPath?: string\n}\n\n/** Shared by crash summary and dump: whether the stderr looks like a Go\n * panic/fatal-error crash (vs. an ordinary exit). */\nfunction looksLikeCrash(stderr: string): boolean {\n return /(?:^|\\n)\\s*(?:\\d{4}\\/\\d{2}\\/\\d{2} \\d{2}:\\d{2}:\\d{2} )?(?:panic:|fatal error:|http: panic serving)/.test(stderr)\n}\n\n/** Turn a crash stderr tail into a status message and optionally persist the\n * full dump under the state dir. Keeps at most MAX_CRASH_DUMPS dump files. */\nexport async function analyzeCrashExit(stderr: string, statePath: string): Promise<CrashAnalysis> {\n const summary = helperCrashSummary(stderr) || 'helper exited'\n if (!looksLikeCrash(stderr) || stderr.trim() === '') return { summary }\n const target = statePath.trim()\n if (target === '') return { summary }\n try {\n const file = join(target, `crash-${Date.now()}.log`)\n await writeFile(file, stderr, { mode: 0o600 })\n await trimCrashDumps(target)\n return { summary, dumpPath: file }\n } catch {\n return { summary }\n }\n}\n\n/** Remove oldest crash-*.log files beyond MAX_CRASH_DUMPS. */\nasync function trimCrashDumps(dir: string): Promise<void> {\n let names: string[]\n try {\n names = (await readdir(dir)).filter((name) => name.startsWith('crash-') && name.endsWith('.log'))\n } catch {\n return\n }\n if (names.length <= MAX_CRASH_DUMPS) return\n names.sort()\n const excess = names.length - MAX_CRASH_DUMPS\n await Promise.all(names.slice(0, excess).map((name) => rm(join(dir, name), { force: true }).catch(() => {})))\n}\n\n/** Parse one helper IPC line without ever evaluating or interpolating it. */\nexport function parseHelperEvent(line: string): HelperEvent | null {\n try {\n const value = JSON.parse(line) as Record<string, unknown>\n const phases: RemotePhase[] = ['starting', 'login_required', 'online', 'error', 'stopped']\n if (typeof value.phase !== 'string' || !phases.includes(value.phase as RemotePhase)) return null\n return {\n phase: value.phase as RemotePhase,\n ...(typeof value.publicURL === 'string' ? { publicURL: value.publicURL } : {}),\n ...(typeof value.authURL === 'string' ? { authURL: value.authURL } : {}),\n ...(typeof value.message === 'string' ? { message: value.message.slice(0, 500) } : {}),\n }\n } catch {\n return null\n }\n}\n\nfunction isTailscaleAuthURL(value: string | undefined): boolean {\n if (!value) return false\n try {\n const url = new URL(value)\n return url.protocol === 'https:' &&\n (url.hostname === 'login.tailscale.com' || url.hostname.endsWith('.login.tailscale.com'))\n } catch {\n return false\n }\n}\n\n/** Translate Node's platform/architecture names to the GOOS/GOARCH directory\n * names used by the committed helper matrix. */\nexport function bundledHelperPlatformDir(\n platform: NodeJS.Platform = process.platform,\n arch: string = process.arch,\n): string {\n const goos = platform === 'win32' ? 'windows' : platform\n const goarch = arch === 'x64' ? 'amd64' : arch\n return `${goos}-${goarch}`\n}\n\n/** Build the list of candidate locations for the embedded tunnel helper, in\n * priority order. The first existing executable wins at start() time. The\n * order matters: explicit config (handled by the caller) > npm install\n * layout > DSH-bundled layout > user data dir. */\nexport function bundledHelperCandidates(\n platform: NodeJS.Platform = process.platform,\n arch: string = process.arch,\n): string[] {\n const here = dirname(fileURLToPath(import.meta.url))\n const pkgRoot = resolve(here, '..')\n const fileName = platform === 'win32' ? 'dsh-deeppilot-tunnel.exe' : 'dsh-deeppilot-tunnel'\n const platformDir = bundledHelperPlatformDir(platform, arch)\n\n const candidates: string[] = []\n // 1. Standard npm layout: <pkgRoot>/bin/<os>-<arch>/<file>\n candidates.push(resolve(pkgRoot, 'bin', platformDir, fileName))\n // 2. DSH sometimes relocates lib/ into apps/web or a build cache while\n // leaving bin/ beside the original package root. Try a few hops up.\n candidates.push(resolve(pkgRoot, '..', '..', '..', 'node_modules', 'dsh-deeppilot', 'bin', platformDir, fileName))\n candidates.push(resolve(pkgRoot, '..', '..', 'dsh-deeppilot', 'bin', platformDir, fileName))\n candidates.push(resolve(pkgRoot, '..', '..', '..', '..', 'node_modules', 'dsh-deeppilot', 'bin', platformDir, fileName))\n\n // 3. As a last resort, ask the loader to resolve the binary via Node's\n // package resolution. Works when bin/ is shipped but import.meta.url\n // points somewhere unexpected.\n try {\n const require = createRequire(import.meta.url)\n const resolved = require.resolve(`dsh-deeppilot/bin/${platformDir}/${fileName}`)\n if (!candidates.includes(resolved)) candidates.push(resolved)\n } catch {\n /* package.json exports field may not list bin/ — ignore */\n }\n\n // 4. User data dir fallback so power users can drop a custom build in.\n const home = process.env.DSH_HOME?.trim()\n || process.env.HOME\n || process.env.USERPROFILE\n if (home && home.length > 0) {\n const dataDir = resolve(home, '.dsh')\n candidates.push(join(dataDir, 'deeppilot', 'bin', platformDir, fileName))\n }\n\n return candidates\n}\n\n/** Owns exactly one embedded tunnel helper and restarts it after failures. */\nexport class RemoteSupervisor {\n private child: ChildProcess | undefined\n private restartTimer: NodeJS.Timeout | undefined\n private restartAttempt = 0\n private stopping = false\n private statusValue: RemoteStatus\n\n constructor(private readonly options: RemoteSupervisorOptions) {\n this.statusValue = {\n provider: 'tailscale-funnel',\n phase: options.enabled ? 'stopped' : 'disabled',\n updatedAt: Date.now(),\n }\n }\n\n status(): RemoteStatus {\n return { ...this.statusValue }\n }\n\n async start(originURL: string): Promise<void> {\n if (!this.options.enabled || this.child !== undefined || this.stopping) return\n const statePath = expandHome(this.options.statePath)\n // Resolve a usable helper path. An explicit remote.helperPath wins; if it\n // is missing, fall back to a small set of candidate locations so that\n // DSH-bundled layouts and manually-dropped builds still work.\n const configured = this.options.helperPath?.trim() ?? ''\n const candidates = configured\n ? [expandHome(configured)]\n : bundledHelperCandidates()\n let helper: string | undefined\n let lastError: unknown\n for (const candidate of candidates) {\n try {\n await access(candidate, fsConstants.X_OK)\n helper = candidate\n break\n } catch (error) {\n lastError = error\n }\n }\n if (helper === undefined) {\n // A dispose() that raced these checks must not be overwritten by a\n // late failure report.\n if (this.stopping) return\n const platform = `${process.platform}-${process.arch}`\n const message = configured\n ? `embedded tunnel helper unavailable: ${configured}: ${String(lastError ?? 'not found')}`\n : `embedded tunnel helper not found for ${platform} (tried: ${candidates.join(', ')}); set remote.helperPath to override`\n this.setStatus({ phase: 'unavailable', message })\n this.scheduleRestart(originURL, 'unavailable')\n return\n }\n try {\n await mkdir(statePath, { recursive: true, mode: 0o700 })\n } catch (error) {\n if (this.stopping) return\n this.setStatus({ phase: 'unavailable', message: `cannot create remote state dir: ${String(error)}` })\n this.scheduleRestart(originURL, 'unavailable')\n return\n }\n\n // dispose() may have run while the filesystem checks above were in\n // flight; spawning afterwards would orphan a helper process that nothing\n // will ever reap (dispose already returned seeing no child).\n if (this.stopping) return\n\n this.setStatus({ phase: 'starting', message: undefined })\n const child = spawn(helper, tunnelHelperArguments(originURL, statePath, this.options), {\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n PATH: process.env.PATH ?? '/usr/bin:/bin',\n TMPDIR: process.env.TMPDIR ?? '/tmp',\n },\n })\n this.child = child\n if (child.stdout === null || child.stderr === null) {\n this.setStatus({ phase: 'error', message: 'helper stdio unavailable' })\n child.kill('SIGTERM')\n return\n }\n\n let stdoutBuffer = ''\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => {\n stdoutBuffer += chunk\n const lines = stdoutBuffer.split('\\n')\n stdoutBuffer = lines.pop() ?? ''\n for (const line of lines) this.acceptLine(line)\n })\n\n // Keep enough stderr to write a full crash dump on exit; the summary the\n // user sees is derived from this buffer.\n let stderrBuffer = ''\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => {\n stderrBuffer = (stderrBuffer + chunk).slice(-16_000)\n })\n\n child.once('error', (error) => {\n this.setStatus({ phase: 'error', message: `helper launch failed: ${String(error)}` })\n })\n child.once('exit', () => {\n if (this.child === child) this.child = undefined\n if (this.stopping) {\n this.setStatus({ phase: 'stopped', message: undefined })\n return\n }\n void analyzeCrashExit(stderrBuffer, this.options.statePath).then((analysis) => {\n if (this.stopping) return\n const message = analysis.summary + (analysis.dumpPath !== undefined ? ` (full dump: ${analysis.dumpPath})` : '')\n this.setStatus({\n phase: 'error',\n message,\n })\n this.scheduleRestart(originURL, 'crash')\n })\n })\n }\n\n async dispose(): Promise<void> {\n this.stopping = true\n if (this.restartTimer !== undefined) clearTimeout(this.restartTimer)\n this.restartTimer = undefined\n const child = this.child\n this.child = undefined\n if (child === undefined) {\n this.setStatus({ phase: 'stopped', message: undefined })\n return\n }\n await new Promise<void>((resolveDone) => {\n const force = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL')\n }, 3_000)\n child.once('exit', () => {\n clearTimeout(force)\n resolveDone()\n })\n child.kill('SIGTERM')\n })\n this.setStatus({ phase: 'stopped', message: undefined })\n }\n\n private acceptLine(line: string): void {\n const event = parseHelperEvent(line)\n if (event === null || event.phase === undefined) return\n if (event.phase === 'login_required') {\n // UserLogf is diagnostic output, not a typed auth callback. Accept only\n // the known login origin, and never let an incidental runtime URL knock\n // an already-online Funnel back into the setup state.\n if (this.statusValue.phase === 'online' || !isTailscaleAuthURL(event.authURL)) return\n }\n if (event.phase === 'online') this.restartAttempt = 0\n this.setStatus({ ...event, phase: event.phase })\n }\n\n private scheduleRestart(originURL: string, kind: 'unavailable' | 'crash' = 'crash'): void {\n if (this.stopping || this.restartTimer !== undefined) return\n // Configuration-level failures (helper missing, state dir unwritable)\n // cannot self-heal in a tight loop; throttle to one probe per minute so\n // a misconfigured Host stays observable without becoming a CPU sink.\n // Crashes still get the original exponential backoff so a transient\n // helper failure recovers quickly.\n const delay = kind === 'unavailable'\n ? UNAVAILABLE_RETRY_MS\n : RESTART_DELAYS_MS[Math.min(this.restartAttempt, RESTART_DELAYS_MS.length - 1)]\n if (kind === 'crash') this.restartAttempt += 1\n this.restartTimer = setTimeout(() => {\n this.restartTimer = undefined\n void this.start(originURL)\n }, delay)\n this.restartTimer.unref?.()\n }\n\n private setStatus(next: Partial<RemoteStatus> & Pick<RemoteStatus, 'phase'>): void {\n const cleared: Partial<RemoteStatus> = next.phase === 'online'\n ? { authURL: undefined, message: undefined }\n : next.phase === 'login_required'\n ? { publicURL: undefined, message: undefined }\n : next.phase === 'starting' || next.phase === 'stopped' || next.phase === 'disabled'\n ? { publicURL: undefined, authURL: undefined, message: undefined }\n : {}\n this.statusValue = {\n ...this.statusValue,\n ...cleared,\n ...next,\n updatedAt: Date.now(),\n }\n if (next.phase === 'online') {\n this.options.log('remote Funnel online')\n } else if (next.phase === 'login_required') {\n this.options.log('remote Funnel requires browser authorization')\n } else if (next.phase === 'error' || next.phase === 'unavailable') {\n this.options.log(`remote Funnel ${next.phase}: ${next.message ?? 'unknown error'}`)\n }\n }\n}\n","import { networkInterfaces } from 'node:os'\n\nexport function isPrivateIPv4(address: string): boolean {\n const octets = address.split('.').map(Number)\n if (octets.length !== 4 || octets.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {\n return false\n }\n const [a, b] = octets as [number, number, number, number]\n return a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168)\n}\n\n/** Private IPv4 candidates, preferring physical en* interfaces over tunnels. */\nexport function localLANIPv4Addresses(): string[] {\n const candidates: Array<{ name: string; address: string }> = []\n for (const [name, entries] of Object.entries(networkInterfaces())) {\n for (const entry of entries ?? []) {\n if (entry.family === 'IPv4' && !entry.internal && isPrivateIPv4(entry.address)) {\n candidates.push({ name, address: entry.address })\n }\n }\n }\n const priority = (name: string): number => name === 'en0' ? 0 : name.startsWith('en') ? 1 : name.startsWith('bridge') ? 2 : 3\n candidates.sort((left, right) => priority(left.name) - priority(right.name) || left.name.localeCompare(right.name))\n return [...new Set(candidates.map(({ address }) => address))]\n}\n","/**\n * Lightweight self-update check for dsh-deeppilot.\n *\n * On Host boot we ask the GitHub Releases API (REST) which is the latest\n * stable tag, compare it to the installed plugin version, and surface a\n * \"newer release exists\" flag plus the GitHub release URL through the\n * report Remote. The settings page renders one small line at the bottom;\n * a successful check is enough — no manual button, no persistent cache\n * (the host process is the lifetime of the answer).\n *\n * Deliberately no third-party dependency: we use {@link https.request}\n * directly to keep parity with the rest of the project (remote-supervisor\n * uses node:http, host-bridge uses ws, etc).\n *\n * Failure policy: every network/parse error collapses to a single log\n * line and the in-memory snapshot stays \"unknown\". The bridge must never\n * crash because GitHub rate-limited us, returned a 5xx, or the user is\n * offline.\n */\n\nimport { request as httpsRequest, type RequestOptions } from 'node:https'\n\n/** GitHub repo (no .git suffix). Public, unauthenticated, low rate limit. */\nconst RELEASES_PATH = '/repos/Mars-Sea/dsh-deeppilot/releases'\n\n/** Hard ceiling on the network round-trip. The host must never hang. */\nconst FETCH_TIMEOUT_MS = 8_000\n\n/** Per-page limit. We only need the first stable release, but pre-releases\n * tend to be listed first; fetching 20 gives the comparator enough room. */\nconst PER_PAGE = 20\n\n/**\n * Public snapshot surfaced to the report Remote. `available` is `false`\n * until the network answer lands; on failure it stays `false` so the UI\n * simply doesn't render the \"new version\" hint.\n */\nexport interface UpdateInfo {\n /** Host plugin version (from package.json). */\n currentVersion: string\n /** True once a newer stable release has been found on GitHub. */\n available: boolean\n /** GitHub release page URL, when an update is available. */\n releaseUrl: string | null\n /** Newer stable tag, when an update is available. */\n latestVersion: string | null\n}\n\ninterface GitHubRelease {\n tag_name?: unknown\n prerelease?: unknown\n draft?: unknown\n html_url?: unknown\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction parseStableEntry(value: unknown): { tag: string; url: string | null } | null {\n if (!isPlainObject(value)) return null\n const tag = value.tag_name\n if (typeof tag !== 'string') return null\n if (value.prerelease === true || value.draft === true) return null\n if (parseStableTag(tag) === null) return null\n const url = value.html_url\n return { tag, url: typeof url === 'string' ? url : null }\n}\n\n/** Parse one stable release from the `tag_name` shape `vX.Y.Z` (the v is\n * optional; `1.2.3` is also accepted). Pre-release tags like `0.3.0-rc.1`\n * return null — the policy is \"stable channel only\". */\nexport function parseStableTag(tag: string): { major: number; minor: number; patch: number } | null {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)$/.exec(tag.trim())\n if (match === null) return null\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n }\n}\n\n/** Semver compare for X.Y.Z. Returns -1 / 0 / 1. */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parseStableTag(a)\n const pb = parseStableTag(b)\n if (pa === null && pb === null) return 0\n if (pa === null) return -1\n if (pb === null) return 1\n if (pa.major !== pb.major) return pa.major < pb.major ? -1 : 1\n if (pa.minor !== pb.minor) return pa.minor < pb.minor ? -1 : 1\n if (pa.patch !== pb.patch) return pa.patch < pb.patch ? -1 : 1\n return 0\n}\n\n/** Hit the GitHub Releases API. Resolves with the first stable release\n * GitHub returned, or null if the list contains no stable entries.\n * Network / parse errors reject — the caller is responsible for\n * collapsing them to a log line. */\nexport function fetchLatestStableRelease(): Promise<{ tag: string; url: string | null } | null> {\n return new Promise((resolve, reject) => {\n const options: RequestOptions = {\n method: 'GET',\n host: 'api.github.com',\n path: `${RELEASES_PATH}?per_page=${PER_PAGE}`,\n headers: {\n 'user-agent': 'dsh-deeppilot-update-check',\n 'accept': 'application/vnd.github+json',\n },\n }\n const req = httpsRequest(options, (res) => {\n const status = res.statusCode ?? 0\n if (status < 200 || status >= 300) {\n res.resume()\n reject(new Error(`github releases http ${status}`))\n return\n }\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => chunks.push(chunk))\n res.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf8')\n const parsed = JSON.parse(body) as unknown\n if (!Array.isArray(parsed)) {\n reject(new Error('github releases: response is not an array'))\n return\n }\n for (const entry of parsed) {\n const stable = parseStableEntry(entry)\n if (stable !== null) {\n resolve(stable)\n return\n }\n }\n resolve(null)\n } catch (error) {\n reject(error instanceof Error ? error : new Error(String(error)))\n }\n })\n res.on('error', (error) => reject(error))\n })\n req.setTimeout(FETCH_TIMEOUT_MS, () => {\n req.destroy(new Error('github releases: timeout after ' + FETCH_TIMEOUT_MS + 'ms'))\n })\n req.on('error', (error) => reject(error))\n req.end()\n })\n}\n\n/**\n * Process-wide check state. Constructed once in `apply()`, queried\n * synchronously by the report snapshot. The check itself fires once in\n * the background shortly after boot; the answer lives for the lifetime\n * of the host process — re-running the page in the Web UI does not\n * trigger another network call.\n */\nexport class UpdateChecker {\n private readonly log: (message: string) => void\n private readonly currentVersion: string\n private readonly fetchImpl: typeof fetchLatestStableRelease\n private readonly initialDelayMs: number\n private snapshot: UpdateInfo\n private inflight: Promise<void> | null = null\n\n constructor(options: {\n log: (message: string) => void\n currentVersion: string\n fetchImpl?: typeof fetchLatestStableRelease\n initialDelayMs?: number\n }) {\n this.log = options.log\n this.currentVersion = options.currentVersion\n this.fetchImpl = options.fetchImpl ?? fetchLatestStableRelease\n this.initialDelayMs = options.initialDelayMs ?? 2_000\n this.snapshot = {\n currentVersion: this.currentVersion,\n available: false,\n releaseUrl: null,\n latestVersion: null,\n }\n }\n\n /** Return the current in-memory snapshot — safe to call from any host\n * thread. Never throws, never awaits. */\n get(): UpdateInfo {\n return this.snapshot\n }\n\n /**\n * Schedule one background refresh after the configured initial delay.\n * Used by the plugin entry to do the first check without blocking boot.\n */\n scheduleInitial(): void {\n if (this.initialDelayMs <= 0) {\n void this.runOnce()\n return\n }\n const timer = setTimeout(() => {\n void this.runOnce()\n }, this.initialDelayMs)\n if (typeof (timer as { unref?: () => void }).unref === 'function') {\n (timer as { unref: () => void }).unref()\n }\n }\n\n private async runOnce(): Promise<void> {\n if (this.inflight !== null) {\n await this.inflight\n return\n }\n const task = (async () => {\n try {\n const stable = await this.fetchImpl()\n if (stable === null) {\n // No stable release on GitHub (yet) — leave `available` false.\n return\n }\n if (compareSemver(stable.tag, this.currentVersion) > 0) {\n this.snapshot = {\n currentVersion: this.currentVersion,\n available: true,\n releaseUrl: stable.url,\n latestVersion: stable.tag,\n }\n } else {\n // Up to date. Clear any previous \"available\" state so a host\n // restart after an upgrade immediately stops showing the hint.\n this.snapshot = {\n currentVersion: this.currentVersion,\n available: false,\n releaseUrl: null,\n latestVersion: null,\n }\n }\n } catch (error) {\n this.log('update check failed: ' + (error instanceof Error ? error.message : String(error)))\n // Leave the previous snapshot in place. Even \"no answer\" is a\n // worse signal than the last successful check.\n }\n })()\n this.inflight = task.finally(() => {\n this.inflight = null\n })\n return this.inflight\n }\n\n /** No-op kept for API symmetry with the host lifecycle wiring. */\n dispose(): void {\n // The initial-delay timer is unref'd; nothing to track here.\n }\n}\n","export const DEFAULT_LOCAL_PORT = 3098\nexport const MIN_LOCAL_PORT = 1024\nexport const MAX_LOCAL_PORT = 65_535\n\nexport function normalizeLocalPort(value: unknown): number {\n return typeof value === 'number'\n && Number.isInteger(value)\n && value >= MIN_LOCAL_PORT\n && value <= MAX_LOCAL_PORT\n ? value\n : DEFAULT_LOCAL_PORT\n}\n\nexport function localEndpointURLs(addresses: readonly string[], port: number): string[] {\n const normalizedPort = normalizeLocalPort(port)\n return [...new Set(addresses)].map((address) => `http://${address}:${normalizedPort}`)\n}\n\nexport function localListenError(error: unknown, port: number): string {\n const code = (error as NodeJS.ErrnoException | undefined)?.code\n if (code === 'EADDRINUSE') return `local port ${port} is already in use`\n if (code === 'EACCES') return `permission denied while opening local port ${port}`\n return error instanceof Error ? error.message : String(error)\n}\n","import { join } from 'node:path'\nimport z from '@deepseek-ai/schemastery'\nimport {\n DEFAULT_REMOTE_HOSTNAME,\n} from './remote-supervisor.ts'\nimport { DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE, MAX_FUNNEL_CONNECTIONS_PER_SOURCE } from './funnel-policy.ts'\nimport { bridgeDataDir } from './token.ts'\nimport { DEFAULT_LOCAL_PORT, MAX_LOCAL_PORT, MIN_LOCAL_PORT } from './local-policy.ts'\n\nexport interface Config {\n /** Master switch; when false the plugin activates and does nothing. */\n enabled?: boolean\n /** Protocol-v2 device registry JSON path. */\n devicesPath?: string\n /** Replay ring buffer bound (frames) per deployment. */\n historyBufferMax?: number\n /** Verbose per-frame diagnostics (never prints token or message bodies). */\n debug?: boolean\n /** Independent LAN transport. Never exposes the wider DSH web server. */\n local?: {\n enabled?: boolean\n port?: number\n }\n /** Optional embedded remote transport. Reconciled when settings change. */\n remote?: {\n enabled?: boolean\n provider?: 'tailscale-funnel'\n hostname?: string\n statePath?: string\n helperPath?: string\n funnelPort?: 443 | 8443 | 10000\n /** Concurrent Funnel WebSockets allowed from one public source address. */\n maxConnectionsPerSource?: number\n }\n /**\n * Offline push (F-9). `apns` sends directly from the Mac with the user's\n * Apple credentials. `relay` sends notify projections to an operator-run\n * relay for distributed builds. The device reports its own APNs environment,\n * so development and TestFlight/App Store devices may coexist.\n */\n push?: {\n /** `none` (default), `apns`, or `relay`. */\n provider?: 'none' | 'apns' | 'relay'\n /** Generic mode removes conversation-derived titles and bodies before outbound push. */\n contentMode?: 'preview' | 'generic'\n /** Apple Developer team id (JWT iss claim). */\n teamId?: string\n /** APNs auth key id (JWT kid header). */\n keyId?: string\n /** `.p8` private key path. */\n keyPath?: string\n /** App bundle id — the apns-topic header. */\n bundleId?: string\n /** Relay base URL. */\n relayUrl?: string\n /** Per-user bearer token issued by the relay operator. */\n relayToken?: string\n }\n}\n\n/** Operator-run relay used by distributed builds; overridable via config. */\nexport const DEFAULT_RELAY_URL = 'https://pilot.hailab.dev'\n\nexport const Config = z.object({\n enabled: z.boolean().default(true),\n devicesPath: z.string().default(join(bridgeDataDir(), 'devices-v2.json')),\n historyBufferMax: z.natural().min(100).default(2000),\n debug: z.boolean().default(false),\n local: z.object({\n enabled: z.boolean().default(true),\n port: z.natural()\n .min(MIN_LOCAL_PORT)\n .max(MAX_LOCAL_PORT)\n .default(DEFAULT_LOCAL_PORT)\n .description('DeepPilot 局域网独立端口(默认 3098,修改后本地连接会短暂重连)'),\n }).default({\n enabled: true,\n port: DEFAULT_LOCAL_PORT,\n }),\n remote: z.object({\n enabled: z.boolean().default(false),\n provider: z.union(['tailscale-funnel'] as const).default('tailscale-funnel'),\n hostname: z.string().default(DEFAULT_REMOTE_HOSTNAME),\n statePath: z.string().default(join(bridgeDataDir(), 'tailscale')),\n helperPath: z.string().default(''),\n funnelPort: z.union([443, 8443, 10000] as const).default(443),\n maxConnectionsPerSource: z.natural()\n .min(1)\n .max(MAX_FUNNEL_CONNECTIONS_PER_SOURCE)\n .default(DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE)\n .description('Funnel 每个来源允许的并发连接数(1–16,修改后远程连接会短暂重连)'),\n }).default({\n enabled: false,\n provider: 'tailscale-funnel',\n hostname: DEFAULT_REMOTE_HOSTNAME,\n statePath: join(bridgeDataDir(), 'tailscale'),\n helperPath: '',\n funnelPort: 443,\n maxConnectionsPerSource: DEFAULT_FUNNEL_CONNECTIONS_PER_SOURCE,\n }),\n push: z.object({\n provider: z.union(['none', 'apns', 'relay'] as const).default('none'),\n contentMode: z.union(['preview', 'generic'] as const).default('preview'),\n teamId: z.string().default(''),\n keyId: z.string().default(''),\n keyPath: z.string().default(join(bridgeDataDir(), 'apns', 'AuthKey.p8')),\n bundleId: z.string().default('dev.hailab.deeppilot'),\n relayUrl: z.string().default(DEFAULT_RELAY_URL),\n relayToken: z.string().default(''),\n }).default({\n provider: 'none',\n contentMode: 'preview',\n teamId: '',\n keyId: '',\n keyPath: join(bridgeDataDir(), 'apns', 'AuthKey.p8'),\n bundleId: 'dev.hailab.deeppilot',\n relayUrl: DEFAULT_RELAY_URL,\n relayToken: '',\n }),\n})\n\n/**\n * Cordis hands the second argument in different shapes depending on host\n * composition: a reactive options getter, the resolved config value, or\n * nothing when the patch row omits `config`. Normalize all of them.\n */\nexport function normalizeOptions(options: unknown): Config {\n if (typeof options === 'function') return (options as () => Config)()\n if (options && typeof options === 'object') return options as Config\n const validated = (Config as unknown as (data: unknown) => Config)(undefined)\n return validated ?? {}\n}\n","import type { IncomingMessage } from 'node:http'\nimport { isIP } from 'node:net'\nimport type { Duplex } from 'node:stream'\n\nexport const CLIENT_IP_HEADER = 'x-deeppilot-client-ip'\n\nexport function rejectUpgrade(socket: Duplex, status: number, reason: string, retryAfterSeconds?: number): void {\n const body = JSON.stringify({ error: reason })\n const statusText: Record<number, string> = {\n 401: 'Unauthorized',\n 429: 'Too Many Requests',\n 500: 'Internal Server Error',\n 503: 'Service Unavailable',\n }\n const retryAfter = status === 429 && retryAfterSeconds !== undefined\n ? `Retry-After: ${Math.max(1, Math.ceil(retryAfterSeconds))}\\r\\n`\n : ''\n socket.end(\n 'HTTP/1.1 ' + status + ' ' + (statusText[status] ?? 'Error') + '\\r\\n' +\n retryAfter +\n 'Content-Type: application/json\\r\\n' +\n 'Content-Length: ' + Buffer.byteLength(body) + '\\r\\n' +\n 'Connection: close\\r\\n' +\n '\\r\\n' +\n body,\n )\n}\n\nfunction normalizedAddress(value: string | undefined): string | null {\n if (!value) return null\n const normalized = value.startsWith('::ffff:') ? value.slice(7) : value\n return isIP(normalized) === 0 ? null : normalized\n}\n\nfunction isLoopback(value: string | undefined): boolean {\n const address = normalizedAddress(value)\n return address === '127.0.0.1' || address === '::1'\n}\n\n/**\n * Resolve a stable rate-limit key. The helper-supplied address is trusted only\n * on the private loopback hop; direct clients cannot spoof it.\n */\nexport function requestClientIdentity(\n req: Pick<IncomingMessage, 'headers' | 'socket'>,\n): string {\n if (isLoopback(req.socket.remoteAddress)) {\n const forwarded = req.headers[CLIENT_IP_HEADER]\n const value = Array.isArray(forwarded) ? forwarded[0] : forwarded\n const address = normalizedAddress(value)\n if (address !== null) return address\n }\n return normalizedAddress(req.socket.remoteAddress) ?? 'unknown'\n}\n","export interface AuthRatePolicy {\n windowMs: number\n attemptsPerSource: number\n globalAttempts: number\n maxUnauthenticatedPerSource: number\n failureWindowMs: number\n failuresBeforeBlock: number\n blockMs: number\n maxSources: number\n}\n\nexport const DEFAULT_AUTH_RATE_POLICY: AuthRatePolicy = {\n windowMs: 60_000,\n attemptsPerSource: 12,\n globalAttempts: 120,\n maxUnauthenticatedPerSource: 2,\n failureWindowMs: 10 * 60_000,\n failuresBeforeBlock: 5,\n blockMs: 15 * 60_000,\n maxSources: 4_096,\n}\n\ninterface SourceState {\n attempts: number[]\n failures: number[]\n blockedUntil: number\n active: number\n lastSeen: number\n}\n\nexport interface AuthAdmission {\n ok: boolean\n retryAfterMs: number\n release: () => void\n}\n\nexport interface AuthFailureResult {\n blocked: boolean\n newlyBlocked: boolean\n retryAfterMs: number\n}\n\nconst noop = (): void => {}\n\n/** Bounded in-memory protection for anonymous authentication attempts. */\nexport class AuthRateLimiter {\n private readonly sources = new Map<string, SourceState>()\n private globalAttempts: number[] = []\n\n constructor(private readonly policy: AuthRatePolicy = DEFAULT_AUTH_RATE_POLICY) {}\n\n admit(source: string, now = Date.now()): AuthAdmission {\n const state = this.source(source, now)\n if (state === null) return { ok: false, retryAfterMs: this.policy.windowMs, release: noop }\n this.prune(state, now)\n state.lastSeen = now\n\n if (state.blockedUntil > now) {\n return { ok: false, retryAfterMs: state.blockedUntil - now, release: noop }\n }\n if (state.active >= this.policy.maxUnauthenticatedPerSource) {\n return { ok: false, retryAfterMs: this.policy.windowMs, release: noop }\n }\n if (state.attempts.length >= this.policy.attemptsPerSource) {\n return { ok: false, retryAfterMs: state.attempts[0]! + this.policy.windowMs - now, release: noop }\n }\n this.globalAttempts = this.globalAttempts.filter((ts) => ts > now - this.policy.windowMs)\n if (this.globalAttempts.length >= this.policy.globalAttempts) {\n return { ok: false, retryAfterMs: this.globalAttempts[0]! + this.policy.windowMs - now, release: noop }\n }\n\n state.attempts.push(now)\n this.globalAttempts.push(now)\n state.active += 1\n let released = false\n return {\n ok: true,\n retryAfterMs: 0,\n release: () => {\n if (released) return\n released = true\n state.active = Math.max(0, state.active - 1)\n },\n }\n }\n\n recordFailure(source: string, now = Date.now()): AuthFailureResult {\n const state = this.source(source, now)\n if (state === null) return { blocked: true, newlyBlocked: false, retryAfterMs: this.policy.blockMs }\n this.prune(state, now)\n state.lastSeen = now\n const wasBlocked = state.blockedUntil > now\n state.failures.push(now)\n if (state.failures.length >= this.policy.failuresBeforeBlock) {\n state.blockedUntil = Math.max(state.blockedUntil, now + this.policy.blockMs)\n }\n return {\n blocked: state.blockedUntil > now,\n newlyBlocked: !wasBlocked && state.blockedUntil > now,\n retryAfterMs: Math.max(0, state.blockedUntil - now),\n }\n }\n\n recordSuccess(source: string, now = Date.now()): void {\n const state = this.sources.get(source)\n if (state === undefined) return\n state.failures = []\n state.blockedUntil = 0\n state.lastSeen = now\n }\n\n private source(source: string, now: number): SourceState | null {\n const existing = this.sources.get(source)\n if (existing !== undefined) return existing\n if (this.sources.size >= this.policy.maxSources) this.pruneSources(now)\n if (this.sources.size >= this.policy.maxSources) return null\n const state: SourceState = { attempts: [], failures: [], blockedUntil: 0, active: 0, lastSeen: now }\n this.sources.set(source, state)\n return state\n }\n\n private prune(state: SourceState, now: number): void {\n state.attempts = state.attempts.filter((ts) => ts > now - this.policy.windowMs)\n state.failures = state.failures.filter((ts) => ts > now - this.policy.failureWindowMs)\n if (state.blockedUntil <= now) state.blockedUntil = 0\n }\n\n private pruneSources(now: number): void {\n const staleBefore = now - Math.max(this.policy.failureWindowMs, this.policy.blockMs)\n for (const [source, state] of this.sources) {\n this.prune(state, now)\n if (state.active === 0 && state.blockedUntil === 0 && state.lastSeen < staleBefore) {\n this.sources.delete(source)\n }\n }\n }\n}\n","import type { PushNotification } from './protocol.ts'\nimport { pushScopeFor } from './connection-policy.ts'\n\n/** Prune only when the provider supplies an authoritative token-lifecycle verdict. */\nexport function shouldPrunePushToken(\n outcome: 'sent' | 'invalid-token' | 'failed',\n reason?: string,\n): boolean {\n return outcome === 'invalid-token' && (reason === 'Unregistered' || reason === 'ExpiredToken')\n}\n\n/** APNs requires both registration and the same content permission as WS. */\nexport function mayReceivePush(device: { scopes?: readonly string[] }, notification: unknown): boolean {\n const scope = pushScopeFor('s2c.notify', notification)\n return scope !== undefined && device.scopes?.includes('notifications.register') === true &&\n device.scopes.includes(scope)\n}\n\n/**\n * Zero-touch relay self-heal: HTTP 401 means the relay no longer honors the\n * cached credential. Only auto-enrolled cells with a still-current token may\n * re-derive it; an explicitly configured relay token remains user-owned\n * configuration and is never silently rewritten.\n */\nexport function shouldReEnrollRelayToken(\n transport: 'apns' | 'relay',\n outcome: 'sent' | 'invalid-token' | 'failed',\n reason: string | undefined,\n opts: { usedCellToken: boolean; hasEnrollKey: boolean; tokenStillCurrent: boolean },\n): boolean {\n return (\n transport === 'relay' &&\n outcome === 'failed' &&\n reason === 'HTTP 401' &&\n opts.hasEnrollKey &&\n opts.usedCellToken &&\n opts.tokenStillCurrent\n )\n}\n\n/** Apply before either transport receives the payload, including the Relay. */\nexport function pushContent(notification: PushNotification, mode?: 'preview' | 'generic'): PushNotification {\n if (mode !== 'generic') return notification\n const bodies: Record<PushNotification['category'], string> = {\n 'turn.completed': 'A task has completed.',\n 'approval.required': 'An approval needs your attention.',\n 'question.asked': 'A question needs your answer.',\n 'session.error': 'A task needs your attention.',\n }\n return { ...notification, title: 'DeepPilot', body: bodies[notification.category] ?? 'Open DeepPilot for an update.' }\n}\n","/** Coalesce bursts and bound continuous updates, without starving the trailing\n * state. One scheduler per host, not per token or per streaming text frame. */\nexport class WidgetPushScheduler {\n private timer?: ReturnType<typeof setTimeout>\n private lastSent = 0\n private disposed = false\n private sending = false\n private dirty = false\n\n constructor(private readonly send: () => Promise<void>, private readonly intervalMs = 30_000) {}\n\n changed(): void {\n if (this.disposed) return\n this.dirty = true\n if (this.timer || this.sending) return\n this.timer = setTimeout(() => {\n this.timer = undefined\n this.dirty = false\n this.sending = true\n this.lastSent = Date.now()\n void this.send().catch(() => {}).finally(() => {\n this.sending = false\n if (this.dirty) this.changed()\n })\n }, Math.max(Math.min(1000, this.intervalMs), this.intervalMs - (Date.now() - this.lastSent)))\n this.timer.unref()\n }\n\n dispose(): void {\n this.disposed = true\n if (this.timer) clearTimeout(this.timer)\n this.timer = undefined\n }\n}\n","import type { DeviceStore } from './token.ts'\nimport type { LiveActivityState, LiveActivityPushNotification, SessionSummary } from './protocol.ts'\nimport type { ApnsSendResult } from './apns.ts'\nimport { WidgetPushScheduler } from './widget-push.ts'\n\nexport function liveActivityState(session?: SessionSummary): LiveActivityState {\n const total = Math.max(0, session?.todos?.total ?? 0)\n const done = Math.min(total, Math.max(0, session?.todos?.done ?? 0))\n const task = session?.todoItems?.find(item => item.status === 'in_progress') ??\n session?.todoItems?.find(item => item.status === 'pending')\n return {\n title: Array.from(session?.title ?? '').slice(0, 100).join(''),\n task: Array.from(task?.content ?? '').slice(0, 160).join(''), done, total,\n phase: !session ? 'unavailable' : session.pendingApproval ? 'approval' :\n session.pendingQuestion ? 'question' : session.status === 'running' ? 'running' :\n session.status === 'idle' ? 'ended' : 'unavailable',\n }\n}\n\n/** Persist terminal state before coalescing so a rapid next round cannot revive an activity. */\nexport class LiveActivityPushManager {\n private latest = new Map<string, SessionSummary>()\n private sent = new Map<string, string>()\n private readonly scheduler: WidgetPushScheduler\n constructor(\n private readonly devices: () => DeviceStore | undefined,\n private readonly send: (token: string, environment: 'development' | 'production', notification: LiveActivityPushNotification) => Promise<ApnsSendResult>,\n intervalMs = 15_000,\n ) { this.scheduler = new WidgetPushScheduler(() => this.flush(), intervalMs) }\n\n changed(sessions: SessionSummary[]): void {\n this.latest = new Map(sessions.map(session => [session.id, session]))\n for (const device of this.devices()?.list() ?? []) {\n const r = device.liveActivity\n if (!r) continue\n const state = liveActivityState(this.latest.get(r.sessionId))\n if (state.phase === 'ended' || state.phase === 'unavailable') {\n this.devices()?.endLiveActivity(device.deviceId, r.token, state)\n }\n }\n this.scheduler.changed()\n }\n\n async flush(): Promise<void> {\n const devices = this.devices()\n if (!devices) return\n const valid = new Set<string>()\n for (const device of devices.list()) {\n const r = device.liveActivity\n if (!r) continue\n const key = device.deviceId + ':' + r.token\n valid.add(key)\n if (device.revokedAt !== undefined || !['notifications.register', 'sessions.read', 'interactions.respond'].every(scope => device.scopes?.some(value => value === scope)) || r.expiresAt <= Date.now()) {\n devices.clearLiveActivity(device.deviceId, r.activityId, r.token)\n continue\n }\n const state = r.endedState ?? liveActivityState(this.latest.get(r.sessionId))\n const fingerprint = JSON.stringify(state)\n if (this.sent.get(key) === fingerprint) continue\n // Never send a queued registration after it has rotated or been removed.\n if (devices.authorized(device.deviceId)?.liveActivity?.token !== r.token) continue\n const result = await this.send(r.token, r.environment, {\n kind: 'liveactivity', event: r.endedState ? 'end' : 'update',\n timestamp: Math.floor(Date.now() / 1000), contentState: state,\n }).catch((): ApnsSendResult => ({ outcome: 'failed' }))\n if (result.outcome === 'sent') {\n this.sent.set(key, fingerprint)\n // Retain the terminal tombstone until expiry/unregister: reconnect and token rotation cannot restart this round.\n } else if (result.outcome === 'invalid-token') {\n devices.clearLiveActivity(device.deviceId, r.activityId, r.token)\n } else {\n this.scheduler.changed()\n }\n }\n for (const key of this.sent.keys()) if (!valid.has(key)) this.sent.delete(key)\n }\n dispose(): void { this.scheduler.dispose() }\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport type { Duplex } from 'node:stream'\n\nexport interface PhoneServerHandlers {\n health(req: IncomingMessage, res: ServerResponse): void | Promise<void>\n pair(req: IncomingMessage, res: ServerResponse): void | Promise<void>\n upgrade(req: IncomingMessage, socket: Duplex, head: Buffer): void\n}\n\n/**\n * A deliberately narrow transport listener. Both the LAN endpoint and the\n * loopback-only Funnel origin use this factory, so neither can accidentally\n * inherit DSH's wider web/API route surface.\n */\nexport function createPhoneServer(handlers: PhoneServerHandlers): Server {\n const server = createServer((req, res) => {\n const path = requestPath(req)\n if (path === '/phone/health') {\n void handlers.health(req, res)\n } else if (path === '/phone/pair') {\n void handlers.pair(req, res)\n } else {\n res.statusCode = 404\n res.end('not found')\n }\n })\n server.on('upgrade', (req, socket, head) => {\n if (requestPath(req) !== '/phone') {\n socket.end('HTTP/1.1 404 Not Found\\r\\nConnection: close\\r\\n\\r\\n')\n return\n }\n handlers.upgrade(req, socket, head)\n })\n return server\n}\n\nfunction requestPath(req: IncomingMessage): string {\n try {\n return new URL(req.url ?? '/', 'http://phone.local').pathname\n } catch {\n return '/'\n }\n}\n\nexport function listen(server: Server, port: number, host: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const onError = (error: Error): void => {\n server.off('listening', onListening)\n reject(error)\n }\n const onListening = (): void => {\n server.off('error', onError)\n resolve()\n }\n server.once('error', onError)\n server.once('listening', onListening)\n server.listen(port, host)\n })\n}\n\nexport function closeServer(server: Server | undefined): Promise<void> {\n if (server === undefined || !server.listening) return Promise.resolve()\n return new Promise((resolve) => server.close(() => resolve()))\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { createHash, randomBytes } from 'node:crypto'\nimport { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport type { Duplex } from 'node:stream'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { WebSocketServer } from 'ws'\nimport { BridgeConnection } from './connection.ts'\nimport { HostBridge } from './host-bridge.ts'\nimport type { PushOutlet } from './host-bridge.ts'\nimport { Dsh012ApiProxy, type DshInteractionKind } from './dsh012-api-proxy.ts'\nimport type { SettingsSectionHooks } from '@deepseek-ai/dsh-settings'\nimport { applyReportRemote } from './report-remote.ts'\nimport { runRelayProbe } from './relay-test.ts'\nimport type { DeepPilotReport, PushTestResult } from './report-wire.ts'\nimport { DeviceStore, MAX_DEVICES, bridgeDataDir, ensurePrivateBridgeDataDir, expandHome, migrateLegacyBridgeDataDir } from './token.ts'\nimport type { ApnsEnvironment } from './token.ts'\nimport {\n PairingCodeManager,\n deviceIdForPublicKey,\n loadOrCreateHostAudience,\n normalizeDeviceScopes,\n} from './device-auth.ts'\nimport { ApnsClient } from './apns.ts'\nimport { RelayClient } from './relay-client.ts'\nimport type { PushNotification } from './protocol.ts'\nimport {\n DEFAULT_REMOTE_HOSTNAME,\n normalizeRemoteHostname,\n RemoteSupervisor,\n type RemoteStatus,\n} from './remote-supervisor.ts'\nimport { normalizeFunnelConnectionLimit } from './funnel-policy.ts'\nimport { localLANIPv4Addresses } from './local-address.ts'\nimport { UpdateChecker, type UpdateInfo } from './update-check.ts'\nimport { Config, DEFAULT_RELAY_URL, normalizeOptions } from './config.ts'\nimport type { Config as PluginConfig } from './config.ts'\nimport { rejectUpgrade, requestClientIdentity } from './phone-http.ts'\nimport { AuthRateLimiter } from './auth-rate-limit.ts'\nimport { pushContent, mayReceivePush, shouldPrunePushToken, shouldReEnrollRelayToken } from './push-policy.ts'\nimport { LiveActivityPushManager } from './live-activity.ts'\nimport { WidgetPushScheduler } from './widget-push.ts'\nimport type { PushDelivery } from './protocol.ts'\nimport { MAX_APP_VERSION_CHARS, MAX_DEVICE_NAME_CHARS, sanitizeDeviceField } from './connection-policy.ts'\nimport { DEFAULT_LOCAL_PORT, localEndpointURLs, localListenError, normalizeLocalPort } from './local-policy.ts'\nimport { closeServer, createPhoneServer, listen } from './phone-server.ts'\n\n/**\n * dsh-deeppilot — data bridge between the DSH host and DeepPilot\n * clients. Owns independent, narrowly routed LAN and Funnel-origin listeners;\n * temporary compatibility routes remain on the existing DSH web server. The\n * web UI and the rest of DSH's API are never exposed by these listeners.\n *\n * Data plane: an in-process HostBridge consumes a local compatibility façade\n * over DSH 0.1.2 Session/Workspace controllers, mirrors session summaries,\n * tracks pending approvals/questions, and fans projected protocol-v2 pushes\n * out to every connected device.\n *\n * Protocol: PROTOCOL.md is normative; src/protocol.ts and the private app's\n * Swift models mirror that v2 contract.\n */\n\nexport const name = 'deeppilot'\n\nexport { HostBridge } from './host-bridge.ts'\nexport { Config } from './config.ts'\nexport { mayReceivePush, shouldPrunePushToken, shouldReEnrollRelayToken } from './push-policy.ts'\n\n/** No eager web-service requirement: independent transports start on their own. */\nexport const inject: string[] = []\n\n\ninterface WebServerLike {\n register(route: {\n kind: 'exact' | 'prefix'\n path: string\n handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>\n }): () => void\n registerUpgrade(route: {\n path: string\n handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void\n }): () => void\n}\n\ntype SubContext = {\n effect: (setup: () => unknown, name?: string) => unknown\n}\n\nconst SERVER_VERSION = readOwnPackageVersion()\nconst MAX_CLIENT_CONNECTIONS = 16\n/**\n * Single-frame bound. Covers the protocol maximum (4 × 8 MB base64 images\n * plus prompt text) with headroom while keeping an unauthenticated client's\n * pre-hello buffering far below ws's 100 MiB default.\n */\nconst MAX_FRAME_BYTES = 64 * 1024 * 1024\n\n/**\n * Resolve the host plugin's own version from the installed package.json.\n * Sourced at boot so the wire / UI always agrees with what npm published.\n * `createRequire(import.meta.url)` is the tsdown-bundled ESM equivalent of\n * CommonJS's `require`; the package.json sits next to lib/index.js after\n * the build, so `../package.json` resolves to the published manifest.\n */\nfunction readOwnPackageVersion(): string {\n try {\n const require_ = createRequire(import.meta.url)\n const pkg = require_('../package.json') as { version?: unknown }\n if (typeof pkg.version === 'string' && pkg.version.length > 0) return pkg.version\n } catch {\n // fall through to env / hardcoded default below\n }\n // `npm` injects this for `npm run` / `npm exec` / `npm start` invocations.\n // `process.env.npm_package_version` is unset when DSH loads the plugin\n // directly, so we keep it as a secondary source rather than the truth.\n const envVersion = process.env.npm_package_version\n if (typeof envVersion === 'string' && envVersion.length > 0) return envVersion\n return '0.0.0+unknown'\n}\n\nexport function apply(ctx: Context, options: unknown): void {\n const cfg = normalizeOptions(options)\n\n const log = (message: string): void => {\n console.log('[deeppilot] ' + message)\n }\n const auditSalt = randomBytes(32)\n const auditLabel = (value: string): string => createHash('sha256')\n .update(auditSalt)\n .update(value)\n .digest('hex')\n .slice(0, 12)\n\n /**\n * Settings-section source: while a settings service is attached this holds\n * the user-edited section value; otherwise the composition defaults. Read\n * through currentConfig() everywhere (normalizeOptions prefers it).\n */\n let liveSource: (() => Config) | undefined\n let scheduleRemoteReconcile: (() => void) | undefined\n let scheduleLocalReconcile: (() => void) | undefined\n const currentConfig = (): Config => {\n if (liveSource !== undefined) return normalizeOptions(liveSource())\n return normalizeOptions(options)\n }\n const enabledNow = (): boolean => currentConfig().enabled === true\n\n // Web settings page: a \"deeppilot\" section with the plugin knobs.\n // Values persist through the settings document and re-enter via setSource;\n // `enabled` decides whether the bridge starts at all (next restart). This is\n // registered unconditionally so the master switch stays reachable even while\n // the bridge is off — otherwise a disabled bridge could never be re-enabled.\n const settingsHooks: SettingsSectionHooks<PluginConfig> = {\n setSource: (source) => {\n liveSource = source\n // Defer one microtask so the settings service can finish publishing the\n // new source before either transport runtime reads it.\n queueMicrotask(() => {\n scheduleLocalReconcile?.()\n scheduleRemoteReconcile?.()\n })\n },\n onChange: () => queueMicrotask(() => {\n scheduleLocalReconcile?.()\n scheduleRemoteReconcile?.()\n }),\n }\n ctx.inject(['settings'], (settingsCtx) => {\n settingsCtx.settings.installSection(\n ctx,\n 'deeppilot',\n Config,\n normalizeOptions(undefined),\n settingsHooks,\n )\n })\n\n // Master switch, resolved against the latest available settings document.\n // Individual injected services also read currentConfig() when they activate.\n if (currentConfig().enabled !== true) {\n log('disabled via settings; bridge stays inactive (rumors of /phone below are skipped)')\n }\n\n // Resolved asynchronously; route handlers await readiness. Never rejects:\n // a storage failure degrades the bridge instead of killing the host.\n const dataDir = bridgeDataDir()\n\n // ---------- zero-touch push enrollment (distributed builds) ----------\n\n /**\n * Persistent relay-enrollment cell (deeppilot/push-relay.json). A\n * distributed app presents the distributor's shared enrollKey during\n * c2s.push.register; the bridge then auto-enables relay mode, enrolls with\n * the operator's relay and caches the issued token. Users never fill in\n * anything; explicit config always wins over the auto flag.\n */\n interface RelayEnrollmentCell {\n clientId?: string\n autoRelay?: boolean\n enrollKey?: string\n token?: string\n }\n const pushRelayPath = join(dataDir, 'push-relay.json')\n const enrollmentCell: RelayEnrollmentCell = {}\n let enrollmentWriteTail: Promise<void> = Promise.resolve()\n\n function persistEnrollment(): void {\n const snapshot = JSON.stringify({ version: 1, ...enrollmentCell }, null, 2) + '\\n'\n enrollmentWriteTail = enrollmentWriteTail.then(async () => {\n const tempPath = pushRelayPath + '.' + randomBytes(6).toString('hex') + '.tmp'\n try {\n await mkdir(dataDir, { recursive: true })\n await writeFile(tempPath, snapshot, { mode: 0o600 })\n await rename(tempPath, pushRelayPath)\n } catch {\n await unlink(tempPath).catch(() => {})\n // best-effort persistence; enrollment retries on next trigger\n }\n })\n }\n\n /** Fired from BridgeConnection when an app presents its built-in key. */\n const handlePushEnrollKey = async (enrollKey: string): Promise<void> => {\n if (enrollmentCell.enrollKey !== enrollKey) {\n enrollmentCell.enrollKey = enrollKey\n }\n const configuredProvider = currentConfig().push?.provider\n // Only flip when the user has not made an explicit choice.\n if (!configuredProvider || configuredProvider === 'none') {\n if (!enrollmentCell.autoRelay) {\n enrollmentCell.autoRelay = true\n log('push relay mode auto-enabled by enrolled app')\n }\n }\n persistEnrollment()\n // Enroll inline so the register handler sees final readiness: the first\n // offline notification must not depend on a reconnect.\n const url = (currentConfig().push?.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n await ensureRelayEnrolled(url)\n }\n const pairingCodes = new PairingCodeManager()\n const auth: { audience: string | null; devices: DeviceStore | null } = {\n audience: null,\n devices: null,\n }\n const ready = (async () => {\n try {\n try {\n const migratedFrom = await migrateLegacyBridgeDataDir()\n if (migratedFrom !== null) log(`migrated legacy plugin state from ${migratedFrom} to ${dataDir}`)\n } catch (error) {\n log('legacy plugin-state migration skipped: ' + String(error))\n }\n await ensurePrivateBridgeDataDir()\n auth.audience = await loadOrCreateHostAudience(join(dataDir, 'host-id'))\n auth.devices = await DeviceStore.load(cfg.devicesPath ?? join(dataDir, 'devices-v2.json'))\n {\n // Startup visibility: makes \"registrations vanished after restart\"\n // instantly diagnosable (0 push rows ⇒ the file itself lost data).\n const rows = auth.devices.list()\n const registered = rows.filter((row) => row.apns !== undefined).length\n log(`device registry loaded from ${expandHome(cfg.devicesPath ?? join(dataDir, 'devices-v2.json'))}: ${rows.length} device(s), ${registered} push registration(s)`)\n }\n // Restore zero-touch push enrollment state (best effort).\n try {\n const raw = JSON.parse(await readFile(pushRelayPath, 'utf8')) as RelayEnrollmentCell\n if (typeof raw.clientId === 'string') enrollmentCell.clientId = raw.clientId\n if (typeof raw.enrollKey === 'string') enrollmentCell.enrollKey = raw.enrollKey\n if (typeof raw.token === 'string') enrollmentCell.token = raw.token\n if (raw.autoRelay === true) enrollmentCell.autoRelay = true\n } catch {\n // first boot: no enrollment yet\n }\n } catch (error) {\n const message = String(error)\n log('auth material unavailable, bridge degraded: ' + message)\n return { audience: null, devices: null }\n }\n return { audience: auth.audience, devices: auth.devices }\n })()\n\n const beginPairing = async (): Promise<{ code: string; expiresAt: number; audience: string }> => {\n await ready\n if (auth.audience === null || auth.devices === null) throw new Error('device authentication unavailable')\n return { ...pairingCodes.issue(), audience: auth.audience }\n }\n\n /**\n * Settings-page push self-test: force one synthetic notification down the\n * active pathway to EVERY registered device, deliberately ignoring the\n * connected-skip and category-mute filters — an explicit user action must\n * always be able to prove delivery end to end.\n */\n const runPushSelfTest = async (): Promise<PushTestResult> => {\n const resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok) {\n return {\n transport: 'none',\n overall: 'not-configured',\n message: '推送未启用(' + resolved.reason + ')。可先用「测试访问与注册」完成中继注册,或在配置中设置 push.provider',\n results: [],\n }\n }\n const tokenized = (auth.devices?.list() ?? []).filter((device) => device.apns !== undefined)\n if (!auth.devices || tokenized.length === 0) {\n return {\n transport: resolved.value.kind,\n overall: 'no-targets',\n message: '还没有设备注册离线推送——在手机上打开 DeepPilot 并允许系统通知,等状态变为「已就绪」后再试',\n results: [],\n }\n }\n const send = await senderFor(resolved.value)\n if (!send) {\n return { transport: resolved.value.kind, overall: 'failed', message: '发送通道不可用(检查 .p8 密钥文件或中继配置)', results: [] }\n }\n const notification: PushNotification = {\n notificationId: 'test-' + Date.now(),\n category: 'turn.completed',\n sessionId: 'push-test',\n title: 'DeepPilot 测试推送',\n body: '收到这条通知说明离线推送链路正常',\n }\n const results = await Promise.all(tokenized.map(async (device) => {\n const registration = device.apns!\n const { outcome, reason } = await send({\n deviceToken: registration.token,\n environment: registration.environment,\n notification,\n })\n return {\n name: device.deviceName,\n environment: registration.environment,\n outcome,\n // First 10 hex chars let the operator verify the stored token matches\n // what the device currently holds (tokens rotate on reinstall).\n tokenFingerprint: registration.token.slice(0, 10),\n ...(reason !== undefined ? { reason } : {}),\n }\n }))\n const overall: PushTestResult['overall'] = results.some((r) => r.outcome === 'sent') ? 'sent' : 'failed'\n log('push self-test: ' + overall + ' (' + results.map((r) => `\"${r.name}\"=${r.outcome}${r.reason ? '/' + r.reason : ''}`).join(', ') + ')')\n return { transport: resolved.value.kind, overall, results }\n }\n\n const connections = new Set<BridgeConnection>()\n\n const closeConnectionsForBridge = (bridge: HostBridge): void => {\n for (const connection of connections) {\n if (!connection.isAttachedTo(bridge)) continue\n connection.closeForServerStop()\n connections.delete(connection)\n }\n }\n\n const closeAllConnections = (): void => {\n for (const connection of connections) connection.closeForServerStop()\n connections.clear()\n }\n\n // ---------- offline push outlet (F-9) ----------\n\n type PushConfigSnapshot =\n | { kind: 'apns'; teamId: string; keyId: string; keyPath: string; bundleId: string }\n | { kind: 'relay'; url: string; token: string }\n\n const resolvePushConfig = (config: Config): { ok: true; value: PushConfigSnapshot } | { ok: false; reason: string } => {\n const push = config.push ?? {}\n // Auto-enabled by an enrolled distributed app when the user made no\n // explicit provider choice.\n const configured = push.provider ?? 'none'\n const effectiveProvider = configured === 'none' && enrollmentCell.autoRelay === true ? 'relay' : configured\n if (effectiveProvider === 'relay') {\n const url = (push.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n const token = (push.relayToken ?? '').trim() || enrollmentCell.token || ''\n if (!/^https:\\/\\//i.test(url)) return { ok: false, reason: 'relayUrl must be an https URL' }\n if (!token) return { ok: false, reason: 'relay token not enrolled yet' }\n return { ok: true, value: { kind: 'relay', url, token } }\n }\n if (effectiveProvider === 'apns') {\n const teamId = (push.teamId ?? '').trim()\n const keyId = (push.keyId ?? '').trim()\n const keyPath = expandHome((push.keyPath ?? '').trim() || join(dataDir, 'apns', 'AuthKey.p8'))\n const bundleId = (push.bundleId ?? '').trim()\n if (!teamId || !keyId || !bundleId) return { ok: false, reason: 'teamId/keyId/bundleId missing' }\n return { ok: true, value: { kind: 'apns', teamId, keyId, keyPath, bundleId } }\n }\n return { ok: false, reason: 'provider disabled' }\n }\n\n /**\n * Zero-touch enrollment against the operator's relay. Idempotent and\n * cached in the persistent cell; a failure disables push for this config\n * fingerprint with one log line until something changes.\n */\n let enrollAttemptFor: string | undefined\n let enrollLastAttemptAt = 0\n const ensureRelayEnrolled = async (url: string): Promise<string | undefined> => {\n // The enrollment body carries the distributor's shared key; a mis-typed\n // http:// relayUrl must never leak it in cleartext. (Send-path requests\n // are already gated by resolvePushConfig — enrollment call sites are not.)\n if (!/^https:\\/\\//i.test(url.trim())) {\n log('push relay enrollment refused: relayUrl must be an https URL')\n return undefined\n }\n if (enrollmentCell.token) return enrollmentCell.token\n const fingerprint = url + ':' + String(enrollmentCell.enrollKey ?? '')\n if (fingerprint !== enrollAttemptFor) {\n enrollAttemptFor = fingerprint\n enrollLastAttemptAt = 0\n }\n // Same fingerprint failing repeatedly: throttle to one attempt/minute so\n // a down relay cannot turn every notification into an outbound storm,\n // while transient failures still recover quickly.\n if (Date.now() - enrollLastAttemptAt < 60_000) return undefined\n enrollLastAttemptAt = Date.now()\n try {\n if (!enrollmentCell.clientId) {\n enrollmentCell.clientId = 'u_' + randomBytes(16).toString('base64url')\n persistEnrollment()\n }\n const client = new RelayClient({ url, debug: currentConfig().debug === true, log })\n const token = await client.enroll(enrollmentCell.clientId, enrollmentCell.enrollKey ?? '')\n if (!token) {\n log('push relay enrollment failed (' + url + '); will retry on next trigger')\n return undefined\n }\n enrollmentCell.token = token\n persistEnrollment()\n log('push relay enrollment succeeded')\n return token\n } catch (error) {\n log('push relay enrollment error: ' + String(error))\n return undefined\n }\n }\n\n interface SendOutcome { outcome: 'sent' | 'invalid-token' | 'failed'; reason?: string }\n type PushSender = (\n request: { deviceToken: string; environment: ApnsEnvironment; notification: PushDelivery },\n ) => Promise<SendOutcome>\n\n interface CachedSender {\n fingerprint: string\n send: PushSender\n dispose?: () => Promise<void>\n }\n let cachedSender: CachedSender | undefined\n /**\n * Last failed APNs-sender build. The config fingerprint cannot see the\n * filesystem, so remembering a failure forever meant \"copy the .p8 into\n * place later\" never recovered without an edit or restart; throttle the\n * retry by time instead — same pattern as relay enrollment below.\n */\n let senderFailedFor: { fingerprint: string; at: number } | undefined\n const SENDER_FAILURE_RETRY_MS = 60_000\n\n /**\n * Lazily build the push sender for the current config. A broken config\n * (unreadable .p8) disables push for that fingerprint with exactly one log\n * line instead of failing on every event.\n */\n const senderFor = async (resolved: PushConfigSnapshot): Promise<PushSender | undefined> => {\n const fingerprint = JSON.stringify(resolved)\n if (cachedSender?.fingerprint === fingerprint) return cachedSender.send\n // A recent failure only blocks retries for a short window: a permanently\n // broken config must not log-storm on every event, but the same config\n // with the key file since added MUST get another chance.\n if (\n senderFailedFor?.fingerprint === fingerprint &&\n Date.now() - senderFailedFor.at < SENDER_FAILURE_RETRY_MS\n ) {\n return undefined\n }\n if (cachedSender) {\n await cachedSender.dispose?.().catch(() => {})\n cachedSender = undefined\n }\n if (resolved.kind === 'relay') {\n // resolvePushConfig already guarantees a token exists in the cell\n // (config token or a completed enrollment).\n const client = new RelayClient({ url: resolved.url, token: resolved.token, debug: currentConfig().debug === true, log })\n cachedSender = {\n fingerprint,\n send: (request) => client.send(request),\n }\n log('push relay enabled')\n } else {\n try {\n await readFile(expandHome(resolved.keyPath), 'utf8')\n } catch (error) {\n senderFailedFor = { fingerprint, at: Date.now() }\n log('apns push unavailable (key unreadable at ' + resolved.keyPath + '): ' + String(error))\n return undefined\n }\n const client = new ApnsClient({\n teamId: resolved.teamId,\n keyId: resolved.keyId,\n keyPath: resolved.keyPath,\n bundleId: resolved.bundleId,\n debug: currentConfig().debug === true,\n log,\n })\n cachedSender = {\n fingerprint,\n send: (request) => client.send({\n ...request.notification,\n deviceToken: request.deviceToken,\n environment: request.environment,\n }),\n dispose: () => client.dispose(),\n }\n log('apns push enabled')\n }\n senderFailedFor = undefined\n return cachedSender.send\n }\n\n /**\n * Fan one notification-worthy event out to paired devices holding an APNs\n * token. Rules:\n * - devices with a live WebSocket are skipped (they already got the WS\n * frame and will raise the local notification themselves);\n * - only devices granted `notifications.register` are candidates — a\n * device whose scope was revoked must not receive offline pushes\n * (R1/P2 S→C permission policy);\n * - each device is delivered on ITS registered environment (the build\n * kind it self-reported), so sandbox and production devices coexist;\n * - the device's per-category switches suppress muted categories;\n * - only APNs' terminal Unregistered/ExpiredToken verdicts prune storage;\n * BadDeviceToken may be an environment mismatch and stays diagnosable.\n */\n const widgetPush = new WidgetPushScheduler(async () => {\n if (!enabledNow()) return\n const resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok) return\n const devices = auth.devices\n const send = await senderFor(resolved.value)\n if (!devices || !send) return\n const sent = new Set<string>()\n for (const device of devices.list()) {\n const registration = device.widgetApns\n if (!registration || device.revokedAt !== undefined ||\n !(['notifications.register', 'sessions.read', 'interactions.respond'] as const).every(scope =>\n device.scopes?.includes(scope)) ||\n Date.now() - registration.updatedAt > 7 * 24 * 60 * 60 * 1000) continue\n const key = registration.environment + ':' + registration.token\n if (sent.has(key)) continue\n sent.add(key)\n const { outcome, reason } = await send({\n deviceToken: registration.token, environment: registration.environment,\n notification: { kind: 'widget' },\n })\n if (shouldPrunePushToken(outcome, reason)) {\n devices.clearWidgetPushToken(device.deviceId, registration.token)\n }\n if (resolved.value.kind === 'relay' && reason === 'HTTP 401' &&\n enrollmentCell.token === resolved.value.token && enrollmentCell.enrollKey) {\n enrollmentCell.token = undefined\n persistEnrollment()\n await ensureRelayEnrolled(resolved.value.url)\n }\n }\n })\n\n const liveActivityPush = new LiveActivityPushManager(() => auth.devices ?? undefined, async (deviceToken, environment, notification) => {\n if (!enabledNow()) return { outcome: 'failed' }\n const resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok) return { outcome: 'failed' }\n const send = await senderFor(resolved.value)\n if (!send) return { outcome: 'failed' }\n const result = await send({ deviceToken, environment, notification })\n if (resolved.value.kind === 'relay' && result.reason === 'HTTP 401' &&\n enrollmentCell.token === resolved.value.token && enrollmentCell.enrollKey) {\n enrollmentCell.token = undefined\n persistEnrollment()\n await ensureRelayEnrolled(resolved.value.url)\n }\n return result\n })\n\n const makePushOutlet = (): PushOutlet => ({\n widgetChanged: () => widgetPush.changed(),\n liveActivityChanged: sessions => liveActivityPush.changed(sessions),\n // The capability bit must tell the truth: only advertise push when the\n // provider is fully configured, otherwise clients would suppress their\n // local banners expecting a delivery that never happens.\n isAvailable: () => {\n const resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok) return false\n // Relay mode is only truly ready once enrollment produced a token;\n // advertising earlier would make clients suppress their local banners\n // for deliveries that cannot happen yet.\n if (resolved.value.kind === 'relay' && !resolved.value.token) return false\n return true\n },\n fanOut: (sourceNotification) => {\n const notification = pushContent({ ...sourceNotification, hostAudience: auth.audience ?? undefined }, currentConfig().push?.contentMode)\n void (async () => {\n let resolved = resolvePushConfig(currentConfig())\n if (!resolved.ok && resolved.reason === 'relay token not enrolled yet') {\n // A registration carried the enrollKey but enrollment has not run —\n // try once now, then re-resolve.\n const relayUrl = (currentConfig().push?.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n await ensureRelayEnrolled(relayUrl)\n resolved = resolvePushConfig(currentConfig())\n }\n if (!resolved.ok) return\n const devices = auth.devices\n if (!devices) return\n const send = await senderFor(resolved.value)\n if (!send) return\n const transport = resolved.value.kind\n const connectedIds = new Set<string>()\n for (const connection of connections) {\n const id = connection.connectedDeviceId\n if (id && connection.suppressesAlertPush) connectedIds.add(id)\n }\n // Observability first: push failures used to be completely silent\n // (outcomes were debug-gated), which made field diagnosis impossible.\n // Every dispatch and every skip now leaves one flat log line —\n // categories and outcomes only, never message bodies.\n const candidates = devices.list().filter((device) => {\n const registration = device.apns\n if (!registration) return false\n if (connectedIds.has(device.deviceId)) return false\n if (!mayReceivePush(device, notification)) {\n if (currentConfig().debug === true) {\n log(`push skip \"${device.deviceName}\": notification permission not granted`)\n }\n return false\n }\n if (registration.categories?.[notification.category] === false) {\n if (currentConfig().debug === true) {\n log(`push skip \"${device.deviceName}\": category ${notification.category} muted`)\n }\n return false\n }\n return true\n })\n if (candidates.length === 0) {\n const tokenized = devices.list().filter((device) => device.apns !== undefined).length\n log(`push(${transport}) ${notification.category}: no offline targets (connected=${connectedIds.size}, tokenized=${tokenized})`)\n return\n }\n // Relay self-heal inputs, resolved once per dispatch: the URL we are\n // actually sending through, and whether the credential came from the\n // zero-touch cell (explicit relayToken configs are never rewritten).\n const relayUrl = resolved.value.kind === 'relay' ? resolved.value.url : undefined\n const relayTokenUsed = resolved.value.kind === 'relay' ? resolved.value.token : undefined\n const usedCellToken = relayTokenUsed !== undefined && relayTokenUsed === enrollmentCell.token\n const hasEnrollKey = Boolean(enrollmentCell.enrollKey)\n for (const device of candidates) {\n const registration = device.apns!\n void send({ deviceToken: registration.token, environment: registration.environment, notification })\n .then(({ outcome, reason }) => {\n log(`push(${transport}) ${notification.category} → \"${device.deviceName}\" [${registration.environment}] = ${outcome}${reason ? ' (' + reason + ')' : ''}`)\n if (shouldPrunePushToken(outcome, reason)) {\n devices.clearPushToken(device.deviceId)\n log(`push: pruned stale token of \"${device.deviceName}\" (${reason ?? 'unknown'}) — app re-registers on next launch`)\n return\n }\n if (\n relayUrl !== undefined &&\n shouldReEnrollRelayToken(transport, outcome, reason, {\n usedCellToken,\n hasEnrollKey,\n // Compare-and-clear: a delayed 401 from another request sent\n // with the old credential must not erase a token that an\n // earlier callback has already refreshed.\n tokenStillCurrent: enrollmentCell.token === relayTokenUsed,\n })\n ) {\n // The relay no longer honors the cached credential. Drop it and\n // re-derive from the enroll key; ensureRelayEnrolled's own\n // throttle keeps parallel 401s from storming the endpoint, and\n // senderFor's config fingerprint rebuilds the client with the\n // fresh token on the next dispatch.\n enrollmentCell.token = undefined\n persistEnrollment()\n log('push relay credential rejected (HTTP 401); re-enrolling')\n void ensureRelayEnrolled(relayUrl)\n }\n })\n .catch(() => {})\n }\n })()\n },\n })\n\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_FRAME_BYTES })\n let remoteSupervisor: RemoteSupervisor | undefined\n let localState: DeepPilotReport['local'] = {\n phase: currentConfig().enabled === true && currentConfig().local?.enabled !== false ? 'starting' : 'disabled',\n port: normalizeLocalPort(currentConfig().local?.port),\n endpoints: [],\n updatedAt: Date.now(),\n }\n const localStatus = (addresses: readonly string[]): DeepPilotReport['local'] => ({\n ...localState,\n endpoints: localState.phase === 'online' ? localEndpointURLs(addresses, localState.port) : [],\n })\n const remoteStatus = (): RemoteStatus => remoteSupervisor?.status() ?? {\n provider: 'tailscale-funnel',\n phase: currentConfig().remote?.enabled === true ? 'stopped' : 'disabled',\n updatedAt: Date.now(),\n }\n\n // Self-update check: one process-wide instance. The initial schedule fires\n // a single background GitHub fetch shortly after boot. The result is\n // surfaced through the report snapshot; the UI shows nothing extra on\n // a quiet host, and one inline \"new version\" link when an update exists.\n const updateChecker = new UpdateChecker({ log, currentVersion: SERVER_VERSION })\n updateChecker.scheduleInitial()\n const updateInfo = (): UpdateInfo => updateChecker.get()\n\n // Typert Remote for the web settings page (deeppilot/report).\n applyReportRemote(ctx, async () => {\n let pairingReady = false\n let devices: Array<{\n deviceId: string; deviceName: string; appVersion: string; firstSeenTs: number; lastSeenTs: number\n fingerprint: string; scopes: ReturnType<typeof normalizeDeviceScopes>; revokedAt?: number\n apns?: { environment: 'development' | 'production'; updatedAt: number }\n }> = []\n try {\n await ready\n pairingReady = auth.audience !== null && auth.devices !== null\n // Strip the raw APNs token at the source; the report carries only the\n // registration fact (environment + freshness).\n devices = (auth.devices?.list() ?? [])\n .filter((device) => device.publicKey !== undefined && device.fingerprint !== undefined)\n .map(({ deviceId, deviceName, appVersion, firstSeenTs, lastSeenTs, fingerprint, scopes, revokedAt, apns }) => ({\n deviceId,\n deviceName,\n appVersion,\n firstSeenTs,\n lastSeenTs,\n fingerprint: fingerprint!,\n scopes: normalizeDeviceScopes(scopes),\n ...(revokedAt !== undefined ? { revokedAt } : {}),\n ...(apns ? { apns: { environment: apns.environment, updatedAt: apns.updatedAt } } : {}),\n }))\n } catch {\n // degraded: report the minimum without token facts\n }\n const update = updateInfo()\n const lanAddresses = localLANIPv4Addresses()\n return {\n protocolVersion: 2,\n serverVersion: SERVER_VERSION,\n pluginVersion: update.currentVersion,\n ...(update.available ? { updateAvailable: true } : {}),\n ...(update.releaseUrl !== null ? { releaseUrl: update.releaseUrl } : {}),\n enabled: currentConfig().enabled === true,\n identityPath: expandHome(currentConfig().devicesPath ?? join(bridgeDataDir(), 'devices-v2.json')),\n pairingReady,\n activeConnections: connections.size,\n historyBufferMax: currentConfig().historyBufferMax ?? 2000,\n debug: currentConfig().debug === true,\n lanAddresses,\n local: localStatus(lanAddresses),\n remote: remoteStatus(),\n devices,\n }\n }, beginPairing, async (deviceId) => {\n const { devices } = await ready\n if (!devices) throw new Error('device registry unavailable')\n const revoked = devices.revoke(deviceId, Date.now())\n if (revoked) {\n for (const connection of [...connections]) {\n if (connection.connectedDeviceId !== deviceId) continue\n connection.terminate()\n connections.delete(connection)\n }\n log(`device revoked id=${auditLabel(deviceId)}`)\n }\n return revoked\n }, async (deviceId, scopes) => {\n const { devices } = await ready\n if (!devices) throw new Error('device registry unavailable')\n const updated = devices.setScopes(deviceId, scopes)\n if (updated === null) throw new Error('active device not found')\n // Scope changes take effect on the next signed connection; disconnect the\n // current socket so stale in-memory authority cannot survive the update.\n for (const connection of [...connections]) {\n if (connection.connectedDeviceId !== deviceId) continue\n connection.terminate()\n connections.delete(connection)\n }\n log(`device scopes updated id=${auditLabel(deviceId)} scopes=${updated.join(',')}`)\n return updated\n }, async () => {\n const push = currentConfig().push ?? {}\n const configured = push.provider ?? 'none'\n const effective = configured === 'none' && enrollmentCell.autoRelay === true ? 'relay' : configured\n if (effective !== 'relay') {\n return {\n url: '',\n overall: 'failed' as const,\n tokenIssued: false,\n steps: [{ id: 'health' as const, ok: false, message: `当前推送模式不是中继(provider=${configured})。启用方式二选一:① 零配置——在 ios/project.yml 填写 DSPushEnrollKey(与服务器 RELAY_ENROLL_KEY 一致)并重新安装 App,打开 App 即自动启用;② 手动——将 push.provider 设为 relay 并填入 relayToken` }],\n }\n }\n const url = (push.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n if (!/^https:\\/\\//i.test(url)) {\n return {\n url,\n overall: 'failed' as const,\n tokenIssued: false,\n steps: [{ id: 'health' as const, ok: false, message: 'relayUrl 必须是 https 地址:注册请求携带共享密钥,明文 HTTP 会把它暴露给链路上的任何节点' }],\n }\n }\n // The enroll step needs an identity; mint one now so a successful test\n // doubles as a completed enrollment.\n if (!enrollmentCell.clientId && enrollmentCell.enrollKey) {\n enrollmentCell.clientId = 'u_' + randomBytes(16).toString('base64url')\n persistEnrollment()\n }\n return await runRelayProbe({\n url,\n clientId: enrollmentCell.clientId,\n enrollKey: enrollmentCell.enrollKey,\n manualToken: Boolean((push.relayToken ?? '').trim()),\n onEnrolled: (token) => {\n enrollmentCell.token = token\n persistEnrollment()\n log('push relay enrollment succeeded (via settings self-test)')\n },\n })\n }, async () => {\n return await runPushSelfTest()\n })\n const state: { bridge?: HostBridge } = {}\n let pendingUpgrades = 0\n const authRateLimiter = new AuthRateLimiter()\n\n const readJSONBody = async (req: IncomingMessage, maxBytes = 16 * 1024): Promise<unknown> => {\n const chunks: Buffer[] = []\n let size = 0\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n size += buffer.length\n if (size > maxBytes) throw new Error('request body too large')\n chunks.push(buffer)\n }\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as unknown\n }\n\n const handlePair = async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n res.setHeader('Content-Type', 'application/json')\n if (!enabledNow()) {\n res.statusCode = 503\n res.end(JSON.stringify({ ok: false, error: 'bridge disabled' }))\n return\n }\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.setHeader('Allow', 'POST')\n res.end(JSON.stringify({ ok: false, error: 'POST required' }))\n return\n }\n const source = requestClientIdentity(req)\n const admission = authRateLimiter.admit(source)\n if (!admission.ok) {\n res.statusCode = 429\n res.setHeader('Retry-After', String(Math.max(1, Math.ceil(admission.retryAfterMs / 1_000))))\n res.end(JSON.stringify({ ok: false, error: 'pairing rate limited' }))\n return\n }\n try {\n const { devices, audience } = await ready\n if (!devices || !audience) throw new Error('device authentication unavailable')\n const raw = await readJSONBody(req) as Record<string, unknown>\n if (raw === null || typeof raw !== 'object' || raw.v !== 2) throw new TypeError('protocol v2 required')\n const code = typeof raw.code === 'string' ? raw.code : ''\n const publicKey = typeof raw.publicKey === 'string' ? raw.publicKey : ''\n const deviceName = sanitizeDeviceField(raw.deviceName, MAX_DEVICE_NAME_CHARS) || 'unknown'\n const appVersion = sanitizeDeviceField(raw.appVersion, MAX_APP_VERSION_CHARS) || 'unknown'\n const deviceId = deviceIdForPublicKey(publicKey)\n if (devices.list().length >= MAX_DEVICES && devices.authorized(deviceId) === undefined) {\n res.statusCode = 409\n res.end(JSON.stringify({ ok: false, error: 'device registry is full' }))\n return\n }\n if (!pairingCodes.consume(code)) {\n const failure = authRateLimiter.recordFailure(source)\n res.statusCode = failure.blocked ? 429 : 401\n if (failure.retryAfterMs > 0) res.setHeader('Retry-After', String(Math.max(1, Math.ceil(failure.retryAfterMs / 1_000))))\n res.end(JSON.stringify({ ok: false, error: failure.blocked ? 'pairing rate limited' : 'pairing code invalid or expired' }))\n return\n }\n const record = devices.register({\n publicKey,\n deviceName,\n appVersion,\n scopes: normalizeDeviceScopes(raw.scopes),\n }, Date.now())\n authRateLimiter.recordSuccess(source)\n log(`device paired id=${auditLabel(record.deviceId)} source=${auditLabel(source)}`)\n res.statusCode = 201\n res.end(JSON.stringify({\n ok: true,\n v: 2,\n deviceId: record.deviceId,\n audience,\n scopes: record.scopes ?? [],\n }))\n } catch (error) {\n res.statusCode = error instanceof SyntaxError || error instanceof TypeError ? 400 : 503\n res.end(JSON.stringify({ ok: false, error: error instanceof Error ? error.message : 'pairing failed' }))\n } finally {\n admission.release()\n }\n }\n\n const handleUpgrade = (req: IncomingMessage, socket: Duplex, head: Buffer): void => {\n void (async () => {\n try {\n if (!enabledNow()) {\n rejectUpgrade(socket, 503, 'bridge disabled')\n return\n }\n if (connections.size + pendingUpgrades >= MAX_CLIENT_CONNECTIONS) {\n rejectUpgrade(socket, 429, 'too many connections')\n return\n }\n pendingUpgrades += 1\n try {\n const { devices, audience } = await ready\n if (!audience || !devices) {\n rejectUpgrade(socket, 503, 'bridge degraded')\n return\n }\n const source = requestClientIdentity(req)\n const admission = authRateLimiter.admit(source)\n if (!admission.ok) {\n rejectUpgrade(socket, 429, 'authentication rate limited', admission.retryAfterMs / 1_000)\n return\n }\n const bridge = state.bridge\n if (!bridge) {\n admission.release()\n rejectUpgrade(socket, 503, 'bridge not ready')\n return\n }\n try {\n wss.handleUpgrade(req, socket, head, (ws) => {\n if (auth.audience !== audience || state.bridge !== bridge) {\n admission.release()\n ws.close(1012, 'bridge changed')\n return\n }\n try {\n const connection = new BridgeConnection(ws, {\n bridge,\n devices,\n serverVersion: SERVER_VERSION,\n audience,\n log,\n debug: currentConfig().debug === true,\n onClosed: (closed) => connections.delete(closed),\n onAuthenticationSettled: (ok) => {\n admission.release()\n if (ok) {\n authRateLimiter.recordSuccess(source)\n } else {\n const failure = authRateLimiter.recordFailure(source)\n if (failure.newlyBlocked) log(`authentication source blocked source=${auditLabel(source)}`)\n }\n },\n onDeviceAuthenticated: (deviceId) => {\n log(`device authenticated id=${auditLabel(deviceId)} source=${auditLabel(source)}`)\n },\n onPushEnrollKey: handlePushEnrollKey,\n })\n connections.add(connection)\n } catch (error) {\n admission.release()\n ws.close(1011, 'connection setup failed')\n throw error\n }\n })\n } catch (error) {\n admission.release()\n throw error\n }\n } finally {\n pendingUpgrades -= 1\n }\n } catch (error) {\n log('upgrade failed: ' + String(error))\n rejectUpgrade(socket, 500, 'internal error')\n }\n })()\n }\n\n const handleHealth = async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n await ready\n res.setHeader('Content-Type', 'application/json')\n if (!auth.audience || !auth.devices) {\n res.statusCode = 503\n res.end(JSON.stringify({ ok: false, degraded: true }))\n return\n }\n res.statusCode = 200\n res.end(JSON.stringify({\n ok: true,\n enabled: enabledNow(),\n protocolVersion: 2,\n serverVersion: SERVER_VERSION,\n dataPlane: Boolean(state.bridge),\n }))\n } catch {\n res.statusCode = 500\n res.end(JSON.stringify({ ok: false }))\n }\n }\n\n const phoneHandlers = {\n health: handleHealth,\n pair: handlePair,\n upgrade: handleUpgrade,\n }\n\n // Independent transport listeners. LAN owns a stable configurable port;\n // Funnel keeps its loopback-only ephemeral origin. They share only the\n // narrow handlers above, so a LAN bind failure cannot take remote access\n // down and neither listener exposes DSH's wider web/API surface.\n let localServer: ReturnType<typeof createPhoneServer> | undefined\n let appliedLocalKey: string | undefined\n let localDisposed = false\n let localTail = Promise.resolve()\n const reconcileLocal = async (): Promise<void> => {\n if (localDisposed) return\n const config = currentConfig()\n const localConfig = config.local ?? {}\n const next = {\n enabled: config.enabled === true && localConfig.enabled !== false,\n port: normalizeLocalPort(localConfig.port),\n }\n const nextKey = JSON.stringify(next)\n if (nextKey === appliedLocalKey) return\n appliedLocalKey = nextKey\n\n const previous = localServer\n localServer = undefined\n await closeServer(previous)\n if (localDisposed) return\n if (!next.enabled) {\n localState = { phase: 'disabled', port: next.port, endpoints: [], updatedAt: Date.now() }\n log('local transport disabled')\n return\n }\n\n localState = { phase: 'starting', port: next.port, endpoints: [], updatedAt: Date.now() }\n const server = createPhoneServer(phoneHandlers)\n localServer = server\n try {\n await listen(server, next.port, '0.0.0.0')\n if (localDisposed || localServer !== server) {\n await closeServer(server)\n return\n }\n localState = { phase: 'online', port: next.port, endpoints: [], updatedAt: Date.now() }\n log(`local transport listening on 0.0.0.0:${next.port}`)\n } catch (error) {\n if (localServer === server) localServer = undefined\n await closeServer(server)\n const message = localListenError(error, next.port)\n localState = { phase: 'error', port: next.port, endpoints: [], message, updatedAt: Date.now() }\n log('local transport failed: ' + message)\n }\n }\n scheduleLocalReconcile = () => {\n localTail = localTail\n .then(reconcileLocal)\n .catch((error) => log('local reconcile failed: ' + String(error)))\n }\n\n const originServer = createPhoneServer(phoneHandlers)\n let originURL: string | undefined\n let appliedRemoteKey: string | undefined\n let remoteDisposed = false\n let remoteTail = Promise.resolve()\n const reconcileRemote = async (): Promise<void> => {\n if (remoteDisposed || originURL === undefined) return\n const config = currentConfig()\n const remoteConfig = config.remote ?? {}\n const remotePort: 443 | 8443 | 10000 = remoteConfig.funnelPort === 8443 || remoteConfig.funnelPort === 10000\n ? remoteConfig.funnelPort\n : 443\n const helperPath = remoteConfig.helperPath?.trim() || undefined\n const next = {\n enabled: config.enabled === true && remoteConfig.enabled === true && remoteConfig.provider === 'tailscale-funnel',\n hostname: normalizeRemoteHostname(remoteConfig.hostname),\n statePath: remoteConfig.statePath?.trim() || join(dataDir, 'tailscale'),\n helperPath,\n funnelPort: remotePort,\n maxConnectionsPerSource: normalizeFunnelConnectionLimit(remoteConfig.maxConnectionsPerSource),\n }\n const nextKey = JSON.stringify(next)\n if (nextKey === appliedRemoteKey) return\n\n const previous = remoteSupervisor\n remoteSupervisor = undefined\n if (previous !== undefined) await previous.dispose()\n if (remoteDisposed) return\n\n const supervisor = new RemoteSupervisor({\n enabled: next.enabled,\n hostname: next.hostname,\n statePath: next.statePath,\n ...(next.helperPath ? { helperPath: next.helperPath } : {}),\n funnelPort: next.funnelPort,\n maxConnectionsPerSource: next.maxConnectionsPerSource,\n log,\n })\n remoteSupervisor = supervisor\n appliedRemoteKey = nextKey\n await supervisor.start(originURL)\n }\n scheduleRemoteReconcile = () => {\n remoteTail = remoteTail\n .then(reconcileRemote)\n .catch((error) => log('remote reconcile failed: ' + String(error)))\n }\n\n ;(ctx as unknown as SubContext).effect(() => {\n scheduleLocalReconcile?.()\n void listen(originServer, 0, '127.0.0.1').then(() => {\n const address = originServer.address()\n if (address && typeof address === 'object') {\n originURL = `http://127.0.0.1:${address.port}`\n scheduleRemoteReconcile?.()\n }\n }, (error: unknown) => log('remote origin failed: ' + String(error)))\n return async () => {\n localDisposed = true\n remoteDisposed = true\n scheduleLocalReconcile = undefined\n scheduleRemoteReconcile = undefined\n const activeLocal = localServer\n localServer = undefined\n await Promise.allSettled([closeServer(activeLocal), closeServer(originServer)])\n localState = { phase: 'stopped', port: localState.port, endpoints: [], updatedAt: Date.now() }\n await Promise.allSettled([\n localTail,\n remoteTail.then(async () => {\n const supervisor = remoteSupervisor\n remoteSupervisor = undefined\n if (supervisor !== undefined) await supervisor.dispose()\n }),\n ])\n }\n }, 'deeppilot: independent transports')\n\n const sweep = setInterval(() => {\n const now = Date.now()\n for (const connection of connections) {\n if (connection.isStale(now, 60_000)) {\n log('dropping stale connection')\n connection.closeIdle()\n connections.delete(connection)\n }\n }\n }, 30_000)\n ;(ctx as unknown as SubContext).effect(() => () => clearInterval(sweep), 'deeppilot: stale sweep')\n\n // Data plane: dsh 0.1.2 removed apiProxy. Build the bridge's stable\n // protocol-facing façade from the public Session/Workspace controllers.\n\n /**\n * Whether the resident Gateway Client represents a real phone surface. A\n * paired device remains answerable even while offline: HostBridge retains an\n * authoritative pending snapshot that the app pulls on reconnect, while\n * APNs is only a best-effort wakeup. With no paired device this Client calls\n * `next()`; Gateway's independent official Web delivery is unaffected.\n */\n const hasPairedPhoneSurface = (_kind: DshInteractionKind): boolean => {\n const devices = auth.devices?.list() ?? []\n return devices.some((device) => device.revokedAt === undefined)\n }\n\n ;(ctx as unknown as { inject: (deps: string[], fn: (sub: unknown) => void) => void }).inject(\n ['sessionController', 'connection', 'typertGateway'],\n (sub) => {\n if (currentConfig().enabled !== true) {\n log('bridge disabled; data plane stays inactive')\n return\n }\n const apiCtx = sub as unknown as Context & SubContext\n let proxy: Dsh012ApiProxy\n try {\n proxy = new Dsh012ApiProxy(apiCtx, { shouldSurfaceInteraction: hasPairedPhoneSurface })\n } catch (error) {\n log('dsh 0.1.2 session bridge unavailable: ' + String(error))\n return\n }\n const bridge = new HostBridge(proxy, cfg.historyBufferMax, join(dataDir, 'prompt-deliveries-v1.json'))\n bridge.setPushOutlet(makePushOutlet())\n state.bridge = bridge\n bridge.start()\n log('data plane active (mux + host streams)')\n apiCtx.effect(() => () => {\n closeConnectionsForBridge(bridge)\n if (state.bridge === bridge) state.bridge = undefined\n bridge.dispose()\n }, 'deeppilot: host streams')\n },\n )\n\n // Temporary 3080 compatibility plane. New clients use the independent LAN\n // listener above; these DSH routes remain for one migration cycle.\n ;(ctx as unknown as { inject: (deps: string[], fn: (sub: unknown) => void) => void }).inject(\n ['webServer'],\n (sub) => {\n const webCtx = sub as unknown as { webServer?: WebServerLike } & SubContext\n const web = webCtx.webServer\n if (!web) {\n log('webServer service absent; 3080 compatibility routes unavailable (independent transports remain active)')\n return\n }\n // Routes are registered regardless of the master switch so a mid-session\n // toggle always stays serviceable; every handler refuses work when the\n // bridge is currently disabled (evaluated per request so it is robust to\n // the settings scope attaching before or after webServer).\n webCtx.effect(\n () =>\n web.registerUpgrade({\n path: '/phone',\n handler: handleUpgrade,\n }),\n 'deeppilot: /phone WebSocket',\n )\n\n webCtx.effect(\n () =>\n web.register({\n kind: 'exact',\n path: '/phone/health',\n handler: handleHealth,\n }),\n 'deeppilot: /phone/health',\n )\n\n webCtx.effect(\n () =>\n web.register({\n kind: 'exact',\n path: '/phone/pair',\n handler: handlePair,\n }),\n 'deeppilot: /phone/pair',\n )\n\n if (enabledNow()) {\n log('/phone compatibility routes registered on DSH web server')\n } else {\n log('bridge disabled; /phone refuses connections until re-enabled')\n }\n },\n )\n\n ;(ctx as unknown as SubContext).effect(() => async () => {\n closeAllConnections()\n const bridge = state.bridge\n state.bridge = undefined\n bridge?.dispose()\n const sender = cachedSender\n cachedSender = undefined\n updateChecker.dispose()\n widgetPush.dispose()\n liveActivityPush.dispose()\n const wssClosed = new Promise<void>((resolve) => wss.close(() => resolve()))\n await Promise.allSettled([\n enrollmentWriteTail,\n sender?.dispose?.() ?? Promise.resolve(),\n wssClosed,\n ])\n }, 'deeppilot: process resources')\n}\n"],"mappings":"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"}
|