dsh-deeppilot 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["journals","record","cryptoSign","alert","http2Connect","fsConstants","httpsRequest","createHttpServer","createHttpsServer"],"sources":["../src/prompt-delivery.ts","../src/request-validation.ts","../src/connection-policy.ts","../src/device-auth.ts","../src/token.ts","../src/connection.ts","../src/host-api.ts","../src/document-payload.ts","../src/host-event-projection.ts","../src/mutation-journal.ts","../src/host-bridge.ts","../src/dsh-remote-interactions.ts","../src/dsh-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/lan-tls.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 // Device self-revocation takes no required fields: both an omitted payload\n // and `{}` are valid, and `deviceId` is optional (it must equal the\n // authenticated device when present).\n if (value === undefined && (type === 'c2s.session.create' || type === 'c2s.directory.list' || type === 'c2s.device.revoke')) 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.schedule.list' && !text(p.sessionId)) return 'invalid sessionId'\n if (type === 'c2s.schedule.history' && (!text(p.sessionId) || !text(p.id) || !integer(p.limit, 1, 100) || !optional('before', v => text(v)))) return 'invalid schedule history'\n if (type === 'c2s.schedule.create') {\n if (!validSendId(p.clientRequestId) || !text(p.sessionId) || !text(p.title, 120) || !text(p.prompt, 256 * 1024)) return 'invalid schedule create fields'\n const selectors = ['after_seconds', 'at', 'every_seconds', 'daily', 'weekly', 'cron'].filter(key => p[key] !== undefined)\n if (selectors.length !== 1) return 'schedule requires exactly one selector'\n if (p.after_seconds !== undefined && !integer(p.after_seconds, 1, Number.MAX_SAFE_INTEGER)) return 'invalid after_seconds'\n if (p.every_seconds !== undefined && !integer(p.every_seconds, 60, Number.MAX_SAFE_INTEGER)) return 'invalid every_seconds'\n if (p.at !== undefined && typeof p.at !== 'string' && (typeof p.at !== 'object' || p.at === null || Array.isArray(p.at))) return 'invalid at selector'\n }\n if (type === 'c2s.schedule.update') {\n if (!validSendId(p.clientRequestId) || !text(p.sessionId) || !text(p.id) || !p.expected || typeof p.expected !== 'object' || Array.isArray(p.expected)) return 'invalid schedule update fields'\n if (!optional('title', v => text(v, 120)) || !optional('prompt', v => text(v, 256 * 1024))) return 'invalid schedule update content'\n if (p.change !== undefined && (!p.change || typeof p.change !== 'object' || Array.isArray(p.change))) return 'invalid schedule timing change'\n }\n if (type === 'c2s.schedule.delete' && (!validSendId(p.clientRequestId) || !text(p.sessionId) || !text(p.id))) return 'invalid schedule delete fields'\n if (type === 'c2s.session.fork' && (!validSendId(p.clientRequestId) || !optional('atSeq', v => integer(v, 0, Number.MAX_SAFE_INTEGER)))) return 'invalid session fork fields'\n if (type === 'c2s.device.revoke' && !optional('deviceId', v => text(v))) return 'invalid deviceId'\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 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 // Self-revocation is a device-lifecycle operation, not a business read: a\n // device whose scopes were narrowed must still be able to unbind itself,\n // otherwise it is stuck as a permanent offline-push target.\n if (type === 'c2s.device.revoke') 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 (type.startsWith('c2s.schedule.')) return 'schedule.manage'\n if (\n type === 'c2s.workspace.create' ||\n type === 'c2s.session.create' ||\n type === 'c2s.session.fork' ||\n type === 'c2s.session.rename' ||\n type === 'c2s.session.archive' ||\n type === 'c2s.session.unarchive' ||\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 's2c.schedule.changed': 'schedule.manage',\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 scheduleManagementErrorCode(\n kind: 'unsupported' | 'not-found' | 'invalid' | 'conflict' | 'busy' | '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 'invalid': return 'E_PROTOCOL'\n case 'conflict':\n case 'busy': return 'E_BUSY'\n default: return 'E_INTERNAL'\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 {\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 'schedule.manage',\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 { MAX_DEVICE_NAME_CHARS, sanitizeDeviceField } from './connection-policy.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 /** Name reported by the phone. Refreshed on every authenticated hello. */\n deviceName: string\n /** User-assigned name from the DSH settings page; survives app reconnects. */\n customName?: 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/** Name shown to the operator: a user label when present, otherwise the app-reported model name. */\nexport function deviceDisplayName(record: Pick<DeviceRecord, 'deviceName' | 'customName'>): string {\n return record.customName?.trim() ? record.customName : record.deviceName\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 ...(existing?.customName ? { customName: existing.customName } : {}),\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 /**\n * Set or clear the operator-facing device label. The phone-reported name is\n * intentionally left untouched so a reconnect cannot erase this value.\n * Returns the effective display name, or null when the device is not active.\n */\n async setCustomName(deviceId: string, customName: string | null): Promise<string | null> {\n const record = this.authorized(deviceId)\n if (!record) return null\n const normalized = customName === null ? '' : sanitizeDeviceField(customName, MAX_DEVICE_NAME_CHARS)\n if (normalized === (record.customName ?? '')) return deviceDisplayName(record)\n const previous = record.customName\n if (normalized === '') delete record.customName\n else record.customName = normalized\n try {\n await this.flush()\n } catch (error) {\n if (previous === undefined) delete record.customName\n else record.customName = previous\n throw error\n }\n return deviceDisplayName(record)\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 this.detachDuplicateToken('apns', normalized, deviceId)\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 // Match c2s.push.register: hex tokens are stored lowercased, so an\n // uppercase re-send is the same registration, not a rotation.\n const normalized = token.toLowerCase()\n const previous = record.widgetApns\n if (previous?.token === normalized && previous.environment === environment &&\n now - previous.updatedAt < 60 * 60 * 1000) return\n this.detachDuplicateToken('widgetApns', normalized, deviceId)\n record.widgetApns = { token: normalized, 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 /**\n * One physical device owns one APNs token, but a re-pair or a botched unbind\n * can leave the same token attached to a second deviceId. Registering it\n * under `keepDeviceId` detaches it from every other record — only that one\n * token field, never the other record's pairing key or scopes. No flush of\n * its own: the caller batches it with the write that follows, so a single\n * registry write covers both changes.\n */\n private detachDuplicateToken(\n field: 'apns' | 'widgetApns',\n token: string,\n keepDeviceId: string,\n ): void {\n for (const record of this.devices.values()) {\n if (record.deviceId === keepDeviceId) continue\n if (field === 'apns') {\n if (record.apns?.token === token) delete record.apns\n } else if (record.widgetApns?.token === token) {\n delete record.widgetApns\n }\n }\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 { 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 scheduleManagementErrorCode,\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 * c2s.device.revoke (device unbind): the registered device revoked itself\n * and every OTHER active connection of that device must be dropped.\n * `except` is the connection that sent the frame — its close is already\n * owned by the handler (ack first, then 4401). The hook must not flip the\n * registry itself; the handler calls DeviceStore.revoke before this.\n */\n onDeviceRevoke?: (deviceId: string, except: BridgeConnection) => Promise<unknown> | unknown\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 /**\n * Set the moment c2s.device.revoke tears this device down. `ws.close()` is\n * asynchronous, so frames that arrive while the 4401 close is in flight must\n * already be refused — a revoked device may not keep driving the bridge.\n */\n private revoked = 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 // A revoked device is mid-close: swallow everything until the socket\n // goes away instead of answering a device that no longer exists.\n if (this.revoked) return\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 // Device self-revocation is refused by its own handler with a specific\n // reason; the generic widget gate would only say \"read-only\".\n if (env.type !== 'c2s.device.revoke') {\n return this.fail(env.id, 'E_FORBIDDEN', 'widget connection is read-only')\n }\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 if (env.type.startsWith('c2s.schedule.') && !this.scopes.has('sessions.read')) {\n return this.fail(env.id, 'E_FORBIDDEN', 'scope sessions.read required')\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.fork': {\n const p = env.payload as { sessionId?: string; atSeq?: number; clientRequestId?: string }\n if (!this.deps.bridge.capabilities.sessionFork) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'session fork unavailable on this host version')\n }\n const result = await this.deps.bridge.forkSession(this.deviceId!, {\n sessionId: p.sessionId!,\n clientRequestId: p.clientRequestId!,\n ...(p.atSeq !== undefined ? { atSeq: p.atSeq } : {}),\n })\n if (!result.ok) return this.fail(env.id, scheduleManagementErrorCode(result.kind), result.message)\n this.send('s2c.session.forked', {\n clientRequestId: p.clientRequestId!,\n sourceSessionId: p.sessionId!,\n sessionId: result.value.sessionId,\n ...(p.atSeq !== undefined ? { atSeq: p.atSeq } : {}),\n ...(result.replayed ? { replayed: true } : {}),\n }, 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.sessions.archived': {\n // Separate from c2s.sessions.list so the live list keeps its shape for\n // clients that do not know about archived rows.\n this.send('s2c.sessions.archived.snapshot', {\n sessions: this.deps.bridge.listArchivedSessions(),\n }, env.id)\n return\n }\n case 'c2s.session.unarchive': {\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.sessionRestore) {\n return this.fail(env.id, 'E_UNSUPPORTED', 'session restore unavailable on this host version')\n }\n const result = await this.deps.bridge.unarchiveSession(p.sessionId)\n if (!result.ok) {\n return this.fail(env.id, managementErrorCode(result.kind), result.message)\n }\n this.send('s2c.session.unarchived', { 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.schedule.list': {\n const p = env.payload as { sessionId: string }\n if (!this.deps.bridge.capabilities.schedules) return this.fail(env.id, 'E_UNSUPPORTED', 'schedules unavailable on this host version')\n const result = await this.deps.bridge.listSchedules(p.sessionId)\n if (!result.ok) return this.fail(env.id, scheduleManagementErrorCode(result.kind), result.message)\n this.send('s2c.schedule.snapshot', { sessionId: p.sessionId, tasks: result.value }, env.id)\n return\n }\n case 'c2s.schedule.history': {\n const p = env.payload as { sessionId: string; id: string; limit: number; before?: string }\n if (!this.deps.bridge.capabilities.schedules) return this.fail(env.id, 'E_UNSUPPORTED', 'schedules unavailable on this host version')\n const result = await this.deps.bridge.scheduleHistory(p.sessionId, p.id, p.limit, p.before)\n if (!result.ok) return this.fail(env.id, scheduleManagementErrorCode(result.kind), result.message)\n this.send('s2c.schedule.history', { sessionId: p.sessionId, history: result.value }, env.id)\n return\n }\n case 'c2s.schedule.create': {\n if (!this.deps.bridge.capabilities.schedules) return this.fail(env.id, 'E_UNSUPPORTED', 'schedules unavailable on this host version')\n const p = env.payload as Record<string, unknown> & { sessionId: string; clientRequestId: string; title: string; prompt: string }\n const result = await this.deps.bridge.createSchedule(this.deviceId!, p)\n if (!result.ok) return this.fail(env.id, scheduleManagementErrorCode(result.kind), result.message)\n this.send('s2c.schedule.updated', {\n clientRequestId: p.clientRequestId,\n sessionId: p.sessionId,\n task: result.value,\n ...(result.replayed ? { replayed: true } : {}),\n }, env.id)\n return\n }\n case 'c2s.schedule.update': {\n if (!this.deps.bridge.capabilities.schedules) return this.fail(env.id, 'E_UNSUPPORTED', 'schedules unavailable on this host version')\n const p = env.payload as Record<string, unknown> & { sessionId: string; id: string; clientRequestId: string; expected: unknown }\n const result = await this.deps.bridge.updateSchedule(this.deviceId!, p)\n if (!result.ok) return this.fail(env.id, scheduleManagementErrorCode(result.kind), result.message)\n this.send('s2c.schedule.updated', {\n clientRequestId: p.clientRequestId,\n sessionId: p.sessionId,\n task: result.value,\n ...(result.replayed ? { replayed: true } : {}),\n }, env.id)\n return\n }\n case 'c2s.schedule.delete': {\n if (!this.deps.bridge.capabilities.schedules) return this.fail(env.id, 'E_UNSUPPORTED', 'schedules unavailable on this host version')\n const p = env.payload as { sessionId: string; id: string; clientRequestId: string }\n const result = await this.deps.bridge.deleteSchedule(this.deviceId!, p)\n if (!result.ok) return this.fail(env.id, scheduleManagementErrorCode(result.kind), result.message)\n this.send('s2c.schedule.updated', {\n clientRequestId: p.clientRequestId,\n sessionId: p.sessionId,\n deleted: true,\n ...(result.replayed ? { replayed: true } : {}),\n }, 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.device.revoke': {\n // Device unbind: the app is deleting its local instance and asks the\n // host to drop the pairing (APNs/WidgetKit/LiveActivity tokens plus a\n // revokedAt tombstone) so it can never be an offline push target\n // again. Unauthenticated frames never reach here; a widget socket is\n // refused because a short-lived read-only connection must not unbind\n // its device.\n const p = env.payload as { deviceId?: unknown } | undefined\n if (p?.deviceId !== undefined && typeof p.deviceId !== 'string') {\n return this.fail(env.id, 'E_PROTOCOL', 'deviceId must be a string')\n }\n if (typeof p?.deviceId === 'string' && p.deviceId !== this.deviceId) {\n return this.fail(env.id, 'E_FORBIDDEN', 'deviceId does not match the authenticated device')\n }\n if (this.widgetClient) {\n return this.fail(env.id, 'E_FORBIDDEN', 'widget connection cannot revoke its device')\n }\n const deviceId = this.deviceId!\n // Idempotent: an already-revoked record still acks {revoked:true} —\n // the device cannot tell a fresh revocation from a repeated one, and\n // neither case may surface as an error.\n this.deps.devices.revoke(deviceId, Date.now())\n this.revoked = true\n // Dropping sibling sockets is best effort: the registry tombstone is\n // already written, so a failing hook must not swallow the ack.\n try {\n await this.deps.onDeviceRevoke?.(deviceId, this)\n } catch (error) {\n if (this.deps.debug === true) this.deps.log('device revoke hook failed: ' + String(error))\n }\n // Ack strictly precedes the close so a slow client observes the\n // successful unbind before the 4401.\n this.send('s2c.ack', { revoked: true }, env.id)\n this.close(4401, 'device revoked')\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 // A socket that just self-revoked is closing; it may not authenticate\n // again (the registry tombstone would refuse it anyway).\n if (this.revoked) return\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/* Stable bridge-facing structural types mapped to rc.2 controllers by\n * DshApiProxy. */\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 fork?(req: RpcRequestLike<{ sessionId: string; atSeq?: number }>): Promise<RpcResponseLike<{ sessionId: 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 /** Complete projection baseline for one session; null when it is gone. */\n projections(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ asOfSeq: number; values: Record<string, unknown> } | null>>\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 unarchiveSession?(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ archivedSessionIds: string[] }>>\n}\n\nexport type ScheduleKind = 'after' | 'at' | 'every' | 'daily' | 'weekly' | 'cron'\n\nexport interface ScheduleTaskViewLike {\n id: string\n kind: ScheduleKind\n title: string\n prompt: string\n scheduledAt: string\n state: 'scheduled' | 'overdue'\n deliveryMode: 'host'\n afterSeconds?: number\n everySeconds?: number\n time?: string\n timeZone?: string\n weekdays?: number[]\n expression?: string\n}\n\nexport interface ScheduleHistoryViewLike {\n id: string\n records: Array<{\n scheduledAt: string\n deliveredAt: string\n messageId: string\n prompt?: string\n }>\n earlierRecordsUnavailable: boolean\n earlierRecordsPruned?: boolean\n retention: { days: number; records: number }\n nextBefore?: string\n}\n\nexport interface ScheduleApiLike {\n list(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ sessionId: string; tasks: ScheduleTaskViewLike[] }>>\n history(req: RpcRequestLike<{ sessionId: string; id: string; limit: number; before?: string }>):\n Promise<RpcResponseLike<{ sessionId: string; history: ScheduleHistoryViewLike }>>\n create(req: RpcRequestLike<{ sessionId: string; title: string; prompt: string; [key: string]: unknown }>):\n Promise<RpcResponseLike<ScheduleTaskViewLike>>\n update(req: RpcRequestLike<{ sessionId: string; id: string; expected: unknown; title?: string; prompt?: string; change?: unknown }>):\n Promise<RpcResponseLike<{ id: string; updated: boolean; record?: ScheduleTaskViewLike; code?: string }>>\n delete(req: RpcRequestLike<{ sessionId: string; id: string }>):\n Promise<RpcResponseLike<{ id: string; deleted: boolean; code?: 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 *\n * `parentSessionId` alone is NOT a subagent signal: a session forked from\n * another one (c2s.session.fork) also carries it, as fork lineage, while\n * being an ordinary top-level session the phone must show. Only the host's\n * explicit `origin` marks a worker — mirror the same rule already used for\n * the live mux stream (see dsh-api-proxy.ts's `isSubagent` derivation).\n */\nexport function isSubagentRow(row: PhoneSessionRow): boolean {\n return row.origin === 'subagent';\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 /** Internal Host identity hint; never serialized into the phone protocol. */\n isSubagent?: boolean\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 callId?: 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 schedule?: ScheduleApiLike\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; message?: { content?: unknown } } | undefined;\n const ok = data?.error === undefined;\n const result = limitMessageProjection({\n seq: event.seq, role: 'tool', ts: tsOf(event),\n tool: { name: 'result', state: ok ? 'ok' : 'error', summary: ok ? summarizeResult(data?.message?.content) : '失败' },\n ...(ok ? attachmentProjection(data?.message) : {}),\n });\n return {\n kind: 'tool.end',\n data: {\n seq: result.seq, role: result.role, ts: result.ts, ok,\n summary: result.tool?.summary,\n ...(result.attachments ? { attachments: result.attachments } : {}),\n ...(data?.callId ? { callId: String(data.callId) } : {}),\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 // A tool result may carry images as well as text — browser and\n // computer-use backends return screenshots this way. `summarizeResult`\n // covers only the textual part, so project the binary blocks as\n // attachments too; otherwise the phone renders a text-only summary and\n // the image is silently dropped. The durable attachmentId is what lets\n // the client read the bytes back through c2s.session.attachment.\n const attachments = failed ? {} : attachmentProjection(data?.message);\n if (target?.tool) {\n target.tool = { ...target.tool, state: failed ? 'error' : 'ok', summary };\n if (attachments.attachments) Object.assign(target, attachments);\n } else {\n messages.push({\n ...base,\n role: 'tool',\n tool: { name: 'result', state: failed ? 'error' : 'ok', summary },\n ...attachments,\n });\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 { createHash, randomUUID } from 'node:crypto'\nimport { existsSync, readFileSync, mkdirSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, statSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { validSendId } from './prompt-delivery.ts'\n\nexport type MutationErrorCode =\n | 'E_PROTOCOL'\n | 'E_NOT_FOUND'\n | 'E_BUSY'\n | 'E_UNSUPPORTED'\n | 'E_INTERNAL'\n\nexport type MutationOperationResult<T> =\n | { ok: true; value: T }\n | { ok: false; code: MutationErrorCode; message?: string }\n\nexport type MutationDispatchResult<T> =\n | { ok: true; value?: T; replayed?: boolean }\n | { ok: false; code: MutationErrorCode; message?: string; replayed?: boolean }\n\ninterface PersistedReceipt {\n fingerprint: string\n createdAt: number\n status: 'accepted' | 'rejected' | 'unknown'\n code?: MutationErrorCode\n}\n\ninterface Entry extends PersistedReceipt {\n /** Only non-sensitive replay values, enabled for fork session ids. */\n value?: unknown\n}\n\nconst RETENTION_MS = 7 * 24 * 3600 * 1000\nconst CAPACITY = 10_000\n\n/**\n * Small durable at-most-once journal for non-prompt mutations.\n *\n * Only a hash of the request content is persisted. The successful value is\n * kept in memory for the current process so a concurrent retry can receive the\n * same response; after a restart a replay is acknowledged and the client\n * refetches the authoritative resource. This avoids duplicating reminder\n * prompts or conversation data in a second journal.\n */\nexport class MutationJournal {\n private readonly entries: Record<string, Entry> = Object.create(null)\n private readonly inFlight = new Map<string, Promise<MutationDispatchResult<unknown>>>()\n private healthy = true\n\n constructor(private readonly path?: string, private readonly persistValues = false) {\n if (!path || !existsSync(path)) return\n try {\n if (statSync(path).size > 4 * 1024 * 1024) throw new Error('oversized mutation journal')\n const parsed = JSON.parse(readFileSync(path, 'utf8')) as { version?: unknown; entries?: unknown }\n if (parsed.version !== 1 || !Array.isArray(parsed.entries) || parsed.entries.length > CAPACITY) {\n throw new Error('invalid mutation journal')\n }\n for (const value of parsed.entries) {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('invalid mutation entry')\n const entry = value as Record<string, unknown>\n if (typeof entry.fingerprint !== 'string' || !/^[a-f0-9]{64}$/.test(entry.fingerprint) ||\n typeof entry.createdAt !== 'number' || !Number.isFinite(entry.createdAt) ||\n !['accepted', 'rejected', 'unknown'].includes(String(entry.status))) throw new Error('invalid mutation entry')\n if (entry.status === 'rejected' && !isMutationErrorCode(entry.code)) throw new Error('invalid mutation code')\n const key = String((value as { key?: unknown }).key)\n if (!/^[a-f0-9]{64}$/.test(key)) throw new Error('invalid mutation key')\n this.entries[key] = {\n fingerprint: entry.fingerprint,\n createdAt: entry.createdAt,\n status: entry.status as PersistedReceipt['status'],\n ...(isMutationErrorCode(entry.code) ? { code: entry.code } : {}),\n ...(this.persistValues && entry.value !== undefined ? { value: entry.value } : {}),\n }\n }\n } catch {\n this.healthy = false\n }\n }\n\n private key(deviceId: string, id: string): string {\n return createHash('sha256').update(JSON.stringify([deviceId, id])).digest('hex')\n }\n\n private expired(id: string, now = Date.now()): boolean {\n const age = now - Number(id.slice(0, 13))\n return age > RETENTION_MS || age < -5 * 60 * 1000\n }\n\n private save(): void {\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 {\n writeFileSync(fd, JSON.stringify({\n version: 1,\n entries: Object.entries(this.entries).map(([key, entry]) => ({ key, ...entry })),\n }))\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n renameSync(temp, this.path)\n const dir = openSync(dirname(this.path), 'r')\n try { fsyncSync(dir) } finally { closeSync(dir) }\n }\n\n async dispatch<T>(\n deviceId: string,\n id: string,\n content: unknown,\n operation: () => Promise<MutationOperationResult<T>>,\n ): Promise<MutationDispatchResult<T>> {\n if (!validSendId(id)) return { ok: false, code: 'E_PROTOCOL', message: 'invalid clientRequestId' }\n const key = this.key(deviceId, id)\n const fingerprint = createHash('sha256').update(JSON.stringify(content)).digest('hex')\n const existing = this.entries[key]\n if (existing !== undefined) {\n if (existing.fingerprint !== fingerprint) {\n return { ok: false, code: 'E_PROTOCOL', message: 'clientRequestId was reused with different content', replayed: true }\n }\n if (existing.status === 'accepted') return { ok: true, value: existing.value as T | undefined, replayed: true }\n if (existing.status === 'rejected' && existing.code !== undefined) {\n return { ok: false, code: existing.code, replayed: true }\n }\n return { ok: false, code: 'E_INTERNAL', message: 'mutation outcome is unknown; do not retry automatically', replayed: true }\n }\n if (!this.healthy) return { ok: false, code: 'E_INTERNAL', message: 'mutation journal unavailable' }\n if (this.expired(id)) return { ok: false, code: 'E_PROTOCOL', message: 'clientRequestId is outside the retry window' }\n\n const now = Date.now()\n for (const [entryKey, entry] of Object.entries(this.entries)) {\n if (now - entry.createdAt > RETENTION_MS + 5 * 60 * 1000 && !this.inFlight.has(entryKey)) {\n delete this.entries[entryKey]\n }\n }\n if (Object.keys(this.entries).length >= CAPACITY) {\n return { ok: false, code: 'E_BUSY', message: 'mutation journal is full' }\n }\n\n const entry: Entry = { fingerprint, createdAt: Number(id.slice(0, 13)), status: 'unknown' }\n this.entries[key] = entry\n try { this.save() } catch {\n this.healthy = false\n return { ok: false, code: 'E_INTERNAL', message: 'mutation journal could not persist the request' }\n }\n\n const run = (async (): Promise<MutationDispatchResult<unknown>> => {\n try {\n const result = await operation()\n if (result.ok) {\n entry.status = 'accepted'\n if (this.persistValues) entry.value = result.value\n return result\n }\n entry.status = 'rejected'\n entry.code = result.code\n return { ok: false, code: result.code, message: result.message }\n } catch {\n return { ok: false, code: 'E_INTERNAL', message: 'mutation outcome is unknown; do not retry automatically' }\n } finally {\n try { this.save() } catch { this.healthy = false }\n }\n })()\n this.inFlight.set(key, run)\n try {\n return await run as MutationDispatchResult<T>\n } finally {\n this.inFlight.delete(key)\n }\n }\n}\n\nfunction isMutationErrorCode(value: unknown): value is MutationErrorCode {\n return typeof value === 'string' && ['E_PROTOCOL', 'E_NOT_FOUND', 'E_BUSY', 'E_UNSUPPORTED', 'E_INTERNAL'].includes(value)\n}\n\nconst journals = new Map<string, MutationJournal>()\nexport function openMutationJournal(path?: string, persistValues = false): MutationJournal {\n if (!path) return new MutationJournal(undefined, persistValues)\n let journal = journals.get(path)\n if (!journal) { journal = new MutationJournal(path, persistValues); journals.set(path, journal) }\n return journal\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 ScheduleHistoryViewLike,\n ScheduleTaskViewLike,\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 { openMutationJournal, type MutationJournal } from './mutation-journal.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 toolArguments?: string\n}\n\ninterface PendingQuestion {\n rpcId: string\n sessionId: string\n questions: unknown\n}\n\nexport type ScheduleBridgeResult<T> =\n | { ok: true; value: T; replayed?: boolean }\n | { ok: false; kind: 'unsupported' | 'not-found' | 'invalid' | 'conflict' | 'busy' | 'internal'; message: string; replayed?: boolean }\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 activeTools = new Map<string, Map<string, string>>()\n private approvals = new Map<string, PendingApproval>()\n private questions = new Map<string, PendingQuestion>()\n private archivedSessionIds = new Set<string>()\n /** Mirrors archived rows from the last sessions.list so the phone can browse\n * and restore them. Excluded from `summaries` and from the live broadcast. */\n private archivedSummaries = new Map<string, SessionSummary>()\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 readonly scheduleMutations: MutationJournal\n readonly forkMutations: MutationJournal\n\n constructor(\n private readonly apiProxy: ApiProxyLike,\n private readonly historyBufferMax: number = MAX_RING_DEFAULT,\n deliveryJournalPath?: string,\n scheduleJournalPath?: string,\n forkJournalPath?: string,\n ) {\n this.promptDeliveries = openDeliveryJournal(deliveryJournalPath)\n this.scheduleMutations = openMutationJournal(scheduleJournalPath)\n this.forkMutations = openMutationJournal(forkJournalPath, true)\n }\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 sessionFork: typeof this.apiProxy.sessions.fork === 'function',\n sessionRestore: typeof this.apiProxy.workspace?.unarchiveSession === 'function',\n projectSelection: typeof this.apiProxy.workspace?.list === 'function' &&\n typeof this.apiProxy.workspace?.create === 'function',\n schedules: typeof this.apiProxy.schedule?.list === 'function' &&\n typeof this.apiProxy.schedule?.create === 'function',\n push: this.pushOutlet?.isAvailable() === true,\n widgetPush: true,\n liveActivityPush: true,\n // Always available: self-revocation only needs the device registry.\n deviceRevoke: 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 ((args.category === 'turn.completed' || args.category === 'session.error') &&\n 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/schedule-changed':\n this.record('s2c.schedule.changed', {})\n break\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 if (frame.isSubagent === true) this.subagentSessionIds.add(sessionId);\n if (this.subagentSessionIds.has(sessionId)) break;\n this.noteActivity(sessionId, event);\n this.captureAssistantText(sessionId, event);\n const projection = projectEvent(sessionId, event);\n this.captureActivity(sessionId, event, projection?.data.tool as { name?: string; summary?: string } | undefined);\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; callId?: 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 if (p.callId) void this.loadApprovalArguments(p.approvalId, p.callId);\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 // Archived sessions stay out of the live list and its broadcast so\n // existing clients keep their current behaviour; they are mirrored here\n // and served on demand through c2s.sessions.archived.\n const nextArchived = new Map<string, SessionSummary>();\n for (const row of response.result.value.items ?? []) {\n if (isSubagentRow(row)) this.subagentSessionIds.add(row.sessionId);\n if (this.subagentSessionIds.has(row.sessionId)) continue\n const summary = toSummary(row, this.approvals, this.questions, workspaceBySession.get(row.sessionId));\n if (this.archivedSessionIds.has(row.sessionId)) {\n nextArchived.set(row.sessionId, { ...summary, archived: true });\n continue\n }\n next.set(row.sessionId, summary);\n }\n for (const [id, calls] of this.activeTools) {\n const row = next.get(id);\n if (!row || (row.status !== 'running' && !row.pendingApproval && !row.pendingQuestion)) this.activeTools.delete(id);\n else row.activity = [...calls.values()].at(-1) ?? null;\n }\n // Worker identity is immutable for this bridge lifetime. A stale list or\n // a removed worker must not erase identity learned from the event stream.\n this.summaries = next;\n this.archivedSummaries = nextArchived;\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 captureActivity(sessionId: string, event: SessionEventLike, tool?: { name?: string; summary?: string }): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n const data = event.data as { callId?: string } | undefined;\n if (event.type === 'tool/call' && data?.callId) {\n const calls = this.activeTools.get(sessionId) ?? new Map<string, string>();\n const detail = [tool?.name, tool?.summary].filter(Boolean).join(': ');\n calls.set(data.callId, Array.from(detail).slice(0, 160).join(''));\n if (calls.size > 64) calls.delete(calls.keys().next().value!);\n this.activeTools.set(sessionId, calls);\n } else if (event.type === 'tool/result' && data?.callId) {\n this.activeTools.get(sessionId)?.delete(data.callId);\n } else if (event.type === 'turn/start' || event.type === 'turn/end') {\n this.activeTools.delete(sessionId);\n } else return;\n const activity = [...(this.activeTools.get(sessionId)?.values() ?? [])].at(-1) ?? null;\n if (row.activity === activity) return;\n row.activity = activity;\n // Tool progress must not reorder the session list or trigger Widget pushes.\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 * Archived rows from the last sessions.list, newest first. Served only on\n * demand so the live session list and its broadcast keep their shape for\n * clients that predate `c2s.sessions.archived`.\n */\n listArchivedSessions(): SessionSummary[] {\n return [...this.archivedSummaries.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 ...(pending.toolArguments !== undefined ? { toolArguments: pending.toolArguments } : {}),\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 /** Resolve only the exact invocation in this session; never guess from the latest tool. */\n private async loadApprovalArguments(requestId: string, callId: string): Promise<void> {\n const pending = this.approvals.get(requestId);\n if (!pending) return;\n try {\n const response = await this.apiProxy.sessions.history({\n rpcId: randomUUID(),\n payload: { sessionId: pending.sessionId, maxMessages: 200 },\n });\n if (this.disposed || this.approvals.get(requestId) !== pending || !response.result?.ok) return;\n const event = (response.result.value.events ?? []).map(row => row.event).find(event => {\n const data = event.data as { callId?: string; name?: string } | undefined;\n return event.type === 'tool/call' && data?.callId === callId && data?.name === pending.toolName;\n });\n const args = (event?.data as { arguments?: unknown } | undefined)?.arguments;\n if (typeof args !== 'string' || !args.trim()) return;\n pending.toolArguments = args;\n this.record('s2c.pending.approval', {\n requestId, sessionId: pending.sessionId, toolName: pending.toolName,\n summary: pending.reason, riskLevel: riskOf(pending.toolName), toolArguments: args,\n });\n } catch {\n // Keep the approval answerable with explicitly unavailable execution details.\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 // DSH exposes a complete per-session projection baseline; fold it\n // into the summary row when the phone opens a session so the first paint\n // does not depend on list-row hints or frames missed while offline.\n void this.refreshProjections(sessionId);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Pull one session's projection baseline and fold every key\n * through applyProjection — unknown keys are ignored there, `null` means the\n * session no longer exists, and any failure degrades to a diagnostic: opening\n * a session must never fail because a baseline could not be read.\n */\n private async refreshProjections(sessionId: string): Promise<void> {\n try {\n const response = await this.apiProxy.sessions.projections({\n rpcId: randomUUID(),\n payload: { sessionId },\n });\n if (this.disposed) return;\n const result = response.result;\n if (!result) return;\n if (!result.ok) {\n this.diagnostic('sessions.projections failed: ' + result.error.code);\n return;\n }\n const baseline = result.value;\n if (baseline === null || baseline === undefined) return;\n for (const [key, value] of Object.entries(baseline.values ?? {})) {\n this.applyProjection(sessionId, key, value);\n }\n } catch (error) {\n this.diagnostic('sessions.projections threw: ' + String((error as { message?: unknown })?.message ?? error));\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 unarchiveSession(sessionId: string): Promise<SessionManagementResult<true>> {\n const unarchive = this.apiProxy.workspace?.unarchiveSession\n if (typeof unarchive !== 'function') {\n return { ok: false, kind: 'unsupported', message: 'session restore unavailable on this host version' }\n }\n try {\n const response = await unarchive.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'session restore 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 // Rebuild both mirrors from the Host instead of hand-moving the row:\n // refreshSummaries re-emits s2c.sessions.delta, which carries the restored\n // session back to the client's live list.\n await this.refreshSummaries()\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 forkSession(\n deviceId: string,\n payload: { clientRequestId: string; sessionId: string; atSeq?: number },\n ): Promise<ScheduleBridgeResult<{ sessionId: string }>> {\n const fork = this.apiProxy.sessions.fork\n if (typeof fork !== 'function') return { ok: false, kind: 'unsupported', message: 'session fork unavailable on this host version' }\n if (!this.summaries.has(payload.sessionId)) return { ok: false, kind: 'not-found', message: 'session not found' }\n if (this.archivedSessionIds.has(payload.sessionId) || this.subagentSessionIds.has(payload.sessionId)) {\n return { ok: false, kind: 'invalid', message: 'archived or subagent sessions cannot be forked' }\n }\n const result = await this.forkMutations.dispatch(\n deviceId,\n payload.clientRequestId,\n { sessionId: payload.sessionId, ...(payload.atSeq !== undefined ? { atSeq: payload.atSeq } : {}) },\n async () => {\n const response = await fork.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId: payload.sessionId, ...(payload.atSeq !== undefined ? { atSeq: payload.atSeq } : {}) },\n })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'session fork returned no result' }\n if (!response.result.ok) return scheduleMutationError(response.result.error)\n return { ok: true, value: { sessionId: response.result.value.sessionId } }\n },\n )\n if (result.ok) {\n await this.refreshSummaries()\n return { ok: true, value: result.value as { sessionId: string }, replayed: result.replayed }\n }\n return { ok: false, kind: scheduleErrorKind(result.code), message: result.message ?? result.code, replayed: result.replayed }\n }\n\n async listSchedules(sessionId: string): Promise<ScheduleBridgeResult<ScheduleTaskViewLike[]>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, kind: 'unsupported', message: 'schedules unavailable on this host version' }\n try {\n const response = await schedule.list({ rpcId: randomUUID(), payload: { sessionId } })\n if (!response.result) return { ok: false, kind: 'internal', message: 'schedule list returned no result' }\n if (!response.result.ok) return scheduleHostError(response.result.error)\n return { ok: true, value: response.result.value.tasks }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async scheduleHistory(\n sessionId: string,\n id: string,\n limit: number,\n before?: string,\n ): Promise<ScheduleBridgeResult<ScheduleHistoryViewLike>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, kind: 'unsupported', message: 'schedules unavailable on this host version' }\n try {\n const response = await schedule.history({\n rpcId: randomUUID(),\n payload: { sessionId, id, limit, ...(before !== undefined ? { before } : {}) },\n })\n if (!response.result) return { ok: false, kind: 'internal', message: 'schedule history returned no result' }\n if (!response.result.ok) return scheduleHostError(response.result.error)\n return { ok: true, value: response.result.value.history }\n } catch (error) {\n return { ok: false, kind: 'internal', message: String(error) }\n }\n }\n\n async createSchedule(\n deviceId: string,\n payload: Record<string, unknown> & { sessionId: string; clientRequestId: string; title: string; prompt: string },\n ): Promise<ScheduleBridgeResult<ScheduleTaskViewLike>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, kind: 'unsupported', message: 'schedules unavailable on this host version' }\n const { clientRequestId, sessionId, ...request } = payload\n const result = await this.scheduleMutations.dispatch(\n deviceId,\n clientRequestId,\n { sessionId, request },\n async () => {\n const response = await schedule.create({ rpcId: randomUUID(), payload: { sessionId, ...request } })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule create returned no result' }\n if (!response.result.ok) return scheduleMutationError(response.result.error)\n return { ok: true, value: response.result.value }\n },\n )\n if (result.ok) {\n this.record('s2c.schedule.changed', {})\n return { ok: true, value: result.value as ScheduleTaskViewLike, replayed: result.replayed }\n }\n return { ok: false, kind: scheduleErrorKind(result.code), message: result.message ?? result.code, replayed: result.replayed }\n }\n\n async updateSchedule(\n deviceId: string,\n payload: Record<string, unknown> & { sessionId: string; id: string; clientRequestId: string; expected: unknown },\n ): Promise<ScheduleBridgeResult<ScheduleTaskViewLike>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, kind: 'unsupported', message: 'schedules unavailable on this host version' }\n const { clientRequestId, ...request } = payload\n const result = await this.scheduleMutations.dispatch(\n deviceId,\n clientRequestId,\n request,\n async () => {\n const response = await schedule.update({ rpcId: randomUUID(), payload: request })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule update returned no result' }\n if (!response.result.ok) return scheduleMutationError(response.result.error)\n const value = response.result.value\n if (value.updated !== true || value.record === undefined) {\n return { ok: false, code: scheduleCodeToError(value.code), message: value.code ?? 'schedule update rejected' }\n }\n return { ok: true, value: value.record }\n },\n )\n if (result.ok) {\n this.record('s2c.schedule.changed', {})\n return { ok: true, value: result.value as ScheduleTaskViewLike, replayed: result.replayed }\n }\n return { ok: false, kind: scheduleErrorKind(result.code), message: result.message ?? result.code, replayed: result.replayed }\n }\n\n async deleteSchedule(\n deviceId: string,\n payload: { sessionId: string; id: string; clientRequestId: string },\n ): Promise<ScheduleBridgeResult<{ id: string; deleted: true }>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, kind: 'unsupported', message: 'schedules unavailable on this host version' }\n const result = await this.scheduleMutations.dispatch(\n deviceId,\n payload.clientRequestId,\n { sessionId: payload.sessionId, id: payload.id },\n async () => {\n const response = await schedule.delete({\n rpcId: randomUUID(),\n payload: { sessionId: payload.sessionId, id: payload.id },\n })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule delete returned no result' }\n if (!response.result.ok) return scheduleMutationError(response.result.error)\n if (response.result.value.deleted !== true) {\n return { ok: false, code: 'E_NOT_FOUND', message: response.result.value.code ?? 'schedule not found' }\n }\n return { ok: true, value: { id: response.result.value.id, deleted: true as const } }\n },\n )\n if (result.ok) {\n this.record('s2c.schedule.changed', {})\n return { ok: true, value: result.value as { id: string; deleted: true }, replayed: result.replayed }\n }\n return { ok: false, kind: scheduleErrorKind(result.code), message: result.message ?? result.code, replayed: result.replayed }\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 scheduleHostError(error: { code: string; message?: string }): ScheduleBridgeResult<never> {\n const message = error.message ?? error.code\n switch (error.code) {\n case 'schedule_not_found':\n case 'delivery_cursor_not_found':\n return { ok: false, kind: 'not-found', message }\n case 'schedule_conflict':\n return { ok: false, kind: 'conflict', message }\n case 'invalid_prompt':\n case 'invalid_selector':\n case 'invalid_rule':\n case 'invalid_time_zone':\n case 'not_future':\n case 'time_out_of_range':\n case 'frequency_too_high':\n return { ok: false, kind: 'invalid', message }\n case 'schedule_ended':\n return { ok: false, kind: 'invalid', message }\n default:\n return { ok: false, kind: 'internal', message }\n }\n}\n\nfunction scheduleMutationError(error: { code: string; message?: string }): { ok: false; code: 'E_PROTOCOL' | 'E_NOT_FOUND' | 'E_BUSY' | 'E_UNSUPPORTED' | 'E_INTERNAL'; message: string } {\n const result = scheduleHostError(error)\n if (result.ok) return { ok: false, code: 'E_INTERNAL', message: 'unexpected schedule result' }\n return {\n ok: false,\n code: result.kind === 'not-found' ? 'E_NOT_FOUND'\n : result.kind === 'conflict' ? 'E_BUSY'\n : result.kind === 'invalid' ? 'E_PROTOCOL'\n : result.kind === 'unsupported' ? 'E_UNSUPPORTED' : 'E_INTERNAL',\n message: result.message,\n }\n}\n\nfunction scheduleCodeToError(code: string | undefined): 'E_PROTOCOL' | 'E_NOT_FOUND' | 'E_BUSY' | 'E_UNSUPPORTED' | 'E_INTERNAL' {\n if (code === 'schedule_not_found') return 'E_NOT_FOUND'\n if (code === 'schedule_conflict') return 'E_BUSY'\n if (code === 'schedule_ended') return 'E_PROTOCOL'\n if (code === 'invalid_prompt' || code === 'invalid_selector' || code === 'invalid_rule' || code === 'invalid_time_zone' || code === 'not_future' || code === 'time_out_of_range' || code === 'frequency_too_high') return 'E_PROTOCOL'\n return 'E_INTERNAL'\n}\n\nfunction scheduleErrorKind(code: string): 'unsupported' | 'not-found' | 'invalid' | 'conflict' | 'busy' | 'internal' {\n switch (code) {\n case 'E_NOT_FOUND': return 'not-found'\n case 'E_BUSY': return 'conflict'\n case 'E_PROTOCOL': return 'invalid'\n case 'E_UNSUPPORTED': return 'unsupported'\n default: return 'internal'\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 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 HostWireStreamLike {\n open(endpoint: string, payload: unknown, uplink: undefined, peer: undefined, signal: AbortSignal): Promise<AsyncIterable<unknown>>\n}\n\ninterface HostGatewayLike {\n wireStream: HostWireStreamLike\n}\n\ninterface ClientTransportHooksLike {\n fetch(input: string, init: RequestInit): Promise<Response>\n openStream(endpoint: string, payload: unknown, signal: AbortSignal): AsyncIterable<unknown>\n ownsHost: true\n}\n\n/** The rc.2 Client sends relative RPC paths to its in-process carrier. */\nexport function inProcessRemoteRequest(input: string, init: RequestInit): Request {\n // The shared Fetch handler routes by pathname and never performs a network\n // request. Node's Request still requires an absolute URL for relative paths.\n return new Request(new URL(input, 'http://localhost/'), init)\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 DshRemoteInteractionHandlers {\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, undefined, undefined, 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 startDshRemoteInteractions(\n hostCtx: Context,\n handlers: DshRemoteInteractionHandlers,\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 Host connection is unavailable')\n if (gateway === undefined) throw new Error('DSH 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(inProcessRemoteRequest(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 * Adapter for the DSH rc.2 controller API.\n *\n * DeepPilot's phone protocol deliberately speaks one stable in-process\n * `apiProxy` vocabulary. This adapter maps it to the current public\n * Session/Workspace controllers and Gateway-backed Remote Events, keeping\n * the phone protocol isolated from the Host API.\n */\nimport { randomUUID } from 'node:crypto'\nimport type { Context } from '@deepseek-ai/cordis'\nimport {\n startDshRemoteInteractions,\n type RemoteApprovalRequest,\n type RemoteQuestionRequest,\n} from './dsh-remote-interactions.ts'\nimport { projectHistory } from './host-event-projection.ts'\nimport type {\n ApiProxyLike,\n DirectoryListingLike,\n HistoryResult,\n HostSessionModels,\n MuxFrameLike,\n PhoneSessionRow,\n ScheduleHistoryViewLike,\n ScheduleTaskViewLike,\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 fork(request: { sessionId: string; atSeq?: number }): Promise<{ sessionId: 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 /** Non-activating projection baseline for one session. */\n projections(request: { sessionId: string }, signal?: AbortSignal):\n Promise<{ asOfSeq: number; values: Record<string, unknown> } | null>\n}\n\ninterface WorkspaceControllerLike {\n create(request: { path: string }): Promise<{ workspace: unknown; created: boolean }>\n archiveSession(request: { sessionId: string }): Promise<{ archivedSessionIds: readonly string[] }>\n unarchiveSession(request: { sessionId: string }): Promise<{ archivedSessionIds: readonly string[] }>\n follow(signal: AbortSignal): AsyncIterable<{ type: string; value?: unknown }>\n}\n\ninterface ScheduleControllerLike {\n list(request: { sessionId: string }): Promise<readonly unknown[]>\n history(request: { sessionId: string; id: string; limit: number; before?: string }): Promise<unknown>\n create(sessionId: string, request: Record<string, unknown>, signal?: AbortSignal): Promise<unknown>\n update(request: Record<string, unknown>, signal?: AbortSignal): Promise<unknown>\n delete(request: { sessionId: string; id: string }, signal?: AbortSignal): Promise<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 a Host waterfall result. */\n map(value: unknown): unknown\n}\n\n/** Which first-answer-wins interaction a phone may surface. */\nexport type DshInteractionKind = 'approval' | 'question'\n\nexport interface DshApiProxyOptions {\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 adapter with the shape HostBridge consumes. */\nexport class DshApiProxy implements ApiProxyLike {\n private readonly session: SessionControllerLike\n private readonly workspaceController: WorkspaceControllerLike | undefined\n private scheduleController: ScheduleControllerLike | undefined\n private scheduleApi: ApiProxyLike['schedule'] | 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: DshApiProxyOptions = {}) {\n const session = ctx.get('sessionController') as SessionControllerLike | undefined\n if (session === undefined) throw new Error('DSH sessionController is unavailable')\n this.session = session\n this.workspaceController = ctx.get('workspaceController') as WorkspaceControllerLike | undefined\n // A profile without the optional workspace service cannot restore a\n // session; keep the phone capability bit honest.\n if (this.workspaceController === undefined) delete this.workspace?.unarchiveSession\n this.directoryPicker = ctx.get('directoryPickerController') as DirectoryPickerControllerLike | undefined\n this.shouldSurfaceInteraction = options.shouldSurfaceInteraction ?? (() => true)\n this.resolveSchedule()\n }\n\n /**\n * Resolve the optional Schedule service lazily, on every read.\n *\n * The bridge is built from a `ctx.inject` on sessionController / connection\n * / typertGateway, and `schedule` is deliberately NOT in that list: it only\n * exists when the user enables the optional Automation tasks bundle. On a\n * DSH 0.2.0 host those three services become ready well before\n * ScheduleService finishes its own async init, so a value captured here in\n * the constructor stayed `undefined` for the bridge's whole lifetime and\n * welcome advertised `schedules=false` even with the bundle mounted.\n *\n * Once resolved the controller is kept: services are not torn down and\n * rebuilt underneath a live bridge, so re-resolving per call would be pure\n * overhead.\n */\n private resolveSchedule(): void {\n if (this.scheduleController !== undefined) return\n const controller = this.ctx.get('schedule') as ScheduleControllerLike | undefined\n if (controller === undefined) return\n this.scheduleController = controller\n this.scheduleApi = this.createScheduleApi(controller)\n }\n\n get schedule(): ApiProxyLike['schedule'] {\n this.resolveSchedule()\n return this.scheduleApi\n }\n\n private createScheduleApi(controller: ScheduleControllerLike): NonNullable<ApiProxyLike['schedule']> {\n return {\n list: async (request) => this.call(async () => ({\n sessionId: request.payload!.sessionId,\n tasks: (await controller.list({ sessionId: request.payload!.sessionId })).map(toScheduleTask),\n })),\n history: async (request) => this.call(async () => {\n const value = await controller.history({\n sessionId: request.payload!.sessionId,\n id: request.payload!.id,\n limit: request.payload!.limit,\n ...(request.payload!.before !== undefined ? { before: request.payload!.before } : {}),\n }) as Record<string, unknown>\n if (typeof value.code === 'string') {\n throw Object.assign(new Error(String(value.code)), { code: value.code })\n }\n return { sessionId: request.payload!.sessionId, history: toScheduleHistory(value) }\n }),\n create: async (request) => this.call(async () => {\n const { sessionId, ...createRequest } = request.payload!\n return toScheduleTask(await controller.create(sessionId, createRequest))\n }),\n update: async (request) => this.call(async () => {\n const payload = request.payload!\n const result = await controller.update({\n ...payload,\n expected: toScheduleExpected(payload.expected),\n }) as Record<string, unknown>\n return {\n id: String(result.id ?? payload.id),\n updated: result.updated === true,\n ...(result.record !== undefined ? { record: toScheduleTask(result.record) } : {}),\n ...(typeof result.code === 'string' ? { code: result.code } : {}),\n }\n }),\n delete: async (request) => this.call(async () => {\n const result = await controller.delete({ sessionId: request.payload!.sessionId, id: request.payload!.id }) as Record<string, unknown>\n return { id: String(result.id), deleted: result.deleted === true, ...(result.code !== undefined ? { code: String(result.code) } : {}) }\n }),\n }\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 // Keep worker identity internally so HostBridge can suppress notifications\n // as well as exclude these rows from the phone's session list.\n return { items: value.items.map(toPhoneSessionRow) }\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 fork: async (request) => this.call(() => this.session.fork(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 projections: async (request) => this.call(() => this.session.projections(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 unarchiveSession: async (request) => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const value = await this.workspaceController.unarchiveSession(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; header?: { origin?: string } }, event: unknown) => {\n queue.push({\n type: 'session/event', sessionId: String(session.id),\n // Header origin is available before the next list refresh. A header's\n // parentSession alone is fork lineage, not proof of a worker session.\n isSubagent: session.header?.origin === 'subagent',\n event: event as MuxFrameLike['event'],\n })\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 startDshRemoteInteractions(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 ...(request.callId ? { callId: request.callId } : {}),\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 listen('schedule/changed', 'host/schedule-changed'),\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}\nfunction toScheduleExpected(value: unknown): Record<string, unknown> {\n const row = value !== null && typeof value === 'object' ? value as Record<string, unknown> : {}\n const { state: _state, deliveryMode: _deliveryMode, ...record } = row\n return record\n}\nfunction toScheduleTask(value: unknown): ScheduleTaskViewLike {\n const row = value as Record<string, unknown>\n const kind = ['after', 'at', 'every', 'daily', 'weekly', 'cron'].includes(String(row.kind))\n ? String(row.kind) as ScheduleTaskViewLike['kind']\n : 'at'\n const optionalNumber = (key: string): number | undefined => typeof row[key] === 'number' && Number.isFinite(row[key]) ? row[key] as number : undefined\n return {\n id: String(row.id ?? ''),\n kind,\n title: String(row.title ?? ''),\n prompt: String(row.prompt ?? ''),\n scheduledAt: String(row.scheduledAt ?? ''),\n state: row.state === 'overdue' ? 'overdue' : 'scheduled',\n deliveryMode: 'host',\n ...(optionalNumber('afterSeconds') !== undefined ? { afterSeconds: optionalNumber('afterSeconds')! } : {}),\n ...(optionalNumber('everySeconds') !== undefined ? { everySeconds: optionalNumber('everySeconds')! } : {}),\n ...(typeof row.time === 'string' ? { time: row.time } : {}),\n ...(typeof row.timeZone === 'string' ? { timeZone: row.timeZone } : {}),\n ...(Array.isArray(row.weekdays) ? { weekdays: row.weekdays.filter((day): day is number => typeof day === 'number') } : {}),\n ...(typeof row.expression === 'string' ? { expression: row.expression } : {}),\n }\n}\nfunction toScheduleHistory(value: unknown): ScheduleHistoryViewLike {\n const row = value as Record<string, unknown>\n const records = Array.isArray(row.records) ? row.records : []\n return {\n id: String(row.id ?? ''),\n records: records.map((entry) => {\n const item = entry as Record<string, unknown>\n return {\n scheduledAt: String(item.scheduledAt ?? ''),\n deliveredAt: String(item.deliveredAt ?? ''),\n messageId: String(item.messageId ?? ''),\n ...(typeof item.prompt === 'string' ? { prompt: item.prompt } : {}),\n }\n }),\n earlierRecordsUnavailable: row.earlierRecordsUnavailable === true,\n ...(typeof row.earlierRecordsPruned === 'boolean' ? { earlierRecordsPruned: row.earlierRecordsPruned } : {}),\n retention: {\n days: Number((row.retention as { days?: unknown } | undefined)?.days ?? 0),\n records: Number((row.retention as { records?: unknown } | undefined)?.records ?? 0),\n },\n ...(typeof row.nextBefore === 'string' ? { nextBefore: row.nextBefore } : {}),\n }\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 DeviceRenamer = (deviceId: string, customName: string | null) => Promise<string | null>\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 deviceRenamer: DeviceRenamer\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 deviceRenamer: DeviceRenamer,\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.deviceRenamer = deviceRenamer\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 setDeviceName(deviceId: string, customName: string | null): Promise<string | null> {\n return this.deviceRenamer(deviceId, customName)\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, TypertCodec, 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 /** Effective operator-facing name: customName when set, otherwise the app-reported name. */\n deviceName: string\n /** User-assigned label; absent means the app-reported name is in use. */\n customName?: 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 /** Private IPv4 candidates for local QR pairing. */\n lanAddresses: string[]\n /** Independent TLS-only 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 /** `sha256:` SPKI pin of the LAN certificate; present while `online`. */\n tlsFingerprint?: string\n /** The LAN private key was recreated this run: paired LAN devices must pair again. */\n tlsIdentityRegenerated?: boolean\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_NAME_ENDPOINT = 'deeppilot/setDeviceName'\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 const customName = s.customName\n if (customName !== undefined && (\n typeof customName !== 'string' ||\n customName.length === 0 ||\n customName.length > 64 ||\n customName.trim() !== customName ||\n /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(customName)\n )) reject('device.customName')\n return {\n deviceId: str(s, 'deviceId', 'device.deviceId'),\n deviceName: str(s, 'deviceName', 'device.deviceName'),\n ...(typeof customName === 'string' ? { customName } : {}),\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 const tlsFingerprint = s.tlsFingerprint\n if (tlsFingerprint !== undefined && typeof tlsFingerprint !== 'string') reject('local.tlsFingerprint')\n const tlsIdentityRegenerated = s.tlsIdentityRegenerated\n if (tlsIdentityRegenerated !== undefined && typeof tlsIdentityRegenerated !== 'boolean') reject('local.tlsIdentityRegenerated')\n return {\n phase: phase as DeepPilotReport['local']['phase'],\n port: int(s, 'port', 'local.port'),\n endpoints: endpoints as string[],\n ...(typeof tlsFingerprint === 'string' ? { tlsFingerprint } : {}),\n ...(tlsIdentityRegenerated === true ? { tlsIdentityRegenerated: true } : {}),\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 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 customNameSchema: TypertSchema<string | null> = {\n parse(value: unknown): string | null {\n if (value === null) return null\n if (typeof value !== 'string') reject('customName')\n const trimmed = value.trim()\n if (trimmed.length === 0 || trimmed.length > 64 || /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(value)) reject('customName')\n return trimmed\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/** The rc.2 Gateway materializes each strict codec through `create()`. */\nfunction strictCodec<T>(typeSymbol: string, schema: TypertSchema<T>): TypertCodec {\n return {\n mode: 'strict',\n typeSymbol,\n create: () => schema,\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeepPilotReport`, reportSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#PairingGrantSnapshot`, pairingGrantSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceId`, deviceIdSchema),\n }],\n result: strictCodec(`${REPORT_REMOTE_PACKAGE}#Boolean`, booleanSchema),\n}\n\nexport const SET_DEVICE_NAME_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${SET_DEVICE_NAME_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'setDeviceName',\n invocation: { kind: 'direct' },\n parameters: [\n {\n name: 'deviceId', wire: 'deviceId', source: 'json',\n codec: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceId`, deviceIdSchema),\n },\n {\n name: 'customName', wire: 'customName', source: 'json',\n codec: strictCodec(`${REPORT_REMOTE_PACKAGE}#CustomDeviceName`, customNameSchema),\n },\n ],\n result: strictCodec(`${REPORT_REMOTE_PACKAGE}#CustomDeviceName`, customNameSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceId`, deviceIdSchema),\n },\n {\n name: 'scopes', wire: 'scopes', source: 'json',\n codec: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceScopes`, scopesSchema),\n },\n ],\n result: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceScopes`, scopesSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#RelayTestResult`, relayTestSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#PushTestResult`, pushTestSchema),\n}\n\nconst INVOCATION_DESCRIPTORS = [\n REPORT_DESCRIPTOR,\n BEGIN_PAIRING_DESCRIPTOR,\n REVOKE_DEVICE_DESCRIPTOR,\n SET_DEVICE_NAME_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 // This 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 { DeviceRenamer, 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 deviceRenamer: DeviceRenamer,\n deviceScopeUpdater: DeviceScopeUpdater,\n relayTester: RelayTester,\n pushTester: PushTester,\n): void {\n ctx.inject(['typert'], (remoteCtx) => {\n new DeepPilotReportService(remoteCtx, snapshot, pairingStarter, deviceRevoker, deviceRenamer, 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\n/** The LAN listener is TLS-only, so every advertised endpoint is `https://`. */\nexport function localEndpointURLs(addresses: readonly string[], port: number): string[] {\n const normalizedPort = normalizeLocalPort(port)\n return [...new Set(addresses)].map((address) => `https://${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 /** Testing & troubleshooting, rendered as its own settings section. */\n diagnostics?: {\n /** Verbose per-frame diagnostics (never prints token or message bodies). */\n debug?: boolean\n }\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 // rc.2 accepts live settings writes only for fields declared volatile.\n enabled: z.boolean().default(true).volatile(),\n devicesPath: z.string().default(join(bridgeDataDir(), 'devices-v2.json')),\n historyBufferMax: z.natural().min(100).default(2000),\n diagnostics: z.object({\n debug: z.boolean().default(false)\n .description('打印握手、推送等诊断日志;不会打印配对令牌、APNs token 或消息内容'),\n }).default({\n debug: false,\n }).volatile(),\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 局域网独立端口(仅 TLS;默认 3098,修改后本地连接会短暂重连)'),\n }).default({\n enabled: true,\n port: DEFAULT_LOCAL_PORT,\n }).volatile(),\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 }).volatile(),\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 * Deep-unwrap live-update (volatile) references to plain values.\n *\n * On a 0.1.7 host, `apply()`'s options — and even a direct `Config(raw)` call\n * — carry `{ get() }` reference objects for volatile fields. Every consumer of\n * `currentConfig()` compares plain values (`=== true`, numeric bounds, object\n * fields), and schemastery refuses to re-parse a reference, so normalization\n * unwraps on the way in and on the way out. A JSON-shaped config value cannot\n * carry a function, so the `get` check cannot false-positive.\n */\nexport function plainConfig(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value\n if (typeof (value as { get?: unknown }).get === 'function') {\n // A reference's snapshot is recursively plain data (references cannot\n // nest inside references), so one unwrap layer suffices; recursion keeps\n // plain containers working around it.\n return plainConfig((value as { get: () => unknown }).get())\n }\n if (Array.isArray(value)) return value.map(plainConfig)\n const plain: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) plain[key] = plainConfig(item)\n return plain\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 — and\n * unwrap volatile references so the returned Config is plain data.\n */\nexport function normalizeOptions(options: unknown): Config {\n if (typeof options === 'function') return plainConfig((options as () => unknown)()) as Config\n if (options && typeof options === 'object') return plainConfig(options) as Config\n const validated = (Config as unknown as (data: unknown) => Config)(undefined)\n return plainConfig(validated ?? {}) as Config\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 ?? session?.todoItems?.length ?? 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(session?.activity?.trim() || task?.content || '').slice(0, 160).join(''), done, total,\n phase: !session || total === 0 ? '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 as createHttpServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport { createServer as createHttpsServer } from 'node:https'\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\nexport interface PhoneServerTls {\n key: string\n cert: string\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 *\n * With `tls` the listener speaks HTTPS/WSS only (the LAN posture); without\n * it the listener is plain HTTP, which is reserved for the loopback Funnel\n * origin where tailscaled terminates TLS.\n */\nexport function createPhoneServer(handlers: PhoneServerHandlers, tls?: PhoneServerTls): Server {\n const onRequest = (req: IncomingMessage, res: ServerResponse): void => {\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 const server: Server = tls === undefined\n ? createHttpServer(onRequest)\n : createHttpsServer({ key: tls.key, cert: tls.cert, minVersion: 'TLSv1.2' }, onRequest)\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 { createHash, createPrivateKey, createPublicKey, X509Certificate } from 'node:crypto'\nimport { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { generate } from 'selfsigned'\n\nexport { LAN_TLS_FINGERPRINT_PATTERN, isLanTlsFingerprint } from './pairing-qr.ts'\n\nexport const LAN_TLS_COMMON_NAME = 'dsh-deeppilot'\nexport const LAN_TLS_KEY_FILE = 'key.pem'\nexport const LAN_TLS_CERT_FILE = 'cert.pem'\n\nconst CERT_VALIDITY_MS = 10 * 365 * 24 * 60 * 60_000\n/** Re-sign this far ahead of expiry so a long-running host never serves a stale leaf. */\nconst CERT_RENEW_LEAD_MS = 30 * 24 * 60 * 60_000\n\nexport interface LanTlsIdentity {\n /** PKCS#8 PEM private key. Never logged or reported. */\n key: string\n /** Self-signed X.509 PEM leaf certificate. */\n cert: string\n /** Pinned by paired devices; changes only when the private key changes. */\n fingerprint: string\n /** Unix ms when the current leaf certificate expires. */\n notAfter: number\n /**\n * The private key was newly created. Devices that pinned the previous\n * identity can no longer connect and must pair again.\n */\n regenerated: boolean\n /** A fresh leaf was signed with the existing key; the fingerprint is unchanged. */\n resigned: boolean\n}\n\n/** Compute the pinned public-key fingerprint of a PEM certificate. */\nexport function spkiFingerprint(certPem: string): string {\n const der = createPublicKey(certPem).export({ type: 'spki', format: 'der' })\n return 'sha256:' + createHash('sha256').update(der).digest('base64url')\n}\n\n/**\n * Load the LAN listener's TLS identity from `dir`, creating or repairing it\n * as needed. The private key is the durable identity: it is created once and\n * reused for every subsequent certificate, so pinned devices survive\n * certificate renewals. Only a missing or unreadable key forces a new one.\n */\nexport async function loadOrCreateLanTlsIdentity(dir: string, now: number = Date.now()): Promise<LanTlsIdentity> {\n await mkdir(dir, { recursive: true, mode: 0o700 })\n const keyPath = join(dir, LAN_TLS_KEY_FILE)\n const certPath = join(dir, LAN_TLS_CERT_FILE)\n\n let key = await readPem(keyPath)\n let regenerated = false\n if (key === undefined || !validPrivateKey(key)) {\n regenerated = true\n key = undefined\n }\n\n let cert = regenerated ? undefined : await readPem(certPath)\n let resigned = false\n const existing = key !== undefined && cert !== undefined ? inspectCertificate(cert, key, now) : undefined\n if (existing === undefined) {\n const issued = await issueCertificate(key, now)\n if (key === undefined) {\n key = pemFile(issued.key)\n await writePrivate(keyPath, key)\n } else {\n resigned = true\n }\n cert = pemFile(issued.cert)\n await writePrivate(certPath, cert)\n }\n if (key === undefined || cert === undefined) throw new Error('LAN TLS identity unavailable')\n\n return {\n key,\n cert,\n fingerprint: spkiFingerprint(cert),\n notAfter: existing ?? new X509Certificate(cert).validToDate.getTime(),\n regenerated,\n resigned,\n }\n}\n\nasync function readPem(path: string): Promise<string | undefined> {\n try {\n const text = await readFile(path, 'utf8')\n return text.trim().length > 0 ? text : undefined\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n // Any other read failure is treated like a missing file: the caller\n // rewrites the identity and the operator sees the \"regenerated\" signal.\n return undefined\n }\n}\n\nfunction validPrivateKey(pem: string): boolean {\n try {\n const key = createPrivateKey(pem)\n return key.asymmetricKeyType === 'ec'\n } catch {\n return false\n }\n}\n\n/**\n * Return the certificate's expiry when it is usable with `keyPem`, or\n * `undefined` when it must be re-issued (malformed, wrong key, or expiring).\n */\nfunction inspectCertificate(certPem: string, keyPem: string, now: number): number | undefined {\n try {\n const cert = new X509Certificate(certPem)\n const certSpki = cert.publicKey.export({ type: 'spki', format: 'der' })\n const keySpki = createPublicKey(createPrivateKey(keyPem)).export({ type: 'spki', format: 'der' })\n if (!certSpki.equals(keySpki)) return undefined\n const notAfter = cert.validToDate.getTime()\n const notBefore = cert.validFromDate.getTime()\n if (!(notBefore <= now && notAfter - CERT_RENEW_LEAD_MS > now)) return undefined\n return notAfter\n } catch {\n return undefined\n }\n}\n\nasync function issueCertificate(existingKey: string | undefined, now: number): Promise<{ key: string; cert: string }> {\n // Back-date slightly so a phone whose clock trails the Mac still accepts a\n // certificate issued moments ago.\n const notBeforeDate = new Date(now - 5 * 60_000)\n const notAfterDate = new Date(now + CERT_VALIDITY_MS)\n const keyPair = existingKey === undefined\n ? undefined\n : {\n privateKey: createPrivateKey(existingKey).export({ type: 'pkcs8', format: 'pem' }) as string,\n publicKey: createPublicKey(existingKey).export({ type: 'spki', format: 'pem' }) as string,\n }\n const result = await generate(\n [{ name: 'commonName', value: LAN_TLS_COMMON_NAME }],\n {\n keyType: 'ec',\n curve: 'P-256',\n algorithm: 'sha256',\n notBeforeDate,\n notAfterDate,\n ...(keyPair ? { keyPair } : {}),\n extensions: [\n { name: 'basicConstraints', cA: false, critical: true },\n { name: 'keyUsage', digitalSignature: true, keyAgreement: true, critical: true },\n { name: 'extKeyUsage', serverAuth: true },\n { name: 'subjectAltName', altNames: [{ type: 2, value: LAN_TLS_COMMON_NAME }] },\n ],\n },\n )\n return { key: existingKey ?? result.private, cert: result.cert }\n}\n\n/** Exact on-disk form, so a freshly issued value equals its later reload. */\nfunction pemFile(pem: string): string {\n return pem.replace(/\\r\\n/g, '\\n').trimEnd() + '\\n'\n}\n\nasync function writePrivate(path: string, contents: string): Promise<void> {\n const tmp = `${path}.${process.pid}.tmp`\n try {\n await writeFile(tmp, contents, { mode: 0o600 })\n await rename(tmp, path)\n } catch (error) {\n await unlink(tmp).catch(() => {})\n throw error\n }\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 { DshApiProxy, type DshInteractionKind } from './dsh-api-proxy.ts'\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, deviceDisplayName, 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 { DEFAULT_RELAY_URL, normalizeOptions } from './config.ts'\nimport type { Config } 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'\nimport { loadOrCreateLanTlsIdentity, type LanTlsIdentity } from './lan-tls.ts'\n\n/**\n * dsh-deeppilot — data bridge between the DSH host and DeepPilot\n * clients. Owns independent, narrowly routed LAN (TLS-only, pinned by paired\n * devices) and loopback Funnel-origin listeners. The web UI and the rest of\n * DSH's API are never exposed by these listeners.\n *\n * Data plane: an in-process HostBridge consumes a local adapter over DSH\n * 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 web-service requirement: the plugin owns its own transport listeners. */\nexport const inject: string[] = []\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 let scheduleRemoteReconcile: (() => void) | undefined\n let scheduleLocalReconcile: (() => void) | undefined\n const currentConfig = (): Config => normalizeOptions(options)\n const enabledNow = (): boolean => currentConfig().enabled === true\n\n // rc.2 commits volatile config edits into live refs and emits on the owning\n // fiber. Reconcile transport listeners after the new values are published.\n ;(ctx as unknown as { on: (name: string, listener: () => void) => void }).on(\n 'loader/volatile-update',\n () => queueMicrotask(() => {\n scheduleLocalReconcile?.()\n scheduleRemoteReconcile?.()\n }),\n )\n\n // Master switch, resolved against the current profile entry.\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: deviceDisplayName(device),\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 /**\n * Unbind one device. Single path shared by the settings page (report-service\n * revokeDevice) and the wire-level c2s.device.revoke frame: mark the registry\n * tombstone (which also drops every APNs/WidgetKit/LiveActivity token, so the\n * push fan-out can no longer select it) and hard-drop its live sockets.\n * `except` is the connection that sent the revoke frame — it closes itself\n * with 4401 after acking, so it is not terminated here.\n */\n const revokeDevice = async (deviceId: string, except?: BridgeConnection): Promise<boolean> => {\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 === except || connection.connectedDeviceId !== deviceId) continue\n connection.terminate()\n connections.delete(connection)\n }\n log(`device revoked id=${auditLabel(deviceId)}`)\n }\n return revoked\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().diagnostics?.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().diagnostics?.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().diagnostics?.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().diagnostics?.debug === true) {\n log(`push skip \"${deviceDisplayName(device)}\": notification permission not granted`)\n }\n return false\n }\n if (registration.categories?.[notification.category] === false) {\n if (currentConfig().diagnostics?.debug === true) {\n log(`push skip \"${deviceDisplayName(device)}\": 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} → \"${deviceDisplayName(device)}\" [${registration.environment}] = ${outcome}${reason ? ' (' + reason + ')' : ''}`)\n if (shouldPrunePushToken(outcome, reason)) {\n devices.clearPushToken(device.deviceId)\n log(`push: pruned stale token of \"${deviceDisplayName(device)}\" (${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 // The LAN TLS identity is loaded once per plugin lifetime: port or enable\n // toggles reuse it so paired devices keep their pin. `tlsIdentityRegenerated`\n // stays raised for the settings page until the next restart because it\n // means every previously paired LAN device must pair again.\n let lanTlsIdentity: Promise<LanTlsIdentity> | undefined\n let tlsIdentityRegenerated = false\n const loadLanTls = (): Promise<LanTlsIdentity> => {\n lanTlsIdentity ??= (async () => {\n await ready\n const identity = await loadOrCreateLanTlsIdentity(join(dataDir, 'lan-tls'))\n if (identity.regenerated) {\n tlsIdentityRegenerated = true\n log(`LAN TLS identity created: fingerprint=${identity.fingerprint}; previously paired LAN devices must pair again`)\n } else if (identity.resigned) {\n log(`LAN TLS certificate renewed (fingerprint unchanged: ${identity.fingerprint})`)\n }\n return identity\n })()\n // A failed load (disk error) must not poison later reconciles.\n lanTlsIdentity.catch(() => { lanTlsIdentity = undefined })\n return lanTlsIdentity\n }\n const localStatus = (addresses: readonly string[]): DeepPilotReport['local'] => ({\n ...localState,\n endpoints: localState.phase === 'online' ? localEndpointURLs(addresses, localState.port) : [],\n ...(tlsIdentityRegenerated ? { tlsIdentityRegenerated: true } : {}),\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; customName?: 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, customName, appVersion, firstSeenTs, lastSeenTs, fingerprint, scopes, revokedAt, apns }) => ({\n deviceId,\n deviceName: deviceDisplayName({ deviceName, customName }),\n ...(customName ? { customName } : {}),\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 lanAddresses,\n local: localStatus(lanAddresses),\n remote: remoteStatus(),\n devices,\n }\n }, beginPairing, async (deviceId) => {\n // Settings-page revocation shares the exact path used by the wire-level\n // c2s.device.revoke frame (index.ts revokeDevice helper).\n return await revokeDevice(deviceId)\n }, async (deviceId, customName) => {\n const { devices } = await ready\n if (!devices) throw new Error('device registry unavailable')\n const effectiveName = await devices.setCustomName(deviceId, customName)\n if (effectiveName === null) throw new Error('active device not found')\n const normalized = customName === null ? '' : sanitizeDeviceField(customName, MAX_DEVICE_NAME_CHARS)\n log(`device custom name updated id=${auditLabel(deviceId)} custom=${String(normalized.length > 0)}`)\n return normalized === '' ? null : normalized\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 // Only a request that arrived over the LAN TLS listener echoes the pin;\n // Funnel pairings terminate TLS at tailscaled with a public CA cert.\n const overLanTls = (req.socket as { encrypted?: boolean }).encrypted === true\n const tlsFingerprint = overLanTls ? (await lanTlsIdentity)?.fingerprint : undefined\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 ...(tlsFingerprint ? { tlsFingerprint } : {}),\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().diagnostics?.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 // A device that unbinds itself from the app must not leave a\n // second socket (e.g. an older install) still live: the\n // registry tombstone is already written by the handler, so\n // this only drops the sibling sockets.\n onDeviceRevoke: (deviceId, except) => revokeDevice(deviceId, except),\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 let server: ReturnType<typeof createPhoneServer> | undefined\n try {\n const tls = await loadLanTls()\n if (localDisposed || appliedLocalKey !== nextKey) return\n server = createPhoneServer(phoneHandlers, { key: tls.key, cert: tls.cert })\n localServer = server\n await listen(server, next.port, '0.0.0.0')\n if (localDisposed || localServer !== server) {\n await closeServer(server)\n return\n }\n localState = {\n phase: 'online',\n port: next.port,\n endpoints: [],\n tlsFingerprint: tls.fingerprint,\n updatedAt: Date.now(),\n }\n log(`local transport listening on https://0.0.0.0:${next.port} (tls fingerprint ${tls.fingerprint})`)\n } catch (error) {\n if (server !== undefined) {\n if (localServer === server) localServer = undefined\n await closeServer(server)\n }\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 // Build the bridge's stable protocol-facing adapter from the public\n // 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: DshApiProxy\n try {\n proxy = new DshApiProxy(apiCtx, { shouldSurfaceInteraction: hasPairedPhoneSurface })\n } catch (error) {\n log('DSH session bridge unavailable: ' + String(error))\n return\n }\n const bridge = new HostBridge(\n proxy,\n cfg.historyBufferMax,\n join(dataDir, 'prompt-deliveries-v1.json'),\n join(dataDir, 'schedule-mutations-v1.json'),\n join(dataDir, 'fork-mutations-v1.json'),\n )\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 ;(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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"}
1
+ {"version":3,"file":"index.js","names":["reject","reject","reject","reject","reject","reject","fsConstants","cryptoSign","alert","http2Connect","createHttpServer","createHttpsServer","record","httpsRequest"],"sources":["../src/wire-errors.ts","../src/connection-policy.ts","../src/auth-rate-limit.ts","../src/device-auth.ts","../src/wire-interaction.ts","../src/wire-device.ts","../src/token.ts","../src/wire-push.ts","../src/wire-schedule.ts","../src/document-payload.ts","../src/host-event-projection.ts","../src/wire-session.ts","../src/wire-registry.ts","../src/connection-gate.ts","../src/connection.ts","../src/funnel-policy.ts","../src/remote-supervisor.ts","../src/local-policy.ts","../src/config.ts","../src/apns.ts","../src/relay-url.ts","../src/relay-client.ts","../src/widget-push.ts","../src/live-activity.ts","../src/push-policy.ts","../src/relay-test.ts","../src/push-gateway.ts","../src/phone-server.ts","../src/transport-reconciler.ts","../src/dispatch-journal.ts","../src/host-api.ts","../src/host-capabilities.ts","../src/host-bridge.ts","../src/dsh-remote-interactions.ts","../src/dsh-api-proxy.ts","../src/report-service.ts","../src/report-wire.ts","../src/report-remote.ts","../src/local-address.ts","../src/update-check.ts","../src/phone-http.ts","../src/lan-tls.ts","../src/index.ts"],"sourcesContent":["/**\n * 错误词表(error vocabulary)的唯一属主。\n *\n * 一条失败信息在系统里要过三种词汇:Host 控制器返回的错误码(`session-not-found`、\n * `schedule_conflict`……)、Bridge 结果里的状态、以及 wire 上的 `E_*` 码。\n * 此前这三层各有映射函数(host-bridge 里 5 个、connection-policy 里 2 个、\n * connection.ts 的 switch 里 5 处内联三元链),一处漂移就会让客户端对\n * 「该不该重试」的判断失真。\n *\n * 本 module 只做一次翻译:每个域一张「Host code -> wire code」表,\n * Bridge 的结果直接携带 wire 码。`E_BUSY` 与 `E_PROTOCOL` 决定客户端是否\n * 重试,因此这张表是 wire 行为的一部分,逐码都有测试把守。\n *\n * 规范见 PROTOCOL.md 错误码表(`E_PROTOCOL` = 未知类型或非法 payload,\n * `E_FORBIDDEN` = 权限不足,`E_UNSUPPORTED` = 能力缺失)。\n */\n\n/** wire 错误码及其规范描述;PROTOCOL.md 错误码表的 TS 镜像。 */\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\nexport type WireErrorCode = keyof typeof ERROR_CODES\n\n/** Bridge 未携带 code 的结果(内部守卫失败等)落到这一档。 */\nexport const WIRE_ERROR_FALLBACK: WireErrorCode = 'E_INTERNAL'\n\n/**\n * 每个域一张「Host code -> wire code」表。查不到的 Host code 归\n * `E_INTERNAL`:未知的 Host 失败对手机没有可执行含义,重试只会放大故障。\n *\n * 表的取值与迁移前的行为逐码一致(见 tests/wire-errors.test.ts 的对等部分),\n * 即此前各映射链的并集——包括 models 域把 `model-unavailable` 映到\n * `E_NOT_FOUND` 的现行取值。\n *\n * 键写的是 DSH 实际抛出的**带命名空间**的码(旧 host 的扁平写法作为兼容别名\n * 逐条保留,它们同时充当「命名空间换了但尾部没换」时的兜底——查表会先原样命中,\n * 再剥前缀命中,见 lookupCode)。\n *\n * schedule 域例外:定时任务服务(`@deepseek-ai/dsh-schedule`)至今仍抛扁平\n * snake_case(`schedule_not_found`),不要给它加命名空间。\n */\nexport type ErrorDomain = 'session' | 'model' | 'schedule'\n\nconst DOMAIN_TABLES: Record<ErrorDomain, Readonly<Record<string, WireErrorCode>>> = {\n // 会话/工作区/目录管理域的 Host 错误码。\n session: {\n 'session/not-found': 'E_NOT_FOUND',\n 'workspace/not-found': 'E_NOT_FOUND',\n 'session/agent-busy': 'E_BUSY',\n // writer-held 与 agent-busy 同类:会话正被别人占着写,稍后重试有意义。\n 'session/writer-held': 'E_BUSY',\n 'session/conflict': 'E_BUSY',\n 'workspace/session-active': 'E_BUSY',\n 'gateway/bad-request': 'E_PROTOCOL',\n 'session/title-invalid': 'E_PROTOCOL',\n 'session/attachment-invalid': 'E_PROTOCOL',\n 'session/invalid-time-zone': 'E_PROTOCOL',\n 'workspace/invalid-path': 'E_PROTOCOL',\n 'workspace/name-conflict': 'E_PROTOCOL',\n 'workspace/move-invalid': 'E_PROTOCOL',\n 'workspace-file/not-found': 'E_NOT_FOUND',\n 'directory-picker/unavailable': 'E_UNSUPPORTED',\n // 旧 host 的扁平写法:保留是为了兼容仍在跑的老 DSH。\n 'session-not-found': 'E_NOT_FOUND',\n 'workspace-not-found': 'E_NOT_FOUND',\n 'agent-busy': 'E_BUSY',\n 'session-conflict': 'E_BUSY',\n 'title-invalid': 'E_PROTOCOL',\n 'workspace-invalid-path': 'E_PROTOCOL',\n 'workspace-name-conflict': 'E_PROTOCOL',\n 'directory-unreadable': 'E_PROTOCOL',\n 'directory-exists': 'E_PROTOCOL',\n 'directory-create-failed': 'E_PROTOCOL',\n 'directory-picker-unavailable': 'E_UNSUPPORTED',\n },\n // 模型目录与切换域的 Host 错误码。\n model: {\n 'session/not-found': 'E_NOT_FOUND',\n 'session/agent-busy': 'E_BUSY',\n 'session/writer-held': 'E_BUSY',\n 'session/conflict': 'E_BUSY',\n 'session/model-unavailable': 'E_NOT_FOUND',\n // 旧 host 的扁平写法。\n 'session-not-found': 'E_NOT_FOUND',\n 'agent-busy': 'E_BUSY',\n 'session-conflict': 'E_BUSY',\n 'model-unavailable': 'E_NOT_FOUND',\n },\n // 定时任务域的 Host 错误码(snake_case 是 Host Schedule 服务的词表,至今未变)。\n schedule: {\n 'schedule_not_found': 'E_NOT_FOUND',\n 'delivery_cursor_not_found': 'E_NOT_FOUND',\n 'schedule_conflict': 'E_BUSY',\n 'invalid_prompt': 'E_PROTOCOL',\n 'invalid_selector': 'E_PROTOCOL',\n 'invalid_rule': 'E_PROTOCOL',\n 'invalid_time_zone': 'E_PROTOCOL',\n 'not_future': 'E_PROTOCOL',\n 'time_out_of_range': 'E_PROTOCOL',\n 'frequency_too_high': 'E_PROTOCOL',\n 'schedule_ended': 'E_PROTOCOL',\n // DSH 0.2.1-alpha.1 新增:目标会话属于子代理路由,投递永远到不了它,\n // Host 对 create/update 拒绝(delete 仍放行以便清理旧数据)。\n // 归 E_PROTOCOL 而非 E_UNSUPPORTED:能力本身在宿主上存在,是这次请求\n // 的目标不可满足,重试无意义。与其余「参数/时序不合法」类拒绝同档。\n 'subagent_session': 'E_PROTOCOL',\n },\n}\n\n/**\n * 一个 Host 失败在 Bridge 侧的形状。\n *\n * `details` 是 DSH 的 `RemoteError` 附带的结构化载荷(dsh-typert-protocol 的\n * `remote-error.d.ts`),键由错误码决定;prompt 准入那一路的 `reason` 装的就是\n * 被包装掉的真实原因。窄化成只读 `reason` 是因为**只有**这一路会用到它。\n */\nexport interface HostFailure {\n code: string\n message?: string\n readonly details?: { readonly reason?: unknown } | undefined\n}\n\n/**\n * 剥掉 `namespace/` 前缀:`session/agent-busy` -> `agent-busy`。\n *\n * DSH 的 API 层现在抛的是带命名空间的码(`session/agent-busy`、\n * `workspace/not-found`、`gateway/internal`……),而下面的表一开始只有扁平写法。\n * 两边对不上时整表失配、一律落进 `E_INTERNAL`,于是 `E_BUSY` 永远出不来——\n * 而 `E_BUSY` 正是客户端决定「该不该重试」的那个码(issue #26)。\n */\nexport function canonicalHostCode(code: string): string {\n const slash = code.lastIndexOf('/')\n return slash === -1 ? code : code.slice(slash + 1)\n}\n\n/** 查表顺序:原样命中优先,其次剥掉命名空间后命中,最后才是兜底。 */\nfunction lookupCode(domain: ErrorDomain, code: string): WireErrorCode {\n const table = DOMAIN_TABLES[domain]\n return table[code] ?? table[canonicalHostCode(code)] ?? WIRE_ERROR_FALLBACK\n}\n\n/** 一个 Host 失败翻译成 Bridge 的失败结果:直接携带 wire 错误码。 */\nexport function wireErrorOf(\n domain: ErrorDomain,\n error: HostFailure,\n): { ok: false; code: WireErrorCode; message: string } {\n const code = lookupCode(domain, error.code)\n return {\n ok: false,\n code,\n message: describeFailure(error, code),\n }\n}\n\n/**\n * 组装给手机看的那句话。\n *\n * DSH 把 prompt 准入的**任意**内部失败包成 `session/agent-busy`,真实原因只留在\n * `details.reason`(`@deepseek-ai/dsh-api-session-controller` 的 `types/commands.js`\n * 里那一句 `throw new RemoteError('session/agent-busy', 'prompt rejected', { reason: … })`)。\n * 插件原先只取 `message`,于是手机端永远只显示笼统的「发送未确认」。\n *\n * 只在落到 `E_INTERNAL` 时追加 reason:这类码按定义对客户端没有可执行含义,\n * 多这一句不改变「该不该重试」的判断,却能让用户和排查者看到真正的原因。已映射\n * 的码本身已经可执行,保持原样不动。\n */\nfunction describeFailure(error: HostFailure, wireCode: WireErrorCode): string {\n const base = error.message ?? error.code\n if (wireCode !== WIRE_ERROR_FALLBACK) return base\n const reason = error.details?.reason\n if (typeof reason !== 'string' || reason.length === 0) return base\n return `${base} (${error.code}): ${reason}`\n}\n\n/** 只有一个 Host code(没有附带 message)时取它的 wire 码。 */\nexport function wireCodeFor(domain: ErrorDomain, hostCode: string | undefined): WireErrorCode {\n if (hostCode === undefined) return WIRE_ERROR_FALLBACK\n return lookupCode(domain, hostCode)\n}\n\n/**\n * 回答待决 approval/question 的三种结局。保留三分而不是压成布尔:\n * 「没有这条待决」与「Host 拒收了答案」必须让客户端分得清,否则手机上\n * 任何拒绝都显示成 question not pending。\n */\nexport type PendingResponseReason = 'not-pending' | 'bad-response' | 'transport'\n\nexport function pendingResponseErrorCode(reason: PendingResponseReason): WireErrorCode {\n switch (reason) {\n case 'not-pending': return 'E_NOT_FOUND'\n // Host 拒收了答案批次(形状/标签不匹配)——客户端载荷问题,不是待决消失。\n case 'bad-response': return 'E_PROTOCOL'\n case 'transport': return 'E_INTERNAL'\n }\n}\n\n/** 与 pendingResponseErrorCode 配套的可读信息,同一处维护。 */\nexport function pendingResponseMessage(\n kind: 'approval' | 'question',\n reason: PendingResponseReason,\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","/**\n * 连接层常量与载荷清洗。\n *\n * 本 module 的职责已经收窄:scope 表随 wire 注册表(每帧一行)迁到\n * wire-registry,错误码映射随错误词表迁到 wire-errors,请求形状校验随行内\n * validate 迁到各特性模块。剩下的都是与帧类型无关的东西——资源上限、\n * 清洗函数、envelope 形状守卫、下行广播权限。\n */\n\nimport 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\n/**\n * clientSendId / clientRequestId 的形态:13 位纪元前缀 + UUID。\n * wire 层据此校验载荷,journal 侧据此守卫(见 dispatch-journal.ts)。\n */\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\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 the registry lookup'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 row\n * validates its own payload shape (see the per-row `validate` in\n * wire-registry.ts).\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\n/**\n * 下行广播与重放授权。未知帧类型 fail-closed:不下发。\n *\n * `s2c.session.tail` 与 `s2c.history.page` 是 PROTOCOL.md 下行权限表里的类型,\n * 但由连接点对点直推(不经 record()/重放环)。条目保留:将来任何把它们送进\n * ring 的路径都会自动受到这里的 gate 约束,而不是静默全量广播。\n */\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 's2c.schedule.changed': 'schedule.manage',\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","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 {\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 'schedule.manage',\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","/**\n * 交互特性的 wire 行:回答待决的 approval 与 question。\n *\n * 两帧共用 `interactions.respond`。失败的三种结局(没有这条待决 / Host 拒收\n * 答案 / 传输失败)由 wire-errors 的词表翻译成 wire 错误码与可读信息——此前\n * 这条映射住在 connection-policy,和 scope 表、常量混在一起。\n */\n\nimport {\n isOptionalField,\n isText,\n payloadObject,\n reject,\n type WireFrameRow,\n} from './wire-registry.ts'\nimport { pendingResponseErrorCode, pendingResponseMessage } from './wire-errors.ts'\n\nconst RESPOND: WireFrameRow['scopes'] = ['interactions.respond']\n\nexport const interactionRows: readonly WireFrameRow[] = [\n {\n type: 'c2s.approval.respond',\n stage: 'authenticated',\n scopes: RESPOND,\n doc: 'PROTOCOL.md c2s.approval.respond',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n if (!isText(p.requestId)) return reject('E_PROTOCOL', 'invalid requestId')\n if (\n !['allow', 'deny'].includes(p.decision as string) ||\n !isOptionalField(p, 'reason', (v) => isText(v, 65536, false))\n ) {\n return reject('E_PROTOCOL', 'invalid approval response')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const decision = payload.decision as 'allow' | 'deny'\n if (decision !== 'allow' && decision !== 'deny') {\n return ctx.fail('E_PROTOCOL', 'requestId and decision required')\n }\n // 可选的拒绝理由必须抵达 Host,模型据此理解工具调用为何被拒。\n const outcome = await ctx.bridge.respondApproval(\n payload.requestId as string,\n decision,\n typeof payload.reason === 'string' ? (payload.reason as string) : undefined,\n )\n if (!outcome.ok) {\n const reason = outcome.reason\n return ctx.fail(pendingResponseErrorCode(reason), pendingResponseMessage('approval', reason))\n }\n ctx.send('s2c.ack', {})\n },\n },\n {\n type: 'c2s.question.respond',\n stage: 'authenticated',\n scopes: RESPOND,\n doc: 'PROTOCOL.md c2s.question.respond',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n if (!isText(p.requestId)) return reject('E_PROTOCOL', 'invalid requestId')\n if (!Array.isArray(p.answers) || p.answers.length > 100) return reject('E_PROTOCOL', 'invalid answers')\n const ids = new Set<unknown>()\n for (const answer of p.answers as Array<Record<string, unknown>>) {\n if (\n !answer ||\n typeof answer !== 'object' ||\n Array.isArray(answer) ||\n !isText(answer.id) ||\n ids.has(answer.id) ||\n !Array.isArray(answer.selected) ||\n answer.selected.length > 100 ||\n !answer.selected.every((v: unknown) => isText(v, 4096)) ||\n (answer.custom !== undefined && !isText(answer.custom, 65536))\n ) {\n return reject('E_PROTOCOL', 'invalid answer')\n }\n ids.add(answer.id)\n }\n return checked\n },\n handle: async (ctx, payload) => {\n if (!Array.isArray(payload.answers)) return ctx.fail('E_PROTOCOL', 'requestId and answers required')\n const outcome = await ctx.bridge.respondQuestion(payload.requestId as string, payload.answers)\n if (!outcome.ok) {\n const reason = outcome.reason\n return ctx.fail(pendingResponseErrorCode(reason), pendingResponseMessage('question', reason))\n }\n ctx.send('s2c.ack', {})\n },\n },\n]\n","/**\n * 设备生命周期特性的 wire 行:自撤销(解绑)。\n *\n * 该帧不要求任何 scope:设备生命周期操作不能因为 scope 被收窄而无法解绑,\n * 否则它只会永远留在离线推送目标集合里(PROTOCOL.md c2s.device.revoke)。\n * widget 策略取 `handler`:小组件的拒必须是「小组件不得解绑设备」这个具体\n * 理由,通用只读门禁只会说 read-only。\n */\n\nimport {\n isOptionalField,\n isText,\n payloadObject,\n reject,\n type WireFrameRow,\n} from './wire-registry.ts'\n\nexport const deviceRows: readonly WireFrameRow[] = [\n {\n type: 'c2s.device.revoke',\n stage: 'authenticated',\n scopes: [],\n widgetPolicy: 'handler',\n doc: 'PROTOCOL.md c2s.device.revoke',\n validate: (payload) => {\n // 载荷可整体省略:省略与 `{}` 等价,deviceId 可选。\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n // 校验可选的 deviceId:类型/非空(旧 request-validation 的判定),通过后\n // 才进入 handler 的等值判断。\n if (!isOptionalField(checked.value, 'deviceId', (v) => isText(v))) {\n return reject('E_PROTOCOL', 'invalid deviceId')\n }\n if (checked.value.deviceId !== undefined && typeof checked.value.deviceId !== 'string') {\n return reject('E_PROTOCOL', 'deviceId must be a string')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const deviceId = ctx.deviceId\n if (deviceId === undefined) return ctx.fail('E_INTERNAL', 'device identity unavailable')\n if (typeof payload.deviceId === 'string' && payload.deviceId !== deviceId) {\n return ctx.fail('E_FORBIDDEN', 'deviceId does not match the authenticated device')\n }\n if (ctx.widgetClient) {\n return ctx.fail('E_FORBIDDEN', 'widget connection cannot revoke its device')\n }\n // 幂等:已撤销的记录仍然 ack {revoked:true}——设备无法区分首次撤销与\n // 重复撤销,两种情况都不能表现为错误。\n ctx.devices.revoke(deviceId, Date.now())\n ctx.markRevoked()\n // 摘除同设备的其它活跃连接是尽力而为:注册表墓碑已落盘,hook 失败\n // 不能吞掉这次 ack。\n try {\n await ctx.revokeSiblings(deviceId)\n } catch (error) {\n if (ctx.debug) ctx.log('device revoke hook failed: ' + String(error))\n }\n // ack 严格先于关闭,慢客户端才能在 4401 前看到解绑成功。\n ctx.send('s2c.ack', { revoked: true })\n ctx.close(4401, 'device revoked')\n },\n },\n]\n","import type { LiveActivityState } from './protocol.ts'\nimport { MAX_DEVICE_NAME_CHARS, sanitizeDeviceField } from './connection-policy.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 /** Name reported by the phone. Refreshed on every authenticated hello. */\n deviceName: string\n /** User-assigned name from the DSH settings page; survives app reconnects. */\n customName?: 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/** Name shown to the operator: a user label when present, otherwise the app-reported model name. */\nexport function deviceDisplayName(record: Pick<DeviceRecord, 'deviceName' | 'customName'>): string {\n return record.customName?.trim() ? record.customName : record.deviceName\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 ...(existing?.customName ? { customName: existing.customName } : {}),\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 /**\n * Set or clear the operator-facing device label. The phone-reported name is\n * intentionally left untouched so a reconnect cannot erase this value.\n * Returns the effective display name, or null when the device is not active.\n */\n async setCustomName(deviceId: string, customName: string | null): Promise<string | null> {\n const record = this.authorized(deviceId)\n if (!record) return null\n const normalized = customName === null ? '' : sanitizeDeviceField(customName, MAX_DEVICE_NAME_CHARS)\n if (normalized === (record.customName ?? '')) return deviceDisplayName(record)\n const previous = record.customName\n if (normalized === '') delete record.customName\n else record.customName = normalized\n try {\n await this.flush()\n } catch (error) {\n if (previous === undefined) delete record.customName\n else record.customName = previous\n throw error\n }\n return deviceDisplayName(record)\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 this.detachDuplicateToken('apns', normalized, deviceId)\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 // Match c2s.push.register: hex tokens are stored lowercased, so an\n // uppercase re-send is the same registration, not a rotation.\n const normalized = token.toLowerCase()\n const previous = record.widgetApns\n if (previous?.token === normalized && previous.environment === environment &&\n now - previous.updatedAt < 60 * 60 * 1000) return\n this.detachDuplicateToken('widgetApns', normalized, deviceId)\n record.widgetApns = { token: normalized, 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 /**\n * One physical device owns one APNs token, but a re-pair or a botched unbind\n * can leave the same token attached to a second deviceId. Registering it\n * under `keepDeviceId` detaches it from every other record — only that one\n * token field, never the other record's pairing key or scopes. No flush of\n * its own: the caller batches it with the write that follows, so a single\n * registry write covers both changes.\n */\n private detachDuplicateToken(\n field: 'apns' | 'widgetApns',\n token: string,\n keepDeviceId: string,\n ): void {\n for (const record of this.devices.values()) {\n if (record.deviceId === keepDeviceId) continue\n if (field === 'apns') {\n if (record.apns?.token === token) delete record.apns\n } else if (record.widgetApns?.token === token) {\n delete record.widgetApns\n }\n }\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","/**\n * 离线推送特性的 wire 行:APNs token 注册(手机与小组件两份)与 Live Activity\n * 注册。\n *\n * 三处需要特别注意的次序,迁移前一模一样保留:\n * 1. 零配置注册(enrollKey)必须早于 push 能力门——首次注册恰恰发生在推送尚未\n * 就绪时,而钥匙本身会把中继模式打开;\n * 2. token 写入必须早于就绪门——推送还在引导中或中继临时不可用时,token 已落盘,\n * 恢复后无需重新注册;\n * 3. 任何 await 之后都要重新读取设备记录:权限可能在等待期间被改窄。\n */\n\nimport type { ApnsEnvironment } from './token.ts'\nimport { isValidApnsToken } from './token.ts'\nimport {\n isOptionalField,\n isText,\n payloadObject,\n reject,\n type WireFrameRow,\n} from './wire-registry.ts'\n\n/** Live Activity 需要的三个 scope:通知注册 + 会话读取 + 交互应答。 */\nconst LIVE_ACTIVITY_SCOPES: WireFrameRow['scopes'] = [\n 'notifications.register',\n 'sessions.read',\n 'interactions.respond',\n]\n\n/** 小组件总览需要的三个 scope:与 Live Activity 同组(PROTOCOL.md 下行权限一节)。 */\nconst WIDGET_PUSH_SCOPES: WireFrameRow['scopes'] = [\n 'notifications.register',\n 'sessions.read',\n 'interactions.respond',\n]\n\n/** enrollKey 的清洗:只保留可打印 ASCII,截到 128(与迁移前逐字一致)。 */\nfunction cleanEnrollKey(value: unknown): string {\n return typeof value === 'string' ? value.trim().replace(/[^\\x20-\\x7e]/g, '').slice(0, 128) : ''\n}\n\nexport const pushRows: readonly WireFrameRow[] = [\n {\n type: 'c2s.push.register',\n stage: 'authenticated',\n scopes: ['notifications.register'],\n // 注意:不在此声明 capability 门。零配置注册(enrollKey)必须先于 push\n // 能力门执行——首次注册恰恰发生在推送尚未就绪时。门由 handler 在注册之后\n // 就地检查,与迁移前的次序一致。\n doc: 'PROTOCOL.md c2s.push.register',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n // token 的形状检查原在 handler 内(G3);此处并入校验,接受集不变。\n const token = typeof p.deviceToken === 'string' ? (p.deviceToken as string).trim() : ''\n if (!isValidApnsToken(token)) return reject('E_PROTOCOL', 'hex deviceToken (32-512 chars) required')\n if (p.environment !== undefined && p.environment !== 'production' && p.environment !== 'development') {\n return reject('E_PROTOCOL', 'invalid APNs environment')\n }\n if (!isOptionalField(p, 'enrollKey', (v) => isText(v, 128))) return reject('E_PROTOCOL', 'invalid enrollKey')\n if (\n p.categories !== undefined &&\n (typeof p.categories !== 'object' || p.categories === null || Array.isArray(p.categories) ||\n Object.values(p.categories as Record<string, unknown>).some((v) => typeof v !== 'boolean'))\n ) {\n return reject('E_PROTOCOL', 'invalid categories')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const deviceId = ctx.deviceId\n if (deviceId === undefined) return ctx.fail('E_INTERNAL', 'device identity unavailable')\n const token = String(payload.deviceToken).trim()\n const environment: ApnsEnvironment = payload.environment === 'production' ? 'production' : 'development'\n const categories = typeof payload.categories === 'object' && payload.categories !== null\n ? (payload.categories as Record<string, boolean>)\n : undefined\n // 零配置注册先于能力门(见文件头说明 1)。\n if (typeof payload.enrollKey === 'string') {\n const enrollKey = cleanEnrollKey(payload.enrollKey)\n if (enrollKey.length >= 8 && enrollKey.length <= 128) await ctx.enrollPushKey(enrollKey)\n }\n // token 先落盘,再评估就绪(见文件头说明 2);await 之后重新读取权限。\n const record = ctx.devices.authorized(deviceId)\n if (!record?.scopes?.includes('notifications.register')) {\n return ctx.fail('E_FORBIDDEN', 'device authorization changed')\n }\n ctx.devices.setPushToken(deviceId, token, environment, categories, Date.now())\n if (ctx.bridge.capabilities.push !== true) {\n if (ctx.debug) ctx.log('push register held: bridge not ready')\n return ctx.fail('E_UNSUPPORTED', 'push is not configured on this bridge')\n }\n if (ctx.debug) ctx.log('push token registered env=' + environment)\n // enabled 让 App 立即翻转本地能力位,不必等下一次握手。\n ctx.send('s2c.ack', { enabled: true })\n },\n },\n {\n type: 'c2s.widget.push.register',\n stage: 'authenticated',\n scopes: WIDGET_PUSH_SCOPES,\n widgetPolicy: 'allowed',\n // 同 c2s.push.register:能力门在 handler 内、注册之后检查。\n doc: 'PROTOCOL.md c2s.widget.push.register',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n const token = typeof p.deviceToken === 'string' ? (p.deviceToken as string).trim() : ''\n if (!isValidApnsToken(token)) return reject('E_PROTOCOL', 'hex deviceToken (32-512 chars) required')\n if (p.environment !== undefined && p.environment !== 'production' && p.environment !== 'development') {\n return reject('E_PROTOCOL', 'invalid APNs environment')\n }\n if (!isOptionalField(p, 'enrollKey', (v) => isText(v, 128))) return reject('E_PROTOCOL', 'invalid enrollKey')\n return checked\n },\n handle: async (ctx, payload) => {\n const deviceId = ctx.deviceId\n if (deviceId === undefined) return ctx.fail('E_INTERNAL', 'device identity unavailable')\n const token = String(payload.deviceToken).trim()\n const environment: ApnsEnvironment = payload.environment === 'production' ? 'production' : 'development'\n if (typeof payload.enrollKey === 'string') {\n const enrollKey = cleanEnrollKey(payload.enrollKey)\n if (enrollKey.length >= 8 && enrollKey.length <= 128) await ctx.enrollPushKey(enrollKey)\n }\n const record = ctx.devices.authorized(deviceId)\n if (\n !record?.scopes?.includes('notifications.register') ||\n !record.scopes.includes('sessions.read') ||\n !record.scopes.includes('interactions.respond')\n ) {\n return ctx.fail('E_FORBIDDEN', 'device authorization changed')\n }\n ctx.devices.setWidgetPushToken(deviceId, token, environment, Date.now())\n if (ctx.bridge.capabilities.push !== true) {\n if (ctx.debug) ctx.log('push register held: bridge not ready')\n return ctx.fail('E_UNSUPPORTED', 'push is not configured on this bridge')\n }\n ctx.send('s2c.ack', { enabled: true })\n },\n },\n {\n type: 'c2s.liveActivity.unregister',\n stage: 'authenticated',\n scopes: ['notifications.register'],\n doc: 'PROTOCOL.md c2s.liveActivity.unregister',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (!isText(checked.value.activityId, 128)) return reject('E_PROTOCOL', 'invalid activityId')\n return checked\n },\n handle: (ctx, payload) => {\n const activityId = payload.activityId as string\n // 注销正在注册中的活动:抬高端次使在途的注册失效。\n if (ctx.pendingLiveActivityId === activityId) {\n ctx.nextLiveActivityGeneration()\n ctx.setPendingLiveActivityId(undefined)\n }\n ctx.devices.clearLiveActivity(ctx.deviceId!, activityId)\n ctx.send('s2c.ack', {})\n },\n },\n {\n type: 'c2s.liveActivity.register',\n stage: 'authenticated',\n scopes: LIVE_ACTIVITY_SCOPES,\n doc: 'PROTOCOL.md c2s.liveActivity.register',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n if (!isText(p.activityId, 128)) return reject('E_PROTOCOL', 'invalid activityId')\n if (\n !isText(p.sessionId) ||\n typeof p.deviceToken !== 'string' ||\n !/^[0-9a-fA-F]{32,512}$/.test(p.deviceToken) ||\n !['development', 'production'].includes(p.environment as string) ||\n !isOptionalField(p, 'enrollKey', (v) => isText(v, 128))\n ) {\n return reject('E_PROTOCOL', 'invalid live activity registration')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const deviceId = ctx.deviceId\n if (deviceId === undefined) return ctx.fail('E_INTERNAL', 'device identity unavailable')\n const activityId = payload.activityId as string\n const generation = ctx.nextLiveActivityGeneration()\n ctx.setPendingLiveActivityId(activityId)\n // 注意:此处 enrollKey 原样透传,未做 push.register 那样的可打印 ASCII\n // 清洗。两条路径的清洗规则不一致属于已知不对称,本次按原行为保留,\n // 是否统一留待专门决策(不在本轮 wire 对等清单内)。\n if (typeof payload.enrollKey === 'string' && payload.enrollKey) {\n await ctx.enrollPushKey(payload.enrollKey as string)\n }\n if (generation !== ctx.liveActivityGeneration) {\n return ctx.fail('E_BUSY', 'live activity registration superseded')\n }\n // await 之后重新校验:权限可能已被改窄,连接可能已关闭。\n const record = ctx.devices.authorized(deviceId)\n if (\n !record ||\n !LIVE_ACTIVITY_SCOPES.every((scope) => record.scopes?.includes(scope))\n ) {\n return ctx.fail('E_FORBIDDEN', 'live activity permissions required')\n }\n if (!ctx.bridge.listSessions().some((row) => row.id === payload.sessionId)) {\n return ctx.fail('E_NOT_FOUND', 'session not found')\n }\n const previous = record.liveActivity\n if (previous?.activityId === activityId && previous.sessionId !== payload.sessionId) {\n return ctx.fail('E_PROTOCOL', 'activity is bound to another session')\n }\n ctx.devices.setLiveActivity(record.deviceId, {\n activityId,\n sessionId: payload.sessionId as string,\n token: String(payload.deviceToken).toLowerCase(),\n environment: payload.environment as ApnsEnvironment,\n updatedAt: Date.now(),\n expiresAt: Date.now() + 8 * 60 * 60 * 1000,\n })\n ctx.bridge.refreshLiveActivities()\n ctx.send('s2c.ack', { enabled: ctx.bridge.capabilities.push })\n },\n },\n]\n","/**\n * 定时任务特性的 wire 行:列表、历史、创建、修改、删除。\n *\n * scope 取 `schedule.manage` + `sessions.read`:PROTOCOL.md scope 映射表写明\n * 「`schedule.manage` 定时任务/提醒的列表、历史、创建、修改和删除;同时需要\n * `sessions.read` 才能读取任务内容」。迁移前这条组合一半住在 requiredScope、\n * 一半住在 connection.ts 调用点的一行补充规则里(334-336),现在是一行声明。\n *\n * 五个帧共享一个能力位 `schedules`;该位现在只要求 Schedule 服务存在\n * (见 host-capabilities.ts 的 G4 修正)。\n */\n\nimport { validSendId } from './connection-policy.ts'\nimport {\n accept,\n isInteger,\n isOptionalField,\n isText,\n payloadObject,\n reject,\n type WireFrameRow,\n} from './wire-registry.ts'\n\n/** PROTOCOL.md scope 映射表:schedule.manage 需搭配 sessions.read。 */\nconst SCHEDULE_SCOPES: WireFrameRow['scopes'] = ['schedule.manage', 'sessions.read']\n\nexport const scheduleRows: readonly WireFrameRow[] = [\n {\n type: 'c2s.schedule.list',\n stage: 'authenticated',\n scopes: SCHEDULE_SCOPES,\n capability: 'schedules',\n doc: 'PROTOCOL.md c2s.schedule.list',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (!isText(checked.value.sessionId)) return reject('E_PROTOCOL', 'invalid sessionId')\n return checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.listSchedules(payload.sessionId as string)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.schedule.snapshot', { sessionId: payload.sessionId, tasks: result.value })\n },\n },\n {\n type: 'c2s.schedule.history',\n stage: 'authenticated',\n scopes: SCHEDULE_SCOPES,\n capability: 'schedules',\n doc: 'PROTOCOL.md c2s.schedule.history',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (\n !isText(checked.value.sessionId) ||\n !isText(checked.value.id) ||\n !isInteger(checked.value.limit, 1, 100) ||\n !isOptionalField(checked.value, 'before', (v) => isText(v))\n ) {\n return reject('E_PROTOCOL', 'invalid schedule history')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.scheduleHistory(\n payload.sessionId as string,\n payload.id as string,\n payload.limit as number,\n payload.before as string | undefined,\n )\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.schedule.history', { sessionId: payload.sessionId, history: result.value })\n },\n },\n {\n type: 'c2s.schedule.create',\n stage: 'authenticated',\n scopes: SCHEDULE_SCOPES,\n capability: 'schedules',\n doc: 'PROTOCOL.md c2s.schedule.create',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n if (\n !validSendId(p.clientRequestId) ||\n !isText(p.sessionId) ||\n !isText(p.title, 120) ||\n !isText(p.prompt, 256 * 1024)\n ) {\n return reject('E_PROTOCOL', 'invalid schedule create fields')\n }\n // 恰好一个时机选择器:after_seconds / at / every_seconds / daily / weekly / cron。\n const selectors = ['after_seconds', 'at', 'every_seconds', 'daily', 'weekly', 'cron']\n .filter((key) => p[key] !== undefined)\n if (selectors.length !== 1) return reject('E_PROTOCOL', 'schedule requires exactly one selector')\n if (p.after_seconds !== undefined && !isInteger(p.after_seconds, 1, Number.MAX_SAFE_INTEGER)) {\n return reject('E_PROTOCOL', 'invalid after_seconds')\n }\n if (p.every_seconds !== undefined && !isInteger(p.every_seconds, 60, Number.MAX_SAFE_INTEGER)) {\n return reject('E_PROTOCOL', 'invalid every_seconds')\n }\n if (\n p.at !== undefined &&\n typeof p.at !== 'string' &&\n (typeof p.at !== 'object' || p.at === null || Array.isArray(p.at))\n ) {\n return reject('E_PROTOCOL', 'invalid at selector')\n }\n return accept(p)\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.createSchedule(\n ctx.deviceId!,\n payload as Record<string, unknown> & { sessionId: string; clientRequestId: string; title: string; prompt: string },\n )\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.schedule.updated', {\n clientRequestId: payload.clientRequestId,\n sessionId: payload.sessionId,\n task: result.value,\n ...(result.replayed ? { replayed: true } : {}),\n })\n },\n },\n {\n type: 'c2s.schedule.update',\n stage: 'authenticated',\n scopes: SCHEDULE_SCOPES,\n capability: 'schedules',\n doc: 'PROTOCOL.md c2s.schedule.update',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const p = checked.value\n if (\n !validSendId(p.clientRequestId) ||\n !isText(p.sessionId) ||\n !isText(p.id) ||\n p.expected === undefined ||\n typeof p.expected !== 'object' ||\n Array.isArray(p.expected)\n ) {\n return reject('E_PROTOCOL', 'invalid schedule update fields')\n }\n if (\n !isOptionalField(p, 'title', (v) => isText(v, 120)) ||\n !isOptionalField(p, 'prompt', (v) => isText(v, 256 * 1024))\n ) {\n return reject('E_PROTOCOL', 'invalid schedule update content')\n }\n if (\n p.change !== undefined &&\n (typeof p.change !== 'object' || p.change === null || Array.isArray(p.change))\n ) {\n return reject('E_PROTOCOL', 'invalid schedule timing change')\n }\n return accept(p)\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.updateSchedule(\n ctx.deviceId!,\n payload as Record<string, unknown> & { sessionId: string; id: string; clientRequestId: string; expected: unknown },\n )\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.schedule.updated', {\n clientRequestId: payload.clientRequestId,\n sessionId: payload.sessionId,\n task: result.value,\n ...(result.replayed ? { replayed: true } : {}),\n })\n },\n },\n {\n type: 'c2s.schedule.delete',\n stage: 'authenticated',\n scopes: SCHEDULE_SCOPES,\n capability: 'schedules',\n doc: 'PROTOCOL.md c2s.schedule.delete',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (\n !validSendId(checked.value.clientRequestId) ||\n !isText(checked.value.sessionId) ||\n !isText(checked.value.id)\n ) {\n return reject('E_PROTOCOL', 'invalid schedule delete fields')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.deleteSchedule(ctx.deviceId!, {\n sessionId: payload.sessionId as string,\n id: payload.id as string,\n clientRequestId: payload.clientRequestId as string,\n })\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.schedule.updated', {\n clientRequestId: payload.clientRequestId,\n sessionId: payload.sessionId,\n deleted: true,\n ...(result.replayed ? { replayed: true } : {}),\n })\n },\n },\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; message?: { content?: unknown } } | undefined;\n const ok = data?.error === undefined;\n const result = limitMessageProjection({\n seq: event.seq, role: 'tool', ts: tsOf(event),\n tool: { name: 'result', state: ok ? 'ok' : 'error', summary: ok ? summarizeResult(data?.message?.content) : '失败' },\n ...(ok ? attachmentProjection(data?.message) : {}),\n });\n return {\n kind: 'tool.end',\n data: {\n seq: result.seq, role: result.role, ts: result.ts, ok,\n summary: result.tool?.summary,\n ...(result.attachments ? { attachments: result.attachments } : {}),\n ...(data?.callId ? { callId: String(data.callId) } : {}),\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 // A tool result may carry images as well as text — browser and\n // computer-use backends return screenshots this way. `summarizeResult`\n // covers only the textual part, so project the binary blocks as\n // attachments too; otherwise the phone renders a text-only summary and\n // the image is silently dropped. The durable attachmentId is what lets\n // the client read the bytes back through c2s.session.attachment.\n const attachments = failed ? {} : attachmentProjection(data?.message);\n if (target?.tool) {\n target.tool = { ...target.tool, state: failed ? 'error' : 'ok', summary };\n if (attachments.attachments) Object.assign(target, attachments);\n } else {\n messages.push({\n ...base,\n role: 'tool',\n tool: { name: 'result', state: failed ? 'error' : 'ok', summary },\n ...attachments,\n });\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\n// ---------- 历史分页窗口 ----------\n\n/** 参与窗口计算的原始事件:可投影的最小形状。 */\nexport interface HistoryWindowEvent {\n type: string\n seq: number\n time?: number\n data?: unknown\n}\n\nexport interface HistoryWindowOptions {\n /** 只取 seq 严格小于该值的事件(翻页边界)。 */\n beforeSeq?: number\n /** 目标消息条数;小于 1 一律按 1 处理。 */\n limit: number\n}\n\nexport interface HistoryWindow {\n /** 窗口内的原始事件,旧→新,含投影为空者。 */\n events: Array<{ event: HistoryWindowEvent }>\n /** 起点之前是否还有更多事件(客户端可继续翻页)。 */\n hasMore: boolean\n}\n\n/** 一页能要多少条消息:wire 校验与 bridge clamp 共用这一条规则。 */\nexport const MIN_HISTORY_PAGE_MESSAGES = 1\nexport const MAX_HISTORY_PAGE_MESSAGES = 500\n/** 打开会话时的默认尾部条数。 */\nexport const DEFAULT_HISTORY_PAGE_MESSAGES = 100\n/** 打开会话时至少要拉多少条:少于这个数客户端一屏都铺不满。 */\nexport const MIN_TAIL_MESSAGES = 10\n\n/** 把 wire 声明的页大小收敛到合法区间。 */\nexport function normalizePageLimit(value: unknown): number {\n return typeof value === 'number' && Number.isInteger(value)\n ? Math.max(MIN_HISTORY_PAGE_MESSAGES, Math.min(MAX_HISTORY_PAGE_MESSAGES, value))\n : DEFAULT_HISTORY_PAGE_MESSAGES\n}\n\n/**\n * 会话历史的分页窗口:从候选事件里取出「投影后末尾 `limit` 条消息」所在的那\n * 一段原始事件。\n *\n * 迁移前这段循环住在 host adapter(dsh-api-proxy.ts 的 sessions.history)里,\n * 按块累积、每轮对累计窗口重跑一次投影(稀疏投影时最坏 O(N²/L))。它与自己\n * 依赖的投影规则分居两地,而 `projectHistory` 是顺序依赖的(tool/call 与\n * tool/result 靠 toolByCall 配对),所以这里只做一次前向投影,再按消息归属\n * 反推窗口起点。\n *\n * 注意:窗口**不是**最小的那个后缀。现算法按 `limit` 的整数倍从末端取块,\n * 因此窗口可能含若干投影为空的前导事件;本实现按消息归属取起点,同样保留\n * 这些前导事件之前的所有内容——两者的差异由 tests/history-window-parity.test.ts\n * 逐条钉住(75 例确定性语料,含切断 call/result 配对与重复 seq 的形状)。\n */\nexport function historyWindow(\n source: readonly unknown[],\n options: HistoryWindowOptions,\n): HistoryWindow {\n // 页大小走同一条规则:非有限值回落默认,其余收敛到 [1, 500]。\n const limit = normalizePageLimit(options.limit)\n const beforeSeq = options.beforeSeq\n const candidates: HistoryWindowEvent[] = []\n for (const raw of source) {\n if (typeof raw !== 'object' || raw === null) continue\n const event = raw as HistoryWindowEvent\n if (typeof event.type !== 'string' || typeof event.seq !== 'number') continue\n if (beforeSeq !== undefined && !(event.seq < beforeSeq)) continue\n candidates.push(event)\n }\n const entries = candidates.map((event) => ({ event }))\n if (entries.length === 0) return { events: [], hasMore: false }\n\n const projected = projectHistory(entries)\n if (projected.length <= limit) return { events: entries, hasMore: false }\n\n // 每条消息对应的原始下标:投影按 seq 去重(后者胜出),因此取该 seq 最后一次\n // 出现的下标。窗口必须包含这些下标,否则消息会被裁掉。\n const lastIndexBySeq = new Map<number, number>()\n for (let index = 0; index < candidates.length; index += 1) {\n lastIndexBySeq.set(candidates[index]!.seq, index)\n }\n const keep = projected.slice(projected.length - limit)\n let front = candidates.length\n for (const message of keep) {\n const index = lastIndexBySeq.get(message.seq)\n if (index !== undefined && index < front) front = index\n }\n // hasMore 只表示「窗口之前还有能产出消息的事件」:旧实现按 limit 整数倍取块,\n // 窗口之前只剩投影为空的前导事件时也报 true,客户端会多发一次翻页才拿到空页。\n // 这里对前缀做一次投影来定性,代价 O(前 `front` 个事件)。\n const older = front > 0 ? projectHistory(entries.slice(0, front)) : []\n return { events: entries.slice(front), hasMore: older.length > 0 }\n}\n","/**\n * 会话特性的 wire 行:列表/归档、打开与关闭、创建/分支/重命名/取消、历史与\n * 附件、模型目录与切换、prompt 投递。\n *\n * handler 体从 connection.ts 的 switch 原样迁来,`this.` 换成 `ctx.`;\n * 该校验的判定与顺序和迁移前一致——先是原 request-validation 的形状检查,\n * 后是原 case 体内的形状检查——因此同一载荷在新旧路径上得到同一个错误码与\n * 同一条信息(tests/wire-parity.test.ts 在迁移期逐条对等,之后由\n * tests/wire-rows.test.ts 固定为显式期望)。\n */\n\nimport { validSendId } from './connection-policy.ts'\nimport { normalizePageLimit } from './host-event-projection.ts'\nimport {\n IMAGE_MEDIA_TYPES,\n MAX_BASE64_CHARS_PER_IMAGE,\n MAX_DOCUMENT_MEDIA_TYPE_CHARS,\n MAX_DOCUMENT_NAME_CHARS,\n MAX_DOCUMENT_TEXT_CHARS,\n MAX_PROMPT_DOCUMENTS,\n MAX_PROMPT_IMAGES,\n MAX_PROMPT_TEXT_CHARS,\n sanitizeDocumentField,\n sanitizeImageName,\n} from './connection-policy.ts'\nimport {\n accept,\n isInteger,\n isOptionalField,\n isText,\n payloadObject,\n reject,\n type CheckedPayload,\n type WireFrameRow,\n} from './wire-registry.ts'\n\n/** 会话读取域的帧共同要求 sessions.read(PROTOCOL.md scope 映射表)。 */\nconst READ: WireFrameRow['scopes'] = ['sessions.read']\nconst MANAGE: WireFrameRow['scopes'] = ['sessions.manage']\n\n/** 原 request-validation 的 sessionId 检查:所有 c2s.session.* 共用的第一道。 */\nfunction requireSessionId(payload: Record<string, unknown>): CheckedPayload | undefined {\n if (!isText(payload.sessionId)) return reject('E_PROTOCOL', 'invalid sessionId')\n return undefined\n}\n\nexport const sessionRows: readonly WireFrameRow[] = [\n {\n type: 'c2s.ping',\n stage: 'pre-auth',\n scopes: [],\n widgetPolicy: 'allowed',\n doc: 'PROTOCOL.md 连接与鉴权',\n handle: (ctx) => {\n ctx.send('s2c.pong', { serverTime: Date.now() })\n },\n },\n {\n // 握手帧。机制(验签、scope 载入、welcome、续传)仍在连接里:这是认证\n // 状态机的地盘,行只登记「它存在、无需 scope、认证前可到」。\n type: 'c2s.auth.prove',\n stage: 'pre-auth',\n scopes: [],\n widgetPolicy: 'allowed',\n doc: 'PROTOCOL.md 连接与鉴权',\n handle: (ctx) => ctx.prove(),\n },\n {\n type: 'c2s.sessions.list',\n stage: 'authenticated',\n scopes: READ,\n widgetPolicy: 'allowed',\n doc: 'PROTOCOL.md c2s.sessions.list',\n validate: (payload) => payloadObject(payload),\n handle: (ctx) => {\n ctx.send('s2c.sessions.snapshot', { full: true, sessions: ctx.bridge.listSessions() })\n },\n },\n {\n // 与 list 同语义的无参帧:载荷可省略或为 null(G2)。\n type: 'c2s.sessions.archived',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.sessions.archived',\n validate: (payload) => payloadObject(payload),\n handle: (ctx) => {\n ctx.send('s2c.sessions.archived.snapshot', { sessions: ctx.bridge.listArchivedSessions() })\n },\n },\n {\n type: 'c2s.pending.list',\n stage: 'authenticated',\n scopes: ['interactions.respond'],\n widgetPolicy: 'allowed',\n capability: 'pendingSnapshot',\n doc: 'PROTOCOL.md c2s.pending.list',\n validate: (payload) => payloadObject(payload),\n handle: (ctx) => {\n ctx.send('s2c.pending.snapshot', ctx.bridge.pendingSnapshot())\n },\n },\n {\n type: 'c2s.workspaces.list',\n stage: 'authenticated',\n scopes: READ,\n capability: 'projectSelection',\n doc: 'PROTOCOL.md c2s.workspaces.list',\n validate: (payload) => payloadObject(payload),\n handle: async (ctx) => {\n const result = await ctx.bridge.listWorkspaces()\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.workspaces.snapshot', { workspaces: result.value })\n },\n },\n {\n type: 'c2s.workspace.create',\n stage: 'authenticated',\n scopes: MANAGE,\n capability: 'projectSelection',\n doc: 'PROTOCOL.md c2s.workspace.create',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (!isText(checked.value.path, 32768)) return reject('E_PROTOCOL', 'invalid path')\n return checked\n },\n handle: async (ctx, payload) => {\n const path = String(payload.path).trim()\n // 空路径是载荷问题,先于能力检查(与迁移前次序一致)。\n if (!path) return ctx.fail('E_PROTOCOL', 'non-empty path required')\n const result = await ctx.bridge.createWorkspace(path)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.workspace.created', result.value)\n },\n },\n {\n type: 'c2s.directory.list',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.directory.list',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (!isOptionalField(checked.value, 'path', (v) => isText(v, 32768, false))) {\n return reject('E_PROTOCOL', 'invalid path')\n }\n if (checked.value.path !== undefined && typeof checked.value.path !== 'string') {\n return reject('E_PROTOCOL', 'path must be a string')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.listDirectory(payload.path as string | undefined)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.directory.listing', result.value)\n },\n },\n {\n type: 'c2s.directory.pick',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.directory.pick',\n validate: (payload) => payloadObject(payload),\n handle: async (ctx) => {\n const result = await ctx.bridge.pickDirectory()\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.directory.picked', { path: result.value })\n },\n },\n {\n type: 'c2s.session.open',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.session.open',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (!isOptionalField(checked.value, 'tailCount', (v) => isInteger(v, 1, 10000))) {\n return reject('E_PROTOCOL', 'invalid tailCount')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const sessionId = payload.sessionId as string\n const buffered = ctx.bufferOpenEvents(sessionId)\n const ok = await ctx.bridge.openSession(ctx, sessionId, (payload.tailCount as number | undefined) ?? 100)\n if (!ok) {\n // 打开失败:仅当缓冲仍属于本次尝试时才移除,避免清掉并发打开的新缓冲。\n ctx.discardOpenBuffer(sessionId, buffered)\n return ctx.fail('E_NOT_FOUND', 'session history unavailable')\n }\n // 并发的 close 或替换打开会使本次尝试失效:它的 tail 已经发出,但不应\n // 在用户离开页面后重新激活实时投递。\n if (!ctx.flushOpenBuffer(sessionId, buffered)) return\n },\n },\n {\n type: 'c2s.session.close',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.session.close',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n return requireSessionId(checked.value) ?? checked\n },\n handle: (ctx, payload) => {\n ctx.closeOpenSession(payload.sessionId as string)\n ctx.send('s2c.ack', {})\n },\n },\n {\n type: 'c2s.session.create',\n stage: 'authenticated',\n scopes: MANAGE,\n doc: 'PROTOCOL.md c2s.session.create',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n if (\n !isOptionalField(checked.value, 'workspaceId', (v) => isText(v)) ||\n !isOptionalField(checked.value, 'cwd', (v) => isText(v, 32768)) ||\n (checked.value.workspaceId !== undefined && checked.value.cwd !== undefined)\n ) {\n return reject('E_PROTOCOL', 'invalid workspace selection')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const workspaceId = typeof payload.workspaceId === 'string' ? String(payload.workspaceId).trim() : ''\n const cwd = typeof payload.cwd === 'string' ? String(payload.cwd).trim() : ''\n if (workspaceId && cwd) return ctx.fail('E_PROTOCOL', 'workspaceId and cwd are mutually exclusive')\n const newId = await ctx.bridge.createSession({\n ...(workspaceId ? { workspaceId } : {}),\n ...(cwd ? { cwd } : {}),\n })\n if (!newId) return ctx.fail('E_INTERNAL', 'session create failed')\n ctx.send('s2c.ack', { sessionId: newId })\n },\n },\n {\n // PROTOCOL.md:分支会话要求 sessions.read 与 sessions.manage 两个 scope\n // (迁移前只校验了 sessions.manage,调用点的补充规则漏掉了本帧,见 G1)。\n type: 'c2s.session.fork',\n stage: 'authenticated',\n scopes: [...MANAGE, ...READ],\n capability: 'sessionFork',\n doc: 'PROTOCOL.md Session 分支扩展',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (!validSendId(checked.value.clientRequestId) || !isOptionalField(checked.value, 'atSeq', (v) => isInteger(v, 0, Number.MAX_SAFE_INTEGER))) {\n return reject('E_PROTOCOL', 'invalid session fork fields')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n const deviceId = ctx.deviceId!\n const result = await ctx.bridge.forkSession(deviceId, {\n sessionId: payload.sessionId as string,\n clientRequestId: payload.clientRequestId as string,\n ...(payload.atSeq !== undefined ? { atSeq: payload.atSeq as number } : {}),\n })\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.session.forked', {\n clientRequestId: payload.clientRequestId,\n sourceSessionId: payload.sessionId,\n sessionId: result.value.sessionId,\n ...(payload.atSeq !== undefined ? { atSeq: payload.atSeq } : {}),\n ...(result.replayed ? { replayed: true } : {}),\n })\n },\n },\n {\n type: 'c2s.session.rename',\n stage: 'authenticated',\n scopes: MANAGE,\n capability: 'sessionManagement',\n doc: 'PROTOCOL.md c2s.session.rename',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (!isText(checked.value.title, 4096)) return reject('E_PROTOCOL', 'invalid title')\n return checked\n },\n handle: async (ctx, payload) => {\n const title = String(payload.title).trim()\n if (title.length === 0) return ctx.fail('E_PROTOCOL', 'sessionId and non-empty title required')\n const result = await ctx.bridge.renameSession(payload.sessionId as string, title)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.session.renamed', { sessionId: payload.sessionId, title: result.value })\n },\n },\n {\n type: 'c2s.session.archive',\n stage: 'authenticated',\n scopes: MANAGE,\n capability: 'sessionManagement',\n doc: 'PROTOCOL.md c2s.session.archive',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n return requireSessionId(checked.value) ?? checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.archiveSession(payload.sessionId as string)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.session.archived', { sessionId: payload.sessionId })\n },\n },\n {\n type: 'c2s.session.unarchive',\n stage: 'authenticated',\n scopes: MANAGE,\n capability: 'sessionRestore',\n doc: 'PROTOCOL.md c2s.session.unarchive',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n return requireSessionId(checked.value) ?? checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.unarchiveSession(payload.sessionId as string)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.session.unarchived', { sessionId: payload.sessionId })\n },\n },\n {\n type: 'c2s.session.cancel',\n stage: 'authenticated',\n scopes: MANAGE,\n doc: 'PROTOCOL.md c2s.session.cancel',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n return requireSessionId(checked.value) ?? checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.cancelSession(payload.sessionId as string)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.ack', { sessionId: payload.sessionId })\n },\n },\n {\n type: 'c2s.session.history',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.session.history',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (\n !isInteger(checked.value.beforeSeq, 0, Number.MAX_SAFE_INTEGER) ||\n !isOptionalField(checked.value, 'limit', (v) => isInteger(v, 1, 500))\n ) {\n return reject('E_PROTOCOL', 'invalid history range')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n if (typeof payload.beforeSeq !== 'number') {\n return ctx.fail('E_PROTOCOL', 'sessionId and beforeSeq required')\n }\n const page = await ctx.bridge.historyPage(\n payload.sessionId as string,\n payload.beforeSeq,\n normalizePageLimit(payload.limit),\n )\n if (!page) return ctx.fail('E_NOT_FOUND', 'history unavailable')\n ctx.send('s2c.history.page', page)\n },\n },\n {\n type: 'c2s.session.attachment',\n stage: 'authenticated',\n scopes: READ,\n doc: 'PROTOCOL.md c2s.session.attachment',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (!isText(checked.value.attachmentId)) return reject('E_PROTOCOL', 'invalid attachmentId')\n return checked\n },\n handle: async (ctx, payload) => {\n const attachmentId = payload.attachmentId as string\n if (attachmentId.length === 0) return ctx.fail('E_PROTOCOL', 'sessionId and attachmentId required')\n const image = await ctx.bridge.attachmentData(payload.sessionId as string, attachmentId)\n if (!image) return ctx.fail('E_NOT_FOUND', 'attachment unavailable')\n ctx.send('s2c.ack', image)\n },\n },\n {\n type: 'c2s.session.models',\n stage: 'authenticated',\n scopes: READ,\n capability: 'models',\n doc: 'PROTOCOL.md c2s.session.models',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n return requireSessionId(checked.value) ?? checked\n },\n handle: async (ctx, payload) => {\n const result = await ctx.bridge.sessionModels(payload.sessionId as string)\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.session.models', { sessionId: payload.sessionId, ...result.value })\n },\n },\n {\n type: 'c2s.session.selectModel',\n stage: 'authenticated',\n scopes: MANAGE,\n capability: 'models',\n doc: 'PROTOCOL.md c2s.session.selectModel',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (\n !isText(checked.value.provider, 256) ||\n !isText(checked.value.model, 1024) ||\n !isOptionalField(checked.value, 'reasoningEffort', (v) => isText(v, 128, false))\n ) {\n return reject('E_PROTOCOL', 'invalid model selection')\n }\n return checked\n },\n handle: async (ctx, payload) => {\n if (!String(payload.provider).trim() || !String(payload.model).trim()) {\n return ctx.fail('E_PROTOCOL', 'sessionId, provider and model required')\n }\n const result = await ctx.bridge.selectSessionModel(payload.sessionId as string, {\n provider: String(payload.provider).trim(),\n model: String(payload.model).trim(),\n ...(String(payload.reasoningEffort ?? '').trim()\n ? { reasoningEffort: String(payload.reasoningEffort).trim() }\n : {}),\n })\n if (!result.ok) return ctx.fail(result.code, result.message)\n ctx.send('s2c.session.modelSelected', { sessionId: payload.sessionId, selected: result.value })\n },\n },\n {\n // 投递回执查询:journal 语义,能力位恒真但仍绑定,缺位即说明 Bridge 被改动。\n type: 'c2s.session.delivery',\n stage: 'authenticated',\n scopes: ['prompt.send'],\n capability: 'promptDelivery',\n doc: 'PROTOCOL.md c2s.session.delivery',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n if (!validSendId(checked.value.clientSendId)) return reject('E_PROTOCOL', 'invalid clientSendId')\n return checked\n },\n handle: (ctx, payload) => {\n ctx.send('s2c.ack', ctx.bridge.promptDeliveries.lookup(\n ctx.deviceId!,\n payload.clientSendId as string,\n payload.sessionId as string,\n ))\n },\n },\n {\n type: 'c2s.session.sendPrompt',\n stage: 'authenticated',\n scopes: ['prompt.send'],\n doc: 'PROTOCOL.md c2s.session.sendPrompt',\n validate: (payload) => {\n const checked = payloadObject(payload)\n if (!checked.ok) return checked\n const invalid = requireSessionId(checked.value)\n if (invalid) return invalid\n const p = checked.value\n if (p.clientSendId !== undefined && !validSendId(p.clientSendId)) {\n return reject('E_PROTOCOL', 'invalid clientSendId')\n }\n if (\n !isOptionalField(p, 'text', (v) => isText(v, MAX_PROMPT_TEXT_CHARS, false)) ||\n !isOptionalField(p, 'images', Array.isArray) ||\n !isOptionalField(p, 'documents', Array.isArray)\n ) {\n return reject('E_PROTOCOL', 'invalid prompt fields')\n }\n // 附件条目形状:原 request-validation 的检查整体先于 handler 的资源上限,\n // 次序保持不变,同一条载荷在两条路径上得到同一条信息。\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))) {\n return reject('E_PROTOCOL', 'invalid attachment')\n }\n for (const item of (items ?? []) as Array<Record<string, unknown>>) {\n if (item.name !== undefined && !isText(item.name, 4096, false)) {\n return reject('E_PROTOCOL', 'invalid attachment name')\n }\n if (item.truncated !== undefined && typeof item.truncated !== 'boolean') {\n return reject('E_PROTOCOL', 'invalid truncated flag')\n }\n }\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 (text.trim().length === 0 && rawImages.length === 0 && rawDocuments.length === 0) {\n return reject('E_PROTOCOL', 'sessionId and prompt content required')\n }\n if (rawImages.length > MAX_PROMPT_IMAGES) return reject('E_PROTOCOL', 'too many images')\n if (rawDocuments.length > MAX_PROMPT_DOCUMENTS || rawImages.length + rawDocuments.length > MAX_PROMPT_IMAGES) {\n return reject('E_PROTOCOL', 'too many prompt attachments')\n }\n const images: Array<{ mediaType: string; data: string; name?: string }> = []\n for (const image of rawImages as Array<Record<string, unknown>>) {\n const mediaType = String(image?.mediaType)\n const data = image?.data\n if (\n !IMAGE_MEDIA_TYPES.has(mediaType) ||\n typeof data !== 'string' ||\n data.length === 0 ||\n data.length > MAX_BASE64_CHARS_PER_IMAGE\n ) {\n return reject('E_PROTOCOL', 'invalid image attachment')\n }\n images.push({\n mediaType,\n 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 as Array<Record<string, unknown>>) {\n const name = document?.name\n const mediaType = document?.mediaType\n const documentText = document?.text\n if (\n typeof name !== 'string' ||\n typeof mediaType !== 'string' ||\n typeof documentText !== 'string' ||\n documentText.length === 0 ||\n documentText.length > MAX_DOCUMENT_TEXT_CHARS\n ) {\n return reject('E_PROTOCOL', 'invalid document attachment')\n }\n const cleanName = sanitizeDocumentField(name, MAX_DOCUMENT_NAME_CHARS)\n const cleanMediaType = sanitizeDocumentField(mediaType, MAX_DOCUMENT_MEDIA_TYPE_CHARS).toLowerCase()\n if (!cleanName || !cleanMediaType || cleanMediaType.startsWith('image/')) {\n return reject('E_PROTOCOL', 'invalid document attachment')\n }\n documents.push({\n name: cleanName,\n mediaType: cleanMediaType,\n text: documentText,\n ...(document.truncated === true ? { truncated: true } : {}),\n })\n }\n return accept({\n sessionId: p.sessionId,\n text,\n images,\n documents,\n ...(p.clientSendId !== undefined ? { clientSendId: p.clientSendId } : {}),\n })\n },\n handle: async (ctx, payload) => {\n const sessionId = payload.sessionId as string\n const text = payload.text as string\n const images = payload.images as Array<{ mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'; data: string; name?: string }>\n const documents = payload.documents as Array<{ mediaType: string; name: string; text: string; truncated?: boolean }>\n const clientSendId = payload.clientSendId as string | undefined\n if (clientSendId !== undefined) {\n // 幂等投递:同一 clientSendId 重复到达时复用回执,不重复入队。\n const receipt = await ctx.bridge.promptDeliveries.dispatch(\n ctx.deviceId!,\n clientSendId,\n { sessionId, content: { text, images, documents } },\n () => ctx.bridge.sendPrompt(sessionId, text, images, documents),\n )\n ctx.send('s2c.ack', receipt)\n return\n }\n const userSeq = await ctx.bridge.sendPrompt(sessionId, text, images, documents)\n if (!userSeq.ok) return ctx.fail(userSeq.code, userSeq.message)\n ctx.send('s2c.ack', { userSeq: userSeq.value })\n },\n },\n]\n","/**\n * wire 注册表(wire registry)——phone wire 缝的 host 侧属主。\n *\n * 一帧一行:`stage`(认证前/后)、`scopes`(全部满足)、`widgetPolicy`\n * (widget 短连接可读性)、`capability`(welcome 位门)、`validate`\n * (形状与资源上限)、`handle`(帧逻辑)。此前这些事实分散在四个模块里,\n * 各用一种风格枚举帧类型:connection.ts 的 switch、connection-policy 的\n * requiredScope if 链、request-validation 的 if 链、host-bridge 的\n * capabilities getter 与方法内 typeof 探测。\n *\n * 本 module 只提供表的形状、检查与 dispatch;handler 体按特性住在\n * wire-session / wire-schedule / wire-push / wire-device / wire-interaction,\n * 各自向这里登记自己的行(静态导入,无 import 副作用)。\n *\n * 帧的不变量由 tests/wire-registry.test.ts 逐行断言:每位被闸的帧都绑定一个\n * 已存在的 welcome 位、每个 scope 都是合法 DeviceScope、每个类型都有行、\n * 每行都指向 PROTOCOL.md 的一个小节。\n */\n\nimport type { Envelope } from './protocol.ts'\nimport type { BridgeSink, HostBridge } from './host-bridge.ts'\nimport type { WelcomeCapabilities } from './protocol.ts'\nimport type { DeviceStore } from './token.ts'\nimport type { DeviceScope } from './device-auth.ts'\nimport type { CapabilityGate } from './host-capabilities.ts'\nimport type { WireErrorCode } from './wire-errors.ts'\n\n/** 出站帧字面量:与入站共用一份词汇,record() 随后只接受这个子集。 */\nexport type S2CType =\n | 's2c.ack'\n | 's2c.auth.challenge'\n | 's2c.directory.listing'\n | 's2c.directory.picked'\n | 's2c.error'\n | 's2c.history.page'\n | 's2c.notify'\n | 's2c.pending.approval'\n | 's2c.pending.cleared'\n | 's2c.pending.question'\n | 's2c.pending.snapshot'\n | 's2c.pong'\n | 's2c.resume.done'\n | 's2c.resync'\n | 's2c.schedule.changed'\n | 's2c.schedule.history'\n | 's2c.schedule.snapshot'\n | 's2c.schedule.updated'\n | 's2c.session.archived'\n | 's2c.session.event'\n | 's2c.session.forked'\n | 's2c.session.models'\n | 's2c.session.modelSelected'\n | 's2c.session.renamed'\n | 's2c.session.tail'\n | 's2c.session.unarchived'\n | 's2c.sessions.archived.snapshot'\n | 's2c.sessions.delta'\n | 's2c.sessions.snapshot'\n | 's2c.welcome'\n | 's2c.workspace.created'\n | 's2c.workspaces.snapshot'\n\n/**\n * 入站帧字面量 = 本 Bridge 实现的全部客户端帧。\n *\n * 注意 `c2s.resume` 不在其中:PROTOCOL.md 把它与 c2s.ping 并列为控制帧,但\n * 续传由 `c2s.auth.prove` 的 `resumeCursor` 字段承载,没有独立的 resume 帧\n * (历史上 requiredScope 为它留过一个无人使用的条目,见 G7)。\n */\nexport type C2SType =\n | 'c2s.ping'\n | 'c2s.auth.prove'\n | 'c2s.sessions.list'\n | 'c2s.sessions.archived'\n | 'c2s.pending.list'\n | 'c2s.workspaces.list'\n | 'c2s.workspace.create'\n | 'c2s.directory.list'\n | 'c2s.directory.pick'\n | 'c2s.session.open'\n | 'c2s.session.close'\n | 'c2s.session.create'\n | 'c2s.session.fork'\n | 'c2s.session.rename'\n | 'c2s.session.archive'\n | 'c2s.session.unarchive'\n | 'c2s.session.cancel'\n | 'c2s.session.history'\n | 'c2s.session.attachment'\n | 'c2s.session.models'\n | 'c2s.session.selectModel'\n | 'c2s.session.delivery'\n | 'c2s.session.sendPrompt'\n | 'c2s.schedule.list'\n | 'c2s.schedule.history'\n | 'c2s.schedule.create'\n | 'c2s.schedule.update'\n | 'c2s.schedule.delete'\n | 'c2s.approval.respond'\n | 'c2s.question.respond'\n | 'c2s.device.revoke'\n | 'c2s.liveActivity.register'\n | 'c2s.liveActivity.unregister'\n | 'c2s.push.register'\n | 'c2s.widget.push.register'\n\n/** 帧在连接生命周期里允许出现的阶段。 */\nexport type FrameStage = 'pre-auth' | 'authenticated'\n\n/**\n * widget 短连接(clientRole: \"widget\")的帧策略。\n *\n * - `allowed`:只读面板需要的少量帧;\n * - `deny`:通用只读拒绝;\n * - `handler`:交给 handler 用自己的理由拒绝——用于 c2s.device.revoke,\n * 通用门禁只会说 \"read-only\",而规范要求给出「小组件不得解绑设备」的\n * 具体原因(PROTOCOL.md device.revoke 一节)。\n */\nexport type WidgetPolicy = 'allowed' | 'deny' | 'handler'\n\nexport const DEFAULT_WIDGET_POLICY: WidgetPolicy = 'deny'\n\n/** 拒绝:wire 错误码 + 可读信息。undefined 表示通过。 */\nexport interface WireRejection {\n code: WireErrorCode\n message: string\n}\n\n/**\n * 校验结果:通过时带上「归一化后的载荷」——形状检查与归一化同处一行,\n * handler 拿到的就是可直接使用的值(比如 sendPrompt 的 images/documents\n * 已在此时完成媒体类型与长度清洗)。拒绝时带 wire 错误码与可读信息。\n */\nexport type CheckedPayload =\n | { ok: true; value: Record<string, unknown> }\n | ({ ok: false } & WireRejection)\n\n/** 一帧在打开历史期间缓存的实时事件;连接持有所有权。 */\nexport interface OpenEventBuffer {\n readonly frames: Array<{ type: string; payload: unknown; seq?: number }>\n}\n\n/**\n * handler 看到的每帧 facade:把当前帧的 id 绑进 send/fail,handler 不必传 id;\n * 连接自身状态(打开中的会话缓冲、live activity 代次、撤销标志)以少量操作\n * 暴露,所有权仍在 connection —— 注册表只拥有帧的事实。\n */\nexport interface FrameContext extends BridgeSink {\n readonly frame: Envelope\n readonly deviceId: string | undefined\n readonly widgetClient: boolean\n readonly bridge: HostBridge\n readonly devices: DeviceStore\n readonly debug: boolean\n log(message: string): void\n send(type: S2CType, payload: unknown): void\n fail(code: WireErrorCode, message: string): void\n close(code: number, reason: string): void\n bufferOpenEvents(sessionId: string): OpenEventBuffer\n /** 打开失败:仅当缓冲仍属于本次尝试时才移除。 */\n discardOpenBuffer(sessionId: string, buffer: OpenEventBuffer): void\n /** 打开成功:认领缓冲并按其到达顺序补发;被并发操作取代时返回 false。 */\n flushOpenBuffer(sessionId: string, buffer: OpenEventBuffer): boolean\n closeOpenSession(sessionId: string): void\n /** 抬升 Live Activity 注册代次并返回新值;在途注册用旧值比对即知自己已被取代。 */\n nextLiveActivityGeneration(): number\n /** 当前代次:await 之后重新比对用。 */\n readonly liveActivityGeneration: number\n readonly pendingLiveActivityId: string | undefined\n setPendingLiveActivityId(activityId: string | undefined): void\n markRevoked(): void\n /** c2s.auth.prove 的机制由连接门实现(认证是安全判定,不属于特性模块)。 */\n prove(): Promise<void>\n enrollPushKey(enrollKey: string): Promise<void> | void\n revokeSiblings(deviceId: string): Promise<unknown> | unknown\n}\n\nexport interface WireFrameRow {\n readonly type: C2SType\n readonly stage: FrameStage\n /** 全部满足才放行;空数组表示控制帧,不要求业务 scope。 */\n readonly scopes: readonly DeviceScope[]\n readonly widgetPolicy?: WidgetPolicy\n readonly capability?: CapabilityGate\n /** PROTOCOL.md 小节名;tests/wire-registry.test.ts 断言其存在。 */\n readonly doc: string\n readonly validate?: (payload: unknown) => CheckedPayload\n readonly handle: (ctx: FrameContext, payload: Record<string, unknown>) => Promise<void> | void\n}\n\n// ---------- 检查(connection 在 dispatch 前依次调用) ----------\n\n/** 第一个缺失的 scope;消息与迁移前一致(`scope <name> required`)。 */\nexport function scopeRejection(\n row: WireFrameRow,\n scopes: ReadonlySet<DeviceScope>,\n): WireRejection | undefined {\n for (const scope of row.scopes) {\n if (!scopes.has(scope)) return { code: 'E_FORBIDDEN', message: `scope ${scope} required` }\n }\n return undefined\n}\n\n/** 能力位关闭时拒绝。校验先于本检查,与迁移前的次序一致。 */\nexport function capabilityRejection(\n row: WireFrameRow,\n capabilities: WelcomeCapabilities,\n): WireRejection | undefined {\n if (row.capability === undefined) return undefined\n if (capabilities[row.capability] === true) return undefined\n return { code: 'E_UNSUPPORTED', message: 'capability unavailable on this host version' }\n}\n\nexport function widgetPolicyOf(row: WireFrameRow): WidgetPolicy {\n return row.widgetPolicy ?? DEFAULT_WIDGET_POLICY\n}\n\n/** 校验一帧载荷;未登记 validate 的行原样通过。 */\nexport function validatePayload(row: WireFrameRow, payload: unknown): CheckedPayload {\n if (row.validate === undefined) {\n return { ok: true, value: (payload ?? {}) as Record<string, unknown> }\n }\n return row.validate(payload)\n}\n\n/** 执行一帧。检查(阶段/scope/能力/校验)由 connection 按序先行完成。 */\nexport async function dispatchFrame(\n row: WireFrameRow,\n ctx: FrameContext,\n payload: Record<string, unknown>,\n): Promise<void> {\n await row.handle(ctx, payload)\n}\n\n// ---------- 行内校验共用工具 ----------\n\n/**\n * 载荷必须是普通对象。此前这条判定住在 request-validation 里,对\n * `c2s.sessions.list` 等无参帧豁免、对 `c2s.sessions.archived` 却不通融\n * (同语义两种待遇,见 G2);现在豁免由各行的 validate 自己声明。\n */\nexport function payloadObject(value: unknown): CheckedPayload {\n if (value === undefined || value === null) return { ok: true, value: {} }\n if (typeof value !== 'object' || Array.isArray(value)) {\n return { ok: false, code: 'E_PROTOCOL', message: 'payload must be an object' }\n }\n return { ok: true, value: value as Record<string, unknown> }\n}\n\n/** 字符串字段:类型正确、不超长、非空(可放宽)。 */\nexport function isText(value: unknown, max = 4096, nonempty = true): boolean {\n return typeof value === 'string' && value.length <= max && (!nonempty || value.trim().length > 0)\n}\n\n/** 可选字段:缺省合法,给出时必须满足 check。 */\nexport function isOptionalField(\n payload: Record<string, unknown>,\n key: string,\n check: (value: unknown) => boolean,\n): boolean {\n return payload[key] === undefined || check(payload[key])\n}\n\nexport function isInteger(value: unknown, min: number, max: number): boolean {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= min && value <= max\n}\n\nexport function reject(code: WireErrorCode, message: string): CheckedPayload {\n return { ok: false, code, message }\n}\n\nexport function accept(value: Record<string, unknown>): CheckedPayload {\n return { ok: true, value }\n}\n\n// ---------- 表 ----------\n\nimport { interactionRows } from './wire-interaction.ts'\nimport { deviceRows } from './wire-device.ts'\nimport { pushRows } from './wire-push.ts'\nimport { scheduleRows } from './wire-schedule.ts'\nimport { sessionRows } from './wire-session.ts'\n\n/** 全部入站行。装配是静态的:新增特性 module 必须在这里显式出现。 */\nexport const WIRE_FRAME_ROWS: readonly WireFrameRow[] = [\n ...sessionRows,\n ...scheduleRows,\n ...interactionRows,\n ...pushRows,\n ...deviceRows,\n]\n\nconst ROWS_BY_TYPE = new Map<C2SType, WireFrameRow>(WIRE_FRAME_ROWS.map((row) => [row.type, row]))\n\nexport function registryRowFor(type: string): WireFrameRow | undefined {\n return ROWS_BY_TYPE.get(type as C2SType)\n}\n\n/** 供 build 期不变量检查与测试使用:每行可索引。 */\nexport function wireFrameRows(): readonly WireFrameRow[] {\n return WIRE_FRAME_ROWS\n}\n","/**\n * 连接门(ConnectionGate)——「一个匿名 socket 被允许做什么」的唯一属主。\n *\n * 迁移前,这些规则散在五个地方:connection.ts 的 onMessage(长度上限、信封\n * 卫生、pre-auth 白名单、scope/widget 门)、connection.ts 的 prove()(认证)、\n * index.ts 的 handleUpgrade(连接数、名额、失败记账、6 个手工 release 点)、\n * auth-rate-limit.ts(策略)、token.ts(注册表语义)。理解一次 4401 关闭要跨\n * 400 行来回跳。\n *\n * 现在:门拥有 ①认证状态机的全部迁移 ②认证名额的获取与释放(单一释放点)\n * ③「此刻这一帧是否被允许进入」的判定。连接只剩传输、welcome 发射、sink 台账\n * 与连接自有缓冲;注册表行仍住在 wire-registry 及其特性 module 里,门只负责\n * 在正确的时机调用它们。\n *\n * 名额的生命周期分两段,各有保证:\n * - 接入段:门在 handleUpgrade 里构造(admit 发生于此)。若 upgrade 回调根本\n * 不执行(upgrade 期间 socket 被销毁),5 秒兜底会释放名额并判门死刑;\n * - 认证段:attach 之后由 35 秒 hello 计时器兜底,任何一条落定路径\n * (成功/证明无效/超时/关闭)都经 settleAuthentication 的 exactly-once\n * 守卫释放一次。\n */\n\nimport { PROTOCOL_VERSION } from './protocol.ts'\nimport type { AuthProofPayload, Envelope } from './protocol.ts'\nimport type { HostBridge } from './host-bridge.ts'\nimport type { DeviceStore } 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 MAX_APP_VERSION_CHARS,\n MAX_DEVICE_ID_CHARS,\n MAX_DEVICE_NAME_CHARS,\n PRE_AUTH_FRAME_BYTES,\n sanitizeDeviceField,\n isEnvelope,\n} from './connection-policy.ts'\nimport { AuthRateLimiter } from './auth-rate-limit.ts'\nimport {\n capabilityRejection,\n dispatchFrame,\n registryRowFor,\n scopeRejection,\n validatePayload,\n widgetPolicyOf,\n type FrameContext,\n type OpenEventBuffer,\n type S2CType,\n} from './wire-registry.ts'\nimport type { WireErrorCode } from './wire-errors.ts'\n\n/** 认证落定的四种结局;与迁移前 index.ts 收到的 reason 一致。 */\nexport type SettleReason = 'success' | 'invalid-proof' | 'timeout' | 'closed'\n\n/** 认证成功的产物:连接据它发 welcome、注册 sink、决定重放。 */\nexport interface AuthenticatedIdentity {\n deviceId: string\n scopes: ReadonlySet<DeviceScope>\n widgetClient: boolean\n resumeCursor: number | undefined\n deviceName: string\n appVersion: string\n}\n\n/**\n * 门看到的宿主,由连接实现:传输、sink 转发、连接自有缓冲,以及认证成功与\n * 审计两个通知。行(wire-registry)看到的 FrameContext 是它的一个按帧投影。\n */\nexport interface GateHost {\n readonly bridge: HostBridge\n readonly devices: DeviceStore\n readonly debug: boolean\n log(message: string): void\n send(type: S2CType, payload: unknown, id?: string): void\n fail(id: string | undefined, code: WireErrorCode, message: string): void\n close(code: number, reason: string): void\n // ---------- BridgeSink 转发(openSession 等行需要把上下文当作 sink) ----------\n canReceive(scope: DeviceScope): boolean\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 bufferOpenEvents(sessionId: string): OpenEventBuffer\n discardOpenBuffer(sessionId: string, buffer: OpenEventBuffer): void\n flushOpenBuffer(sessionId: string, buffer: OpenEventBuffer): boolean\n closeOpenSession(sessionId: string): void\n nextLiveActivityGeneration(): number\n readonly liveActivityGeneration: number\n readonly pendingLiveActivityId: string | undefined\n setPendingLiveActivityId(activityId: string | undefined): void\n markRevoked(): void\n enrollPushKey(enrollKey: string): Promise<void> | void\n revokeSiblings(deviceId: string): Promise<unknown> | unknown\n // ---------- 通知 ----------\n /** 认证成功:由连接发 welcome、注册 sink、决定重放/重同步。 */\n onAuthenticated(identity: AuthenticatedIdentity): void\n /** 隐私 preserving 审计事件(有效 hello 之后)。 */\n deviceAuthenticated(deviceId: string): void\n /** 认证落定:纯观测通知(名额释放与限流记账已在门内完成)。 */\n settled(ok: boolean, reason: SettleReason): void\n}\n\nexport interface ConnectionGateOptions {\n /** 客户端身份,用于限流(IP 或回环标识)。 */\n source: string\n devices: DeviceStore\n /** 稳定 Host 身份,写入每次挑战。 */\n audience: string\n limiter: AuthRateLimiter\n log: (message: string) => void\n /** 审计标签函数:把敏感标识变成短哈希,供日志使用。 */\n auditLabel?: (value: string) => string\n /** 未 attach 的兜底时限:upgrade 回调根本不执行时释放名额。 */\n attachTimeoutMs?: number\n}\n\n/** upgrade 正常是毫秒级;5 秒已极宽,只为「回调根本不执行」兜底。 */\nconst DEFAULT_ATTACH_TIMEOUT_MS = 5_000\n\nexport class ConnectionGate {\n private authenticated = false\n private settled = false\n private revoked = false\n private deviceId: string | undefined\n private scopes = new Set<DeviceScope>()\n private widgetClient = false\n private readonly challenge: AuthChallenge\n private helloTimer: NodeJS.Timeout | undefined\n private attachTimer: NodeJS.Timeout | undefined\n private attached = false\n private host: GateHost | undefined\n private admission: { release: () => void } | undefined\n private dead = false\n\n constructor(private readonly options: ConnectionGateOptions) {\n this.challenge = createAuthChallenge(options.audience)\n // 名额在此获取:早于 upgrade 回调,因此「回调不执行」也有释放保证。\n const admission = options.limiter.admit(options.source)\n this.admission = admission.ok ? admission : undefined\n if (!admission.ok) {\n this.dead = true\n return\n }\n this.attachTimer = setTimeout(() => {\n this.attachTimer = undefined\n // 从未 attach:回调没跑,socket 不会再来。释放名额,门作废。\n if (!this.attached && !this.settled) {\n this.dead = true\n this.releaseAdmission()\n }\n }, options.attachTimeoutMs ?? DEFAULT_ATTACH_TIMEOUT_MS)\n this.attachTimer.unref()\n }\n\n /** 名额是否拿到;false 时 handleUpgrade 应直接拒掉这个源。 */\n get admitted(): boolean {\n return !this.dead\n }\n\n /** 客户端身份:限流与审计日志共用同一个值。 */\n get source(): string {\n return this.options.source\n }\n\n /**\n * ws 就绪:接线宿主、下发挑战并启动 hello 计时器。只应被调用一次——\n * 由连接在构造时调用(那一刻 ws 才真正存在)。\n */\n attach(host: GateHost): void {\n if (this.dead || this.attached) return\n this.attached = true\n this.host = host\n if (this.attachTimer !== undefined) {\n clearTimeout(this.attachTimer)\n this.attachTimer = undefined\n }\n host.send('s2c.auth.challenge', this.challenge)\n this.helloTimer = setTimeout(() => {\n this.helloTimer = undefined\n if (this.authenticated) return\n this.settle(false, 'timeout')\n this.host?.close(4402, 'auth timeout')\n }, AUTH_TIMEOUT_MS)\n this.helloTimer.unref()\n }\n\n /**\n * 接入窗口结束:若始终没有 socket 接上(upgrade 回调没执行),立刻归还名额,\n * 不必等 5 秒兜底。已 attach 的门不在此释放——它的名额由落定路径或 hello\n * 计时器负责。\n */\n releaseIfNeverAttached(): void {\n if (!this.attached && !this.settled) {\n this.dead = true\n this.releaseAdmission()\n }\n }\n\n /** 拒绝一个已创建但最终不会接线的门(bridge 变更、构造失败)。 */\n markDead(): void {\n this.dead = true\n this.releaseAdmission()\n }\n\n /** socket 关闭:未落定则按 closed 收尾(并释放名额)。 */\n onClose(): void {\n if (!this.settled) this.settle(false, 'closed')\n if (this.helloTimer !== undefined) clearTimeout(this.helloTimer)\n if (this.attachTimer !== undefined) clearTimeout(this.attachTimer)\n }\n\n /**\n * 处理一条原始帧。内部完成全部 pre-auth 规则(长度上限、信封卫生、版本、\n * pre-auth 白名单、撤销吞帧),再进入认证、授权与分发。\n */\n async handleFrame(raw: string): Promise<void> {\n const host = this.host\n if (this.dead || host === undefined) return\n // 撤销后的设备正在关闭:吞掉一切,不再回应一个已不存在的设备。\n if (this.revoked) return\n // 长度上限先行:预认证帧很小,超限即拒且不解析——不让匿名端用 64MiB\n // 载荷在认证窗口内消耗 CPU。\n if (!this.authenticated && raw.length > PRE_AUTH_FRAME_BYTES) {\n host.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 host.fail(undefined, 'E_PROTOCOL', 'malformed frame')\n return\n }\n env = parsed\n } catch {\n host.fail(undefined, 'E_PROTOCOL', 'frame is not valid JSON')\n return\n }\n if (env.v !== PROTOCOL_VERSION) {\n host.fail(env.id, 'E_UNSUPPORTED', 'unsupported protocol version')\n host.close(4500, 'protocol version mismatch')\n return\n }\n\n if (!this.authenticated) {\n // 匿名端对每个非控制帧只得到一个答复:透露哪些名字已注册等于泄露帧清单。\n const control = registryRowFor(env.type)\n if (control === undefined || control.stage !== 'pre-auth') {\n host.fail(env.id, 'E_PROTOCOL', 'authenticate first')\n return\n }\n await dispatchFrame(control, this.context(env), {})\n return\n }\n\n const row = registryRowFor(env.type)\n // widget 只读门在前,且覆盖未知类型:短连接只准发白名册行,其余一律\n // 「只读」,不泄露帧清单。\n if (this.widgetClient && (row === undefined || widgetPolicyOf(row) === 'deny')) {\n return host.fail(env.id, 'E_FORBIDDEN', 'widget connection is read-only')\n }\n // 未知类型直接 E_PROTOCOL(G6)。先查 scope 会让没有 sessions.read 的\n // 设备听到关于一个不存在帧的「权限不足」。\n if (row === undefined) {\n host.fail(env.id, 'E_PROTOCOL', 'unknown type: ' + env.type)\n return\n }\n const scope = scopeRejection(row, this.scopes)\n if (scope !== undefined) return host.fail(env.id, scope.code, scope.message)\n // 校验先于能力门,与迁移前「载荷形状先于 handler 看能力」的次序一致。\n const validated = validatePayload(row, env.payload)\n if (!validated.ok) return host.fail(env.id, validated.code, validated.message)\n const capability = capabilityRejection(row, host.bridge.capabilities)\n if (capability !== undefined) return host.fail(env.id, capability.code, capability.message)\n\n await dispatchFrame(row, this.context(env), validated.value)\n }\n\n /** 门持有的撤销标记由 device.revoke 行置位。 */\n markRevoked(): void {\n this.revoked = true\n }\n\n // ---------- 认证 ----------\n\n /** c2s.auth.prove 的行 handler 调用这里:验签、载入 scope、记账、落定。 */\n async authenticate(env: Envelope): Promise<void> {\n const host = this.host\n // 刚自撤销的 socket 正在关闭,不能再认证(注册表墓碑本来也会拒)。\n if (this.revoked || host === undefined) return\n const p = (env.payload ?? {}) as Partial<AuthProofPayload>\n if (!p.deviceId) {\n host.fail(env.id, 'E_PROTOCOL', 'deviceId required')\n host.close(4403, 'deviceId required')\n return\n }\n const deviceId = sanitizeDeviceField(p.deviceId, MAX_DEVICE_ID_CHARS)\n if (!deviceId) {\n host.fail(env.id, 'E_PROTOCOL', 'deviceId required')\n host.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 record = this.options.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 === this.challenge.nonce &&\n p.audience === this.challenge.audience &&\n p.issuedAt === this.challenge.issuedAt &&\n p.expiresAt === this.challenge.expiresAt &&\n Date.now() <= this.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 ...this.challenge,\n }, p.signature)\n if (!proofValid || record === undefined) {\n host.fail(env.id, 'E_AUTH', 'device proof missing or invalid')\n this.settle(false, 'invalid-proof')\n host.close(4401, 'invalid device proof')\n return\n }\n this.settle(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) {\n this.options.devices.markAuthenticated(deviceId, deviceName, appVersion, Date.now())\n }\n host.deviceAuthenticated(deviceId)\n // 欢迎帧与重放由连接负责:认证是安全判定,欢迎是数据面展示。\n host.onAuthenticated({\n deviceId,\n scopes: this.scopes,\n widgetClient: this.widgetClient,\n resumeCursor: this.widgetClient ? undefined : resumeCursor,\n deviceName,\n appVersion,\n })\n }\n\n /** 限流记账与名额释放只此一处;exactly-once 由 settled 守卫保证。 */\n private settle(ok: boolean, reason: SettleReason): void {\n if (this.settled) return\n this.settled = true\n this.releaseAdmission()\n this.host?.settled(ok, reason)\n if (ok) {\n this.options.limiter.recordSuccess(this.options.source)\n return\n }\n const failure = this.options.limiter.recordFailure(this.options.source)\n if (failure.newlyBlocked) {\n const label = this.options.auditLabel?.(this.options.source) ?? this.options.source\n this.options.log(`authentication source blocked source=${label}`)\n }\n }\n\n private releaseAdmission(): void {\n this.admission?.release()\n this.admission = undefined\n }\n\n /** 把宿主投影成行看到的每帧上下文:id 绑进 send/fail,身份来自门。 */\n private context(env: Envelope): FrameContext {\n const host = this.host!\n return {\n frame: env,\n deviceId: this.deviceId,\n widgetClient: this.widgetClient,\n bridge: host.bridge,\n devices: host.devices,\n debug: host.debug,\n log: (message) => host.log(message),\n send: (type, payload) => host.send(type, payload, env.id),\n fail: (code, message) => host.fail(env.id, code, message),\n close: (code, reason) => host.close(code, reason),\n canReceive: (scope) => host.canReceive(scope),\n push: (type, payload, seq) => host.push(type, payload, seq),\n lastCursor: () => host.lastCursor(),\n replay: (entries) => host.replay(entries),\n replayDone: () => host.replayDone(),\n resync: () => host.resync(),\n bufferOpenEvents: (sessionId) => host.bufferOpenEvents(sessionId),\n discardOpenBuffer: (sessionId, buffer) => host.discardOpenBuffer(sessionId, buffer),\n flushOpenBuffer: (sessionId, buffer) => host.flushOpenBuffer(sessionId, buffer),\n closeOpenSession: (sessionId) => host.closeOpenSession(sessionId),\n nextLiveActivityGeneration: () => host.nextLiveActivityGeneration(),\n get liveActivityGeneration() {\n return host.liveActivityGeneration\n },\n get pendingLiveActivityId() {\n return host.pendingLiveActivityId\n },\n setPendingLiveActivityId: (activityId) => host.setPendingLiveActivityId(activityId),\n markRevoked: () => this.markRevoked(),\n prove: () => this.authenticate(env),\n enrollPushKey: (enrollKey) => host.enrollPushKey(enrollKey),\n revokeSiblings: (deviceId) => host.revokeSiblings(deviceId),\n }\n }\n}\n","import type { WebSocket } from 'ws'\nimport { PROTOCOL_VERSION } from './protocol.ts'\nimport type { Envelope } from './protocol.ts'\nimport type { BridgeSink, HostBridge } from './host-bridge.ts'\nimport type { DeviceStore } from './token.ts'\nimport type { DeviceScope } from './device-auth.ts'\nimport { MAX_OUTBOUND_BUFFER_BYTES } from './connection-policy.ts'\nimport { AuthRateLimiter } from './auth-rate-limit.ts'\nimport type { WireErrorCode } from './wire-errors.ts'\nimport { ConnectionGate, type AuthenticatedIdentity, type GateHost } from './connection-gate.ts'\nimport type { OpenEventBuffer, S2CType } from './wire-registry.ts'\n\nexport {\n AUTH_TIMEOUT_MS,\n MAX_OUTBOUND_BUFFER_BYTES,\n PRE_AUTH_FRAME_BYTES,\n} from './connection-policy.ts'\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 /** 客户端身份,供连接门做限流;缺省时按本地回环源处理。 */\n source?: string\n /** 认证名额与失败记账由连接门持有(见 connection-gate.ts)。 */\n rateLimiter?: AuthRateLimiter\n /** 审计标签函数:把客户端身份变成短哈希供日志使用;缺省时直接用原值。 */\n auditLabel?: (value: string) => string\n /** Called once when the socket closes (cleanly or not). */\n onClosed?: (connection: BridgeConnection) => void\n /**\n * 认证落定通知:纯观测用。名额释放与限流记账已由连接门内部完成,\n * 接入方不再需要据此做任何事;测试用它断言「只落定一次」。\n */\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 * c2s.device.revoke (device unbind): the registered device revoked itself\n * and every OTHER active connection of that device must be dropped.\n * `except` is the connection that sent the frame — its close is already\n * owned by the handler (ack first, then 4401). The hook must not flip the\n * registry itself; the handler calls DeviceStore.revoke before this.\n */\n onDeviceRevoke?: (deviceId: string, except: BridgeConnection) => Promise<unknown> | unknown\n}\n\n/**\n * One connected phone. Implements BridgeSink so the HostBridge can push\n * projected frames and replays.\n *\n * 本模块现在只剩传输与连接自有状态:socket、send/fail/close、背压、idle 计时、\n * welcome 发射、sink 台账、打开中的会话缓冲、Live Activity 代次。帧的规则\n * (pre-auth、认证、授权、分发)全部属于 ConnectionGate;帧的事实属于\n * wire-registry。连接通过实现 GateHost 把这两者接起来。\n */\nexport class BridgeConnection implements BridgeSink {\n private closed = false\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 private readonly openSessions = new Set<string>()\n private liveActivityRegistrationGeneration = 0\n private pendingLiveActivityId?: string\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 /** 认证成功后由门回填,供 welcome 与 sink 注册使用。 */\n private identity: AuthenticatedIdentity | undefined\n\n /** 帧规则(pre-auth、认证、授权、分发)的属主;由接入方创建并交进来。 */\n readonly gate: ConnectionGate\n\n constructor(\n private readonly ws: WebSocket,\n private readonly deps: ConnectionStateDeps,\n /** 由接入方预先创建的门(提前占名额以在握手前限流);缺省时连接自建。 */\n gate: ConnectionGate = new ConnectionGate({\n source: deps.source ?? 'local',\n devices: deps.devices,\n audience: deps.audience,\n limiter: deps.rateLimiter ?? new AuthRateLimiter(),\n log: (message) => deps.log(message),\n ...(deps.auditLabel ? { auditLabel: deps.auditLabel } : {}),\n }),\n ) {\n const connection = this\n const host: GateHost = {\n get bridge() { return connection.deps.bridge },\n get devices() { return connection.deps.devices },\n get debug() { return deps.debug === true },\n log: (message) => deps.log(message),\n send: (type: S2CType, payload, id) => connection.send(type, payload, id),\n fail: (id, code, message) => connection.fail(id, code, message),\n close: (code, reason) => connection.close(code, reason),\n canReceive: (scope) => connection.canReceive(scope),\n push: (type, payload, seq) => connection.push(type, payload, seq),\n lastCursor: () => connection.lastCursor(),\n replay: (entries) => connection.replay(entries),\n replayDone: () => connection.replayDone(),\n resync: () => connection.resync(),\n bufferOpenEvents: (sessionId) => connection.bufferOpenEvents(sessionId),\n discardOpenBuffer: (sessionId, buffer) => connection.discardOpenBuffer(sessionId, buffer),\n flushOpenBuffer: (sessionId, buffer) => connection.flushOpenBuffer(sessionId, buffer),\n closeOpenSession: (sessionId) => connection.closeOpenSession(sessionId),\n nextLiveActivityGeneration: () => {\n connection.liveActivityRegistrationGeneration += 1\n return connection.liveActivityRegistrationGeneration\n },\n get liveActivityGeneration() { return connection.liveActivityRegistrationGeneration },\n get pendingLiveActivityId() { return connection.pendingLiveActivityId },\n setPendingLiveActivityId: (activityId) => { connection.pendingLiveActivityId = activityId },\n markRevoked: () => connection.gate.markRevoked(),\n enrollPushKey: (enrollKey) => deps.onPushEnrollKey?.(enrollKey),\n revokeSiblings: (deviceId) => deps.onDeviceRevoke?.(deviceId, connection),\n onAuthenticated: (identity) => connection.onAuthenticated(identity),\n deviceAuthenticated: (deviceId) => deps.onDeviceAuthenticated?.(deviceId),\n settled: (ok, reason) => deps.onAuthenticationSettled?.(ok, reason),\n }\n this.gate = gate\n\n ws.on('message', (data) => {\n this.lastActivity = Date.now()\n void gate.handleFrame(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 the gate; 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 // The challenge goes out the moment the socket is live; the hello deadline\n // is the gate's, so an upgrade that never produced a socket still has the\n // attach timeout to release its admission slot.\n gate.attach(host)\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.identity?.deviceId\n }\n\n get suppressesAlertPush(): boolean {\n return this.identity?.widgetClient !== true\n }\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.identity?.scopes.has(scope) ?? false\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 /** 认证成功:门只做安全判定,欢迎与重放归连接(数据面)。 */\n private onAuthenticated(identity: AuthenticatedIdentity): void {\n this.identity = identity\n const cursor = identity.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: identity.deviceId,\n scopes: [...identity.scopes],\n capabilities: this.deps.bridge.capabilities,\n cursor: this.deps.bridge.currentCursor(),\n resumed: canResume,\n })\n if (!identity.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 private onClose(): void {\n if (this.closed) return\n this.closed = true\n // Unsettled sockets (never proven) settle as 'closed' and give back their\n // admission slot; already-settled ones are a no-op inside the gate.\n this.gate.onClose()\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.identity !== undefined) this.deps.bridge.removeSink(this)\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: WireErrorCode, message: string): void {\n this.send('s2c.error', { code, message }, id)\n }\n\n // ---------- connection-owned session bookkeeping ----------\n\n private bufferOpenEvents(sessionId: string): OpenEventBuffer {\n const frames: OpenEventBuffer['frames'] = []\n const buffer: OpenEventBuffer = { frames }\n this.openingSessionEvents.set(sessionId, frames)\n return buffer\n }\n\n private discardOpenBuffer(sessionId: string, buffer: OpenEventBuffer): void {\n if (this.openingSessionEvents.get(sessionId) === buffer.frames) {\n this.openingSessionEvents.delete(sessionId)\n }\n }\n\n private flushOpenBuffer(sessionId: string, buffer: OpenEventBuffer): boolean {\n if (this.openingSessionEvents.get(sessionId) !== buffer.frames) return false\n this.openSessions.add(sessionId)\n this.deps.bridge.markSinkOpen(this, sessionId)\n this.openingSessionEvents.delete(sessionId)\n for (const frame of buffer.frames) this.push(frame.type, frame.payload, frame.seq)\n return true\n }\n\n private closeOpenSession(sessionId: string): void {\n this.openingSessionEvents.delete(sessionId)\n this.openSessions.delete(sessionId)\n this.deps.bridge.markSinkClosed(this, sessionId)\n }\n}\n\n/** 供接入方引用:帧上下文的类型仍由 wire-registry 属主。 */\nexport type { S2CType }\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","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\n/** The LAN listener is TLS-only, so every advertised endpoint is `https://`. */\nexport function localEndpointURLs(addresses: readonly string[], port: number): string[] {\n const normalizedPort = normalizeLocalPort(port)\n return [...new Set(addresses)].map((address) => `https://${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 /** Testing & troubleshooting, rendered as its own settings section. */\n diagnostics?: {\n /** Verbose per-frame diagnostics (never prints token or message bodies). */\n debug?: boolean\n }\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 // rc.2 accepts live settings writes only for fields declared volatile.\n enabled: z.boolean().default(true).volatile(),\n devicesPath: z.string().default(join(bridgeDataDir(), 'devices-v2.json')),\n historyBufferMax: z.natural().min(100).default(2000),\n diagnostics: z.object({\n debug: z.boolean().default(false)\n .description('打印握手、推送等诊断日志;不会打印配对令牌、APNs token 或消息内容'),\n }).default({\n debug: false,\n }).volatile(),\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 局域网独立端口(仅 TLS;默认 3098,修改后本地连接会短暂重连)'),\n }).default({\n enabled: true,\n port: DEFAULT_LOCAL_PORT,\n }).volatile(),\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 }).volatile(),\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 * Deep-unwrap live-update (volatile) references to plain values.\n *\n * On a 0.1.7 host, `apply()`'s options — and even a direct `Config(raw)` call\n * — carry `{ get() }` reference objects for volatile fields. Every consumer of\n * `currentConfig()` compares plain values (`=== true`, numeric bounds, object\n * fields), and schemastery refuses to re-parse a reference, so normalization\n * unwraps on the way in and on the way out. A JSON-shaped config value cannot\n * carry a function, so the `get` check cannot false-positive.\n */\nexport function plainConfig(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value\n if (typeof (value as { get?: unknown }).get === 'function') {\n // A reference's snapshot is recursively plain data (references cannot\n // nest inside references), so one unwrap layer suffices; recursion keeps\n // plain containers working around it.\n return plainConfig((value as { get: () => unknown }).get())\n }\n if (Array.isArray(value)) return value.map(plainConfig)\n const plain: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) plain[key] = plainConfig(item)\n return plain\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 — and\n * unwrap volatile references so the returned Config is plain data.\n */\nexport function normalizeOptions(options: unknown): Config {\n if (typeof options === 'function') return plainConfig((options as () => unknown)()) as Config\n if (options && typeof options === 'object') return plainConfig(options) as Config\n const validated = (Config as unknown as (data: unknown) => Config)(undefined)\n return plainConfig(validated ?? {}) as Config\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 * 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 * 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","/** 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 ?? session?.todoItems?.length ?? 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(session?.activity?.trim() || task?.content || '').slice(0, 160).join(''), done, total,\n phase: !session || total === 0 ? '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 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","/**\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 * 推送网关(PushGateway)——离线推送的单一属主。\n *\n * 迁移前,这约 450 行住在 `apply()` 的闭包里:enrollment cell 与持久化、\n * `handlePushEnrollKey`、`resolvePushConfig`、`ensureRelayEnrolled`、\n * `senderFor` + cachedSender + 失败退避、两个 scheduler、`makePushOutlet`、\n * 两个自测。它今天的「接口」其实是「被 WidgetPushScheduler、\n * LiveActivityPushManager、PushOutlet 和两个 report 回调各自捕获的那几段代码」\n * ——没有任何一处能回答「推送为什么没到」。\n *\n * 现在:一个 module,实现 `PushOutlet`(HostBridge 消费的那四个方法)并额外\n * 暴露自测与零配置注册入口。enrollment、持久化、sender 缓存、退避、401 自愈\n * 全部入内;`apply()` 只做依赖注入。\n *\n * 两处本次收敛的重复:\n * - effective provider 推导(原先在 resolvePushConfig 与 relay 自测里各一份);\n * - 401 自愈三元组(原先在 widget / liveActivity / fanOut 三处各一份,\n * 见 healRelayCredential)。\n */\n\nimport { randomBytes } from 'node:crypto'\nimport { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport {\n DEFAULT_RELAY_URL,\n type Config,\n} from './config.ts'\nimport { ApnsClient } from './apns.ts'\nimport { RelayClient } from './relay-client.ts'\nimport { WidgetPushScheduler } from './widget-push.ts'\nimport { LiveActivityPushManager } from './live-activity.ts'\nimport {\n mayReceivePush,\n pushContent,\n shouldPrunePushToken,\n shouldReEnrollRelayToken,\n} from './push-policy.ts'\nimport { deviceDisplayName, expandHome, type DeviceStore } from './token.ts'\nimport type { ApnsEnvironment } from './token.ts'\nimport type { PushDelivery, PushNotification, SessionSummary } from './protocol.ts'\nimport type { PushOutlet } from './host-api.ts'\nimport type { PushTestResult, RelayTestResult } from './report-wire.ts'\nimport { runRelayProbe } from './relay-test.ts'\n\n/** 零配置注册的持久化单元(deeppilot/push-relay.json)。 */\ninterface RelayEnrollmentCell {\n clientId?: string\n autoRelay?: boolean\n enrollKey?: string\n token?: string\n}\n\ntype PushConfigSnapshot =\n | { kind: 'apns'; teamId: string; keyId: string; keyPath: string; bundleId: string }\n | { kind: 'relay'; url: string; token: string }\n\ninterface SendOutcome { outcome: 'sent' | 'invalid-token' | 'failed'; reason?: string }\ntype PushSender = (\n request: { deviceToken: string; environment: ApnsEnvironment; notification: PushDelivery },\n) => Promise<SendOutcome>\n\ninterface CachedSender {\n fingerprint: string\n send: PushSender\n dispose?: () => Promise<void>\n}\n\n/** 274 秒(约 4.5 分钟)内的失败只记一次;其间同一指纹不再重试。 */\nconst SENDER_FAILURE_RETRY_MS = 60_000\n/** 中继注册失败的节流:一次/分钟,避免中继抖动把每次通知变成一次外呼。 */\nconst ENROLL_RETRY_MS = 60_000\n\n/** 网关需要的一切都从外部注入;它自己不创建配置、设备表或连接集合。 */\nexport interface PushGatewayDeps {\n config: () => Config\n /** 推送数据目录(push-relay.json 与 APNs 密钥默认路径的宿主)。 */\n dataDir: string\n devices: () => DeviceStore | null\n audience: () => string | null\n /** 当前活跃连接:用于跳过已有 WebSocket 的设备。 */\n connections: () => Iterable<{\n connectedDeviceId: string | undefined\n suppressesAlertPush: boolean\n }>\n enabledNow: () => boolean\n log: (message: string) => void\n /** 中继探测的传输实现:默认真实 fetch,测试注入假件以免碰网络。 */\n fetchImpl?: typeof fetch\n}\n\nexport class PushGateway implements PushOutlet {\n private readonly pushRelayPath: string\n private readonly enrollmentCell: RelayEnrollmentCell = {}\n private enrollmentWriteTail: Promise<void> = Promise.resolve()\n private enrollAttemptFor: string | undefined\n private enrollLastAttemptAt = 0\n private cachedSender: CachedSender | undefined\n private senderFailedFor: { fingerprint: string; at: number } | undefined\n\n private readonly widgetPush: WidgetPushScheduler\n private readonly liveActivityPush: LiveActivityPushManager\n\n constructor(private readonly deps: PushGatewayDeps) {\n this.pushRelayPath = join(deps.dataDir, 'push-relay.json')\n this.widgetPush = new WidgetPushScheduler(async () => { await this.flushWidgetPushes() })\n this.liveActivityPush = new LiveActivityPushManager(\n () => deps.devices() ?? undefined,\n async (deviceToken, environment, notification) => this.sendLiveActivity(deviceToken, environment, notification),\n )\n }\n\n // ---------- 生命周期 ----------\n\n /** 首启恢复零配置注册状态(best effort)。 */\n async restore(): Promise<void> {\n try {\n const raw = JSON.parse(await readFile(this.pushRelayPath, 'utf8')) as RelayEnrollmentCell\n if (typeof raw.clientId === 'string') this.enrollmentCell.clientId = raw.clientId\n if (typeof raw.enrollKey === 'string') this.enrollmentCell.enrollKey = raw.enrollKey\n if (typeof raw.token === 'string') this.enrollmentCell.token = raw.token\n if (raw.autoRelay === true) this.enrollmentCell.autoRelay = true\n } catch {\n // first boot: no enrollment yet\n }\n }\n\n /** 写盘串行化:并发注册不会交错写坏同一个文件。 */\n private persistEnrollment(): void {\n const snapshot = JSON.stringify({ version: 1, ...this.enrollmentCell }, null, 2) + '\\n'\n this.enrollmentWriteTail = this.enrollmentWriteTail.then(async () => {\n const tempPath = this.pushRelayPath + '.' + randomBytes(6).toString('hex') + '.tmp'\n try {\n await mkdir(this.deps.dataDir, { recursive: true })\n await writeFile(tempPath, snapshot, { mode: 0o600 })\n await rename(tempPath, this.pushRelayPath)\n } catch {\n await unlink(tempPath).catch(() => {})\n // best-effort persistence; enrollment retries on next trigger\n }\n })\n }\n\n /** 等注册状态的写盘尾部排空;测试与收尾都用它取得确定性。 */\n async persisted(): Promise<void> {\n await this.enrollmentWriteTail\n }\n\n /** 进程收尾:等写盘尾部落盘,释放 sender。 */\n async dispose(): Promise<void> {\n this.widgetPush.dispose()\n this.liveActivityPush.dispose()\n const sender = this.cachedSender\n this.cachedSender = undefined\n await Promise.allSettled([\n this.enrollmentWriteTail,\n sender?.dispose?.() ?? Promise.resolve(),\n ])\n }\n\n // ---------- PushOutlet(HostBridge 消费) ----------\n\n widgetChanged(): void {\n this.widgetPush.changed()\n }\n\n liveActivityChanged(sessions: SessionSummary[]): void {\n this.liveActivityPush.changed(sessions)\n }\n\n /** 能力位必须说真话:只在 provider 完全就绪时才广告 push。 */\n isAvailable(): boolean {\n const resolved = this.resolvePushConfig(this.deps.config())\n if (!resolved.ok) return false\n // 中继模式要等注册产出 token 才算就绪;提前广告会让客户端压掉本地通知,\n // 而那条通知永远不会到。\n if (resolved.value.kind === 'relay' && !resolved.value.token) return false\n return true\n }\n\n /**\n * 把一个值得通知的事件扇到持有 APNs token 的已配对设备。规则:\n * - 有活跃 WebSocket 的设备跳过(它们已收到 WS 帧,会自己弹本地通知);\n * - 只考虑被授予 `notifications.register` 的设备——scope 被收窄的设备不得\n * 再收到离线推送(R1/P2 S→C 权限策略);\n * - 每设备按它自己注册的环境投递,沙盒与生产设备可共存;\n * - 设备按类别的静音开关抑制对应类别;\n * - 只有 APNs 的终态 Unregistered/ExpiredToken 才清理存储;\n * BadDeviceToken 可能是环境不匹配,保留可诊断性。\n */\n fanOut(sourceNotification: PushNotification): void {\n const notification = pushContent(\n { ...sourceNotification, hostAudience: this.deps.audience() ?? undefined },\n this.deps.config().push?.contentMode,\n )\n void (async () => {\n let resolved = this.resolvePushConfig(this.deps.config())\n if (!resolved.ok && resolved.reason === 'relay token not enrolled yet') {\n // 注册时带着 enrollKey 但注册还没跑完——立刻试一次再重新解析。\n await this.ensureRelayEnrolled(this.relayUrl())\n resolved = this.resolvePushConfig(this.deps.config())\n }\n if (!resolved.ok) return\n const devices = this.deps.devices()\n if (!devices) return\n const send = await this.senderFor(resolved.value)\n if (!send) return\n const transport = resolved.value.kind\n const connectedIds = new Set<string>()\n for (const connection of this.deps.connections()) {\n const id = connection.connectedDeviceId\n if (id && connection.suppressesAlertPush) connectedIds.add(id)\n }\n // 可观测性优先:推送失败曾经完全静默(受 debug 门控),现场无法诊断。\n // 现在每次派送与每次跳过都留一行平铺日志——只有类别与结果,绝不带消息体。\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 (this.deps.config().diagnostics?.debug === true) {\n this.deps.log(`push skip \"${deviceDisplayName(device)}\": notification permission not granted`)\n }\n return false\n }\n if (registration.categories?.[notification.category] === false) {\n if (this.deps.config().diagnostics?.debug === true) {\n this.deps.log(`push skip \"${deviceDisplayName(device)}\": 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 this.deps.log(`push(${transport}) ${notification.category}: no offline targets (connected=${connectedIds.size}, tokenized=${tokenized})`)\n return\n }\n // 自愈输入每次派送解析一次:实际发送所用的 URL,以及凭据是否来自零配置\n // 单元(显式配置的 relayToken 永不被改写)。\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 === this.enrollmentCell.token\n const hasEnrollKey = Boolean(this.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 this.deps.log(`push(${transport}) ${notification.category} → \"${deviceDisplayName(device)}\" [${registration.environment}] = ${outcome}${reason ? ' (' + reason + ')' : ''}`)\n if (shouldPrunePushToken(outcome, reason)) {\n devices.clearPushToken(device.deviceId)\n this.deps.log(`push: pruned stale token of \"${deviceDisplayName(device)}\" (${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:另一请求携带旧凭据的迟到 401 不得擦掉\n // 已被更早回调刷新过的 token。\n tokenStillCurrent: this.enrollmentCell.token === relayTokenUsed,\n })\n ) {\n // 中继不再认这个凭据。丢掉并从 enroll key 重新派生;\n // ensureRelayEnrolled 自己的节流避免并行 401 打爆端点,\n // senderFor 的配置指纹会在下次派送时用新 token 重建客户端。\n void this.healRelayCredential(relayUrl, relayTokenUsed, 'push relay credential rejected (HTTP 401); re-enrolling')\n }\n })\n .catch(() => {})\n }\n })()\n }\n\n // ---------- 零配置注册与自测(report remote 与 wire 帧消费) ----------\n\n /** 分布式 App 在 c2s.push.register 里呈上分发方的共享钥匙时触发。 */\n async enrollKey(enrollKey: string): Promise<void> {\n if (this.enrollmentCell.enrollKey !== enrollKey) {\n this.enrollmentCell.enrollKey = enrollKey\n }\n const configuredProvider = this.deps.config().push?.provider\n // 只在用户没有显式选择时才翻转。\n if (!configuredProvider || configuredProvider === 'none') {\n if (!this.enrollmentCell.autoRelay) {\n this.enrollmentCell.autoRelay = true\n this.deps.log('push relay mode auto-enabled by enrolled app')\n }\n }\n this.persistEnrollment()\n // 内联完成注册,让 register handler 看到最终就绪状态:第一条离线通知\n // 不应依赖一次重连。\n await this.ensureRelayEnrolled(this.relayUrl())\n }\n\n /** 设置页推送自测:强制一条合成通知走完整链路到每个已注册设备。 */\n async selfTest(): Promise<PushTestResult> {\n const resolved = this.resolvePushConfig(this.deps.config())\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 devices = this.deps.devices()\n const tokenized = (devices?.list() ?? []).filter((device) => device.apns !== undefined)\n if (!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 this.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: deviceDisplayName(device),\n environment: registration.environment,\n outcome,\n // 前 10 位十六进制让运维能核对存储的 token 与设备当前持有的一致\n // (重装会轮换 token)。\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 this.deps.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 /** 设置页中继自测:健康检查 + 注册往返,成功即完成一次注册。 */\n async relayTest(): Promise<RelayTestResult> {\n const push = this.deps.config().push ?? {}\n const configured = push.provider ?? 'none'\n const effective = configured === 'none' && this.enrollmentCell.autoRelay === true ? 'relay' : configured\n if (effective !== 'relay') {\n return {\n url: '',\n overall: 'failed',\n tokenIssued: false,\n steps: [{ id: 'health', ok: false, message: `当前推送模式不是中继(provider=${configured})。启用方式二选一:① 零配置——在 ios/project.yml 填写 DSPushEnrollKey(与服务器 RELAY_ENROLL_KEY 一致)并重新安装 App,打开 App 即自动启用;② 手动——将 push.provider 设为 relay 并填入 relayToken` }],\n }\n }\n const url = this.relayUrl()\n if (!/^https:\\/\\//i.test(url)) {\n return {\n url,\n overall: 'failed',\n tokenIssued: false,\n steps: [{ id: 'health', ok: false, message: 'relayUrl 必须是 https 地址:注册请求携带共享密钥,明文 HTTP 会把它暴露给链路上的任何节点' }],\n }\n }\n // 注册步骤需要一个身份:现在铸造,于是一次成功的自测同时就是一次完成的注册。\n if (!this.enrollmentCell.clientId && this.enrollmentCell.enrollKey) {\n this.enrollmentCell.clientId = 'u_' + randomBytes(16).toString('base64url')\n this.persistEnrollment()\n }\n return await runRelayProbe({\n url,\n clientId: this.enrollmentCell.clientId,\n enrollKey: this.enrollmentCell.enrollKey,\n manualToken: Boolean((push.relayToken ?? '').trim()),\n ...(this.deps.fetchImpl !== undefined ? { fetchImpl: this.deps.fetchImpl } : {}),\n onEnrolled: (token) => {\n this.enrollmentCell.token = token\n this.persistEnrollment()\n this.deps.log('push relay enrollment succeeded (via settings self-test)')\n },\n })\n }\n\n // ---------- 内部:配置解析 / 注册 / sender ----------\n\n private relayUrl(): string {\n return (this.deps.config().push?.relayUrl ?? '').trim() || DEFAULT_RELAY_URL\n }\n\n private resolvePushConfig(config: Config):\n | { ok: true; value: PushConfigSnapshot }\n | { ok: false; reason: string } {\n const push = config.push ?? {}\n // 已注册的分布式 App 在用户没有显式选择时自动启用中继模式。\n const configured = push.provider ?? 'none'\n const effectiveProvider = configured === 'none' && this.enrollmentCell.autoRelay === true ? 'relay' : configured\n if (effectiveProvider === 'relay') {\n const url = this.relayUrl()\n const token = (push.relayToken ?? '').trim() || this.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(this.deps.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 * 对运营方中继做零配置注册。幂等且结果缓存在持久化单元里;一次失败只留\n * 一行日志,直到配置指纹变化。\n */\n private async ensureRelayEnrolled(url: string): Promise<string | undefined> {\n // 注册体携带分发方的共享钥匙;配置错的 http:// relayUrl 绝不能让它明文\n // 泄露。(发送路径的请求已由 resolvePushConfig 把门,注册调用点没有。)\n if (!/^https:\\/\\//i.test(url.trim())) {\n this.deps.log('push relay enrollment refused: relayUrl must be an https URL')\n return undefined\n }\n if (this.enrollmentCell.token) return this.enrollmentCell.token\n const fingerprint = url + ':' + String(this.enrollmentCell.enrollKey ?? '')\n if (fingerprint !== this.enrollAttemptFor) {\n this.enrollAttemptFor = fingerprint\n this.enrollLastAttemptAt = 0\n }\n // 同一指纹反复失败:节流到一分钟一次,宕机的中继不会把每次通知变成一次\n // 外呼风暴,同时瞬时故障仍能快速恢复。\n if (Date.now() - this.enrollLastAttemptAt < ENROLL_RETRY_MS) return undefined\n this.enrollLastAttemptAt = Date.now()\n try {\n if (!this.enrollmentCell.clientId) {\n this.enrollmentCell.clientId = 'u_' + randomBytes(16).toString('base64url')\n this.persistEnrollment()\n }\n const client = new RelayClient({ url, debug: this.deps.config().diagnostics?.debug === true, log: this.deps.log })\n const token = await client.enroll(this.enrollmentCell.clientId, this.enrollmentCell.enrollKey ?? '')\n if (!token) {\n this.deps.log('push relay enrollment failed (' + url + '); will retry on next trigger')\n return undefined\n }\n this.enrollmentCell.token = token\n this.persistEnrollment()\n this.deps.log('push relay enrollment succeeded')\n return token\n } catch (error) {\n this.deps.log('push relay enrollment error: ' + String(error))\n return undefined\n }\n }\n\n /**\n * 按当前配置惰性构建 sender。坏配置(读不到的 .p8)只让该指纹失效并留\n * 一行日志,而不是每个事件都失败。\n */\n private async senderFor(resolved: PushConfigSnapshot): Promise<PushSender | undefined> {\n const fingerprint = JSON.stringify(resolved)\n if (this.cachedSender?.fingerprint === fingerprint) return this.cachedSender.send\n // 最近的失败只在短窗口内阻止重试:长期坏配置不能把每个事件都变成日志风暴,\n // 但同一配置在密钥文件补放之后 MUST 再获得一次机会。\n if (\n this.senderFailedFor?.fingerprint === fingerprint &&\n Date.now() - this.senderFailedFor.at < SENDER_FAILURE_RETRY_MS\n ) {\n return undefined\n }\n if (this.cachedSender) {\n await this.cachedSender.dispose?.().catch(() => {})\n this.cachedSender = undefined\n }\n if (resolved.kind === 'relay') {\n // resolvePushConfig 已保证单元里存在 token(配置 token 或已完成的注册)。\n const client = new RelayClient({\n url: resolved.url,\n token: resolved.token,\n debug: this.deps.config().diagnostics?.debug === true,\n log: this.deps.log,\n })\n this.cachedSender = {\n fingerprint,\n send: (request) => client.send(request),\n }\n this.deps.log('push relay enabled')\n } else {\n try {\n await readFile(expandHome(resolved.keyPath), 'utf8')\n } catch (error) {\n this.senderFailedFor = { fingerprint, at: Date.now() }\n this.deps.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: this.deps.config().diagnostics?.debug === true,\n log: this.deps.log,\n })\n this.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 this.deps.log('apns push enabled')\n }\n this.senderFailedFor = undefined\n return this.cachedSender.send\n }\n\n /**\n * 小组件总览推送:令牌新鲜、三项 scope 齐全、7 天内的设备,按环境去重后\n * 各投一次;中继拒绝凭据时自愈。\n */\n private async flushWidgetPushes(): Promise<void> {\n if (!this.deps.enabledNow()) return\n const resolved = this.resolvePushConfig(this.deps.config())\n if (!resolved.ok) return\n const devices = this.deps.devices()\n const send = await this.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 await this.healRelayCredential(resolved.value.url, resolved.value.token)\n }\n }\n }\n\n /** Live Activity 推送:与 alert 推送共用 sender 与自愈。 */\n private async sendLiveActivity(\n deviceToken: string,\n environment: ApnsEnvironment,\n notification: PushDelivery,\n ): Promise<SendOutcome> {\n if (!this.deps.enabledNow()) return { outcome: 'failed' }\n const resolved = this.resolvePushConfig(this.deps.config())\n if (!resolved.ok) return { outcome: 'failed' }\n const send = await this.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 await this.healRelayCredential(resolved.value.url, resolved.value.token)\n }\n return result\n }\n\n /**\n * 401 自愈(原先是三份拷贝:widget / liveActivity / fanOut)。\n * 中继不再认这个凭据:丢掉它,从 enroll key 重新派生。节流由\n * ensureRelayEnrolled 自己负责,并行 401 不会打爆端点。\n */\n private async healRelayCredential(\n url: string,\n token: string | undefined,\n logLine?: string,\n ): Promise<void> {\n if (token === undefined || this.enrollmentCell.token !== token) return\n if (!this.enrollmentCell.enrollKey) return\n this.enrollmentCell.token = undefined\n this.persistEnrollment()\n if (logLine !== undefined) this.deps.log(logLine)\n await this.ensureRelayEnrolled(url)\n }\n}\n","import { createServer as createHttpServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport { createServer as createHttpsServer } from 'node:https'\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\nexport interface PhoneServerTls {\n key: string\n cert: string\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 *\n * With `tls` the listener speaks HTTPS/WSS only (the LAN posture); without\n * it the listener is plain HTTP, which is reserved for the loopback Funnel\n * origin where tailscaled terminates TLS.\n */\nexport function createPhoneServer(handlers: PhoneServerHandlers, tls?: PhoneServerTls): Server {\n const onRequest = (req: IncomingMessage, res: ServerResponse): void => {\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 const server: Server = tls === undefined\n ? createHttpServer(onRequest)\n : createHttpsServer({ key: tls.key, cert: tls.cert, minVersion: 'TLSv1.2' }, onRequest)\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","/**\n * 传输协调器(TransportReconciler)——独立传输接入的公共协议,只写一次。\n *\n * 迁移前 LAN 与 Funnel 各有一份 40 行的 reconcile 闭包,做同一件事:算目标值 →\n * 与 appliedKey 比对 → 拆除前一个 → 起新的 → 更新状态,外加一条串行 tail 防\n * 并发。两份拷贝之间还飘着三处**刻意保留的差异**(见 TransportSpec)——本轮\n * 的目标是给 `apply()` 造出接口,不是统一传输的并发语义,因此差异原样保留并\n * 在此声明,而不是悄悄抹平。\n *\n * 每个传输一行声明(见 index.ts 的 createLocalTransport / createRemoteTransport),\n * 协调器只拥有差分、串行、拆除与状态发布。\n */\n\nimport type { Config } from './config.ts'\nimport type { DeepPilotReport } from './report-wire.ts'\n\n/** 状态的最小面:phase 必填,其余字段由各传输自己定义。 */\nexport interface TransportStatus {\n phase: string\n updatedAt: number\n}\n\n/** 目标值:参与差分的稳定对象。 */\nexport type TransportTarget = Record<string, unknown>\n\nexport interface TransportSpec<TInstance, TStatus extends TransportStatus> {\n /** 从当前配置算出的目标值;其 JSON 即差分键。 */\n keyOf(config: Config): TransportTarget\n /**\n * `true`:目标未启用时提前返回并直接置 disabled 状态(LAN 式)。\n * `false`:仍构造实例,由实例内部的 no-op 路径把状态置为 disabled(Funnel 式)。\n */\n skipWhenDisabled: boolean\n /**\n * appliedKey 的写入时机。LAN 在拆除旧 listener 之前写,Funnel 在 supervisor\n * 构造之后、异步 start 之前写——两者在「reconcile 等待期间又来一次\n * volatile-update」时行为不同。差异保留,见文件头说明。\n */\n applyKey: 'before-teardown' | 'after-construct'\n /** 构造实例:同步、即刻取得权威性(Funnel 的 appliedKey 在此之后写入)。 */\n construct(target: TransportTarget): TInstance\n /**\n * 启动实例:异步部分(TLS 加载、监听、拉起 helper)。可返回一个新实例来\n * 替换——LAN 的 listener 要等 TLS 身份就绪后才存在。抛错即走错误分支。\n */\n begin(instance: TInstance, guard: BeginGuard<TInstance>): Promise<TInstance | void>\n /** 拆掉一个实例。 */\n /** 拆除实例;`undefined` 表示没有可拆的(首轮或已拆)。 */\n stop(instance: TInstance | undefined): Promise<void>\n /** 目标未启用且 skipWhenDisabled 时的状态。 */\n disabledStatus(target: TransportTarget): TStatus\n /** 启动过程中的状态。 */\n startingStatus(target: TransportTarget): TStatus\n /** 启动失败时的状态;缺省表示该行没有错误分支,错误原样上抛。 */\n errorStatus?(error: unknown, target: TransportTarget): TStatus\n /** 状态查询:实例在场时问它;返回 undefined 表示「仍是我刚设的过渡态」。 */\n statusOf(instance: TInstance | undefined): TStatus | undefined\n /** 目标未启用时记的日志;缺省不记。 */\n disabledMessage?: string\n /** 启动失败时记的日志;缺省由协调器给一句通用的。 */\n failureMessage?: (error: unknown) => string\n}\n\n/**\n * begin 期间的守卫:让行在不复制协调器内部状态的前提下表达「我已被取代」。\n * LAN 原先在 TLS 加载后与 listen 后各查一次(appliedLocalKey / localServer),\n * 这两个检查对应 isCurrent() 与 owns()。\n */\nexport interface BeginGuard<TInstance> {\n /** 这次触发是否仍是当前配置(差分键未被后续触发改写)。 */\n isCurrent(): boolean\n /** 传入的实例是否仍是协调器持有的那个(未被后续触发替换)。 */\n owns(instance: TInstance): boolean\n /** 进程是否正在销毁。 */\n isDisposed(): boolean\n}\n\nexport class TransportReconciler<TInstance, TStatus extends TransportStatus> {\n private instance: TInstance | undefined\n private appliedKey: string | undefined\n private disposed = false\n private tail: Promise<void> = Promise.resolve()\n private currentStatus: TStatus\n\n constructor(\n private readonly spec: TransportSpec<TInstance, TStatus>,\n private readonly config: () => Config,\n private readonly log: (message: string) => void,\n initialStatus: TStatus,\n ) {\n this.currentStatus = initialStatus\n }\n\n /**\n * 当前状态;report 快照直接读它。实例不在场时返回协调器自己维护的状态\n * (disabled / error / 初始),不被 `statusOf(undefined)` 的缺省值覆盖——\n * 否则一次启动失败会把状态翻转回 idle。\n */\n status(): TStatus {\n if (this.instance === undefined) return this.currentStatus\n return this.spec.statusOf(this.instance) ?? this.currentStatus\n }\n\n /** 由 loader/volatile-update 触发:串行执行,前一个没完就不抢。 */\n scheduleReconcile(): void {\n this.tail = this.tail\n .then(() => this.reconcile())\n .catch((error) => this.log('reconcile failed: ' + String(error)))\n }\n\n /** 等当前在途的那一次完成;供 teardown 使用。 */\n async settled(): Promise<void> {\n await this.tail\n }\n\n /** 一次协调:差分 → 拆除 → 启动 → 状态。 */\n async reconcile(): Promise<void> {\n if (this.disposed) return\n const target = this.spec.keyOf(this.config())\n const nextKey = JSON.stringify(target)\n if (nextKey === this.appliedKey) return\n\n if (this.spec.applyKey === 'before-teardown') {\n this.appliedKey = nextKey\n }\n\n const previous = this.instance\n this.instance = undefined\n // 没有可拆的就不调用 stop:LAN 的 closeServer(undefined) 虽是安全路径,\n // 但不该让每个 spec 都为「空实例」写防御分支。\n if (previous !== undefined) await this.spec.stop(previous).catch(() => {})\n if (this.disposed) return\n\n if (target.enabled !== true && this.spec.skipWhenDisabled) {\n this.currentStatus = this.spec.disabledStatus(target)\n if (this.spec.disabledMessage !== undefined) this.log(this.spec.disabledMessage)\n return\n }\n\n this.currentStatus = this.spec.startingStatus(target)\n try {\n const constructed = this.spec.construct(target)\n this.instance = constructed\n if (this.spec.applyKey === 'after-construct') {\n this.appliedKey = nextKey\n }\n const guard: BeginGuard<TInstance> = {\n isCurrent: () => this.appliedKey === nextKey,\n owns: (instance) => this.instance === instance,\n isDisposed: () => this.disposed,\n }\n const replacement = await this.spec.begin(constructed, guard)\n if (replacement !== undefined) this.instance = replacement\n if (this.disposed) {\n await this.spec.stop(this.instance).catch(() => {})\n return\n }\n this.currentStatus = this.spec.statusOf(this.instance) ?? this.currentStatus\n } catch (error) {\n if (this.spec.errorStatus === undefined) throw error\n // 有错误分支的行(LAN 式):半成品实例要拆掉并清空,否则 status() 会\n // 继续问它要状态,把 error 覆盖成 online。Funnel 式没有错误分支,\n // 实例的自身状态机会把 phase 落到 error,因此保留。\n const partial = this.instance\n this.instance = undefined\n if (partial !== undefined) await this.spec.stop(partial).catch(() => {})\n this.currentStatus = this.spec.errorStatus(error, target)\n this.log(this.spec.failureMessage?.(error) ?? 'transport failed: ' + String(error))\n }\n }\n\n /** 进程收尾:标记销毁、拆掉实例、等在途的那一次完成。 */\n async dispose(): Promise<void> {\n this.disposed = true\n const active = this.instance\n this.instance = undefined\n await this.spec.stop(active).catch(() => {})\n await this.tail\n }\n}\n\n// ---------- 两个传输行 ----------\n\nimport type { Server } from 'node:http'\nimport { join } from 'node:path'\nimport {\n closeServer,\n createPhoneServer,\n listen,\n type PhoneServerHandlers,\n} from './phone-server.ts'\nimport {\n localListenError,\n normalizeLocalPort,\n} from './local-policy.ts'\nimport {\n RemoteSupervisor,\n normalizeRemoteHostname,\n type RemoteStatus,\n} from './remote-supervisor.ts'\nimport { normalizeFunnelConnectionLimit } from './funnel-policy.ts'\n\n/** LAN 行的状态即 report 的 `local` 段。 */\nexport type LocalStatus = DeepPilotReport['local']\n\n/** LAN 实例:一个(可能还在起步的)TLS listener。 */\ninterface LocalInstance {\n /** TLS 就绪后才填上;在此之前协调器仍持有这个占位实例。 */\n server: Server | undefined\n tlsFingerprint: string | undefined\n port: number\n /** 上线时刻:状态查询复用同一时间戳,不随查询漂移(与迁移前一致)。 */\n onlineAt: number\n}\n\n/** LAN 需要的外部能力:窄 handler 面、TLS 身份加载器、当前配置。 */\nexport interface LocalTransportDeps {\n handlers: PhoneServerHandlers\n config: () => Config\n /** 加载(必要时创建)LAN TLS 身份;由 apply() 持有,reconciler 不懂 TLS。 */\n tls: () => Promise<{ key: string; cert: string; fingerprint: string }>\n log: (message: string) => void\n}\n\n/**\n * LAN 传输:TLS-only,绑定 0.0.0.0 的稳定端口。\n *\n * 三处刻意保留的差异:`skipWhenDisabled: true`(未启用即提前返回并置\n * disabled)、`applyKey: 'before-teardown'`(拆除旧 listener 之前写键)、\n * 有错误分支(监听失败落到 `phase: 'error'`)。另有两处 supersede 检查原样\n * 保留:TLS 加载后查 `isCurrent()`,listen 后查 `owns()`。\n */\nexport function createLocalTransport(deps: LocalTransportDeps): TransportReconciler<LocalInstance, LocalStatus> {\n const spec: TransportSpec<LocalInstance, LocalStatus> = {\n keyOf: (config) => ({\n enabled: config.enabled === true && config.local?.enabled !== false,\n port: normalizeLocalPort(config.local?.port),\n }),\n skipWhenDisabled: true,\n applyKey: 'before-teardown',\n // 只占位:listener 要等 TLS 身份就绪后才存在。\n construct: (target) => ({ server: undefined, tlsFingerprint: undefined, port: normalizeLocalPort(target.port), onlineAt: Date.now() }),\n begin: async (instance, guard) => {\n const tls = await deps.tls()\n // 被更新的触发取代:不建 listener,状态停在 starting(与迁移前一致)。\n if (!guard.isCurrent() || guard.isDisposed()) return\n const port = instance.port\n const server = createPhoneServer(deps.handlers, { key: tls.key, cert: tls.cert })\n instance.server = server\n instance.tlsFingerprint = tls.fingerprint\n await listen(server, port, '0.0.0.0')\n // listen 期间被取代:拆掉这个半成品,不要让它在端口上继续听着。\n if (!guard.owns(instance) || guard.isDisposed()) {\n instance.server = undefined\n await closeServer(server)\n return\n }\n instance.onlineAt = Date.now()\n deps.log(`local transport listening on https://0.0.0.0:${port} (tls fingerprint ${tls.fingerprint})`)\n },\n stop: async (instance) => {\n if (instance?.server === undefined) return\n const server = instance.server\n instance.server = undefined\n await closeServer(server)\n },\n disabledStatus: (target) => ({\n phase: 'disabled', port: normalizeLocalPort(target.port), endpoints: [], updatedAt: Date.now(),\n }),\n startingStatus: (target) => ({\n phase: 'starting', port: normalizeLocalPort(target.port), endpoints: [], updatedAt: Date.now(),\n }),\n errorStatus: (error, target) => ({\n phase: 'error',\n port: normalizeLocalPort(target.port),\n endpoints: [],\n message: localListenError(error, normalizeLocalPort(target.port)),\n updatedAt: Date.now(),\n }),\n disabledMessage: 'local transport disabled',\n failureMessage: (error) => 'local transport failed: ' + localListenError(error, 0),\n statusOf: (instance) => {\n if (instance === undefined || instance.server === undefined) return undefined\n return {\n phase: 'online',\n port: instance.port,\n endpoints: [],\n tlsFingerprint: instance.tlsFingerprint,\n updatedAt: instance.onlineAt,\n }\n },\n }\n return new TransportReconciler<LocalInstance, LocalStatus>(spec, deps.config, deps.log, {\n phase: deps.config().enabled === true && deps.config().local?.enabled !== false ? 'starting' : 'disabled',\n port: normalizeLocalPort(deps.config().local?.port),\n endpoints: [],\n updatedAt: Date.now(),\n })\n}\n\n/** Funnel 需要的外部能力:窄 handler 面、loopback origin 地址、数据目录。 */\nexport interface RemoteTransportDeps {\n handlers: PhoneServerHandlers\n config: () => Config\n /** loopback origin 的地址;未就绪时该行不协调。 */\n originURL: () => string | undefined\n dataDir: string\n log: (message: string) => void\n}\n\n/**\n * Funnel 传输:loopback origin + Tailscale Funnel helper。\n *\n * 三处刻意保留的差异:`skipWhenDisabled: false`(未启用仍构造 supervisor,\n * 由其内部 no-op 把状态置 disabled)、`applyKey: 'after-construct'`\n * (supervisor 构造后、异步 start 之前写键)、没有错误分支(supervisor 自己\n * 的状态机负责 phase)。\n */\nexport function createRemoteTransport(deps: RemoteTransportDeps): TransportReconciler<RemoteSupervisor, RemoteStatus> {\n const fallbackStatus = (): RemoteStatus => ({\n provider: 'tailscale-funnel',\n phase: deps.config().remote?.enabled === true ? 'stopped' : 'disabled',\n updatedAt: Date.now(),\n })\n const spec: TransportSpec<RemoteSupervisor, RemoteStatus> = {\n keyOf: (config) => {\n const remoteConfig = config.remote ?? {}\n const remotePort: 443 | 8443 | 10000 = remoteConfig.funnelPort === 8443 || remoteConfig.funnelPort === 10000\n ? remoteConfig.funnelPort\n : 443\n return {\n enabled: config.enabled === true && remoteConfig.enabled === true && remoteConfig.provider === 'tailscale-funnel',\n hostname: normalizeRemoteHostname(remoteConfig.hostname),\n statePath: remoteConfig.statePath?.trim() || join(deps.dataDir, 'tailscale'),\n helperPath: remoteConfig.helperPath?.trim() || undefined,\n funnelPort: remotePort,\n maxConnectionsPerSource: normalizeFunnelConnectionLimit(remoteConfig.maxConnectionsPerSource),\n }\n },\n skipWhenDisabled: false,\n applyKey: 'after-construct',\n construct: (target) => new RemoteSupervisor({\n enabled: target.enabled === true,\n hostname: String(target.hostname),\n statePath: String(target.statePath),\n ...(target.helperPath !== undefined ? { helperPath: String(target.helperPath) } : {}),\n funnelPort: target.funnelPort as 443 | 8443 | 10000,\n maxConnectionsPerSource: Number(target.maxConnectionsPerSource),\n log: deps.log,\n }),\n begin: async (supervisor) => {\n const originURL = deps.originURL()\n // origin 尚未就绪:这一轮不启动(与迁移前 originURL === undefined 时\n // 直接返回一致;键已写入,origin 就绪后的那次触发会把它建起来)。\n if (originURL === undefined) return\n await supervisor.start(originURL)\n },\n stop: async (supervisor) => {\n if (supervisor === undefined) return\n await supervisor.dispose()\n },\n disabledStatus: () => ({ provider: 'tailscale-funnel', phase: 'disabled', updatedAt: Date.now() }),\n startingStatus: () => ({ provider: 'tailscale-funnel', phase: 'stopped', updatedAt: Date.now() }),\n statusOf: (supervisor) => supervisor?.status() ?? fallbackStatus(),\n }\n return new TransportReconciler<RemoteSupervisor, RemoteStatus>(spec, deps.config, deps.log, fallbackStatus())\n}\n","/**\n * at-most-once dispatch journal:prompt 投递与非 prompt 变更的**同一个** module。\n *\n * 迁移前 `prompt-delivery.ts` 与 `mutation-journal.ts` 是同一份耐久协议的两份\n * 拷贝(盘点结论:key/expired/save 骨架字节级相同,mutation 甚至反向 import\n * prompt 的 validSendId,共享已从错误方向发生)。两者的差别集中在六个面:\n * 指纹覆盖范围、条目字段、回执形状、id 校验、lookup、落盘容器格式——全部收进\n * 注入的 codec;核心只留耐久协议。\n *\n * 核心拥有:key 派生、原子写盘(temp + fsync + rename + 目录 fsync)、加载与\n * 逐字段校验、保留清扫、容量、healthy 降级、在途去重、opener 单例。\n *\n * healthy 的唯一来源是**构造期的解析失败**(文件损坏,续写会写坏格式);\n * 运行期的落盘失败只影响当次投递,下次投递重新尝试落盘。两者曾经共用同一个\n * 标志位,一次瞬时磁盘错误就让整个进程的所有投递永久短路到 DSH 重启\n * (issue #20 / #26)。\n *\n * codec 拥有:一次投递的全部「方言」。它同时是两个 adapter——prompt 回执与\n * mutation 结果——因此这条缝是真的,不是假想的。\n */\n\nimport { createHash, randomUUID } from 'node:crypto'\nimport { existsSync, readFileSync, mkdirSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, statSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { validSendId } from './connection-policy.ts'\nimport { ERROR_CODES, type WireErrorCode } from './wire-errors.ts'\n\n/** 落盘条目:两个通用字段 + codec 私有字段。 */\nexport interface JournalEntry {\n fingerprint: string\n createdAt: number\n [field: string]: unknown\n}\n\n/** operation 的结果:成功带值,失败带 wire 错误码。 */\nexport type OperationResult<T = unknown> =\n | { ok: true; value: T }\n | { ok: false; code: WireErrorCode; message?: string }\n\n/**\n * 一切「不看条目就能定」的结果类别。codec 用一个方法把它们翻译成自己的方言,\n * 而不是让核心知道任何一方的形状。\n */\nexport type DispatchOutcome =\n /** 命中既有条目(重放)。 */\n | { kind: 'replay'; entry: JournalEntry }\n /** 同一 id 搭不同内容。 */\n | { kind: 'mismatch' }\n /** 构造期解析失败:journal 已永久降级,本次进程不再投递。 */\n | { kind: 'unavailable' }\n /** id 的纪元前缀超出保留窗口。 */\n | { kind: 'expired' }\n /** 条目数已达容量上限。 */\n | { kind: 'full' }\n /** 刚跑完的那一次:operation 的结果原样带出(不标 replayed)。 */\n | { kind: 'ran'; entry: JournalEntry; result: OperationResult }\n /** operation 抛错:条目保持 unknown,且不得自动重试。 */\n | { kind: 'crashed' }\n /**\n * 预留条目时落盘失败——上游**没有**被调用,但无从判断 rename 是否已经\n * 生效(save() 可能在 rename 之后才抛),因此条目留在内存里按 unknown 处理。\n */\n | { kind: 'reserve-failed' }\n /** id 形状不合法(仅 mutation 变体开启这道守卫)。 */\n | { kind: 'invalid-id' }\n\nexport interface DispatchCodec<TRequest = unknown, TResult = unknown> {\n /** 实例身份:opener 单例键的一部分(含 persistValues 等变体差异)。 */\n readonly identity: string\n /** 请求指纹。prompt 覆盖 [sessionId, content];mutation 只覆盖 content。 */\n fingerprint(request: TRequest): string\n /** 预留条目时写入的 codec 字段(fingerprint/createdAt 由核心补)。 */\n reserve(request: TRequest, id: string): Record<string, unknown>\n /** operation 成功后就地更新条目。 */\n accepted(entry: JournalEntry, id: string, value: unknown): void\n /** operation 失败后就地更新条目。 */\n rejected(entry: JournalEntry, id: string, code: WireErrorCode): void\n /** 把结果类别翻译成调用方言。 */\n resultOf(outcome: DispatchOutcome, id: string): TResult\n /** id 非法时是否先拒掉(mutation 是;prompt 由 wire 层保证,故否)。 */\n readonly requiresValidId?: boolean\n /** lookup 的匹配规则;缺省表示该实例不提供 lookup。 */\n matches?(entry: JournalEntry, request: unknown): boolean\n /** lookup 未命中时回什么(prompt 要区分 notFound / expired)。 */\n miss?(id: string, expired: boolean): TResult\n /** 落盘容器 → 内存条目表;任何不合法都抛错(核心转成 healthy=false)。 */\n parse(raw: unknown): Record<string, JournalEntry>\n /** 内存条目表 → 落盘容器。 */\n serialize(entries: Record<string, JournalEntry>): unknown\n}\n\nexport interface DispatchJournalOptions<TRequest = unknown, TResult = unknown> {\n codec: DispatchCodec<TRequest, TResult>\n path?: string\n /** 落盘体积上限:prompt 8MB、mutation 4MB(由条目实际大小决定,不统一)。 */\n maxFileBytes?: number\n capacity?: number\n retentionMs?: number\n /**\n * 并发重复是否搭同在途那次。prompt 是(重复方拿到同一个最终回执);\n * mutation 否(重复方立刻拿到 unknown → E_INTERNAL)。两者都由对等快照钉住。\n */\n joinInFlight?: boolean\n /**\n * 落盘失败的诊断输出。由调用方注入它已有的 logger;缺省即静默。\n * 只打阶段与 errno,绝不打条目内容或消息体(plugin 的日志禁令)。\n */\n log?: (message: string) => void\n /**\n * 目录 fsync 里「对 fd 调用 fsync」这一步的覆盖点,缺省即 `fsyncSync`。\n *\n * 存在的唯一理由是可测:Linux CI 上复现不出 Windows 的 EPERM。注入点刻意\n * 停在 fd 这一层而不是替换整个目录 fsync——容忍 EPERM 的判断必须留在真实\n * 路径里被测到,换掉整函数就等于把待测逻辑一起换掉了。\n */\n fsyncFileDescriptor?: (fd: number) => void\n}\n\nconst DEFAULT_CAPACITY = 10_000\nconst DEFAULT_RETENTION_MS = 7 * 24 * 3600 * 1000\n/** 比保留窗口多宽限 5 分钟:边界附近的条目不会被反复删了又写。 */\nconst SWEEP_GRACE_MS = 5 * 60 * 1000\n\n/**\n * 目录 fsync 的三个「平台不支持」码。\n *\n * Windows 上 `openSync(dir, 'r')` 成功但 `fsyncSync(dirfd)` 必定抛错(社区实测\n * 报 EPERM,issue #20 / #26);EISDIR / EINVAL 是同一现象的其他平台变体。\n * 这三个码在本调用点都不代表数据损坏:文件内容已在 rename 之前 fsync 过,且\n * rename 在同一目录内是原子的,跳过的只是目录项的额外耐久性保证。\n */\nconst TOLERATED_DIR_FSYNC_CODES: ReadonlySet<string> = new Set(['EPERM', 'EISDIR', 'EINVAL'])\n\n/** errno 优先,取不到就退回错误本身的字符串(诊断用,不参与控制流)。 */\nfunction errnoOf(error: unknown): string {\n const code = (error as NodeJS.ErrnoException | null)?.code\n return typeof code === 'string' ? code : String(error)\n}\n\n/** 这类错误是否属于「该平台不支持目录 fsync」而非真的写坏了。 */\nexport function isToleratedDirectoryFsyncError(error: unknown): boolean {\n return TOLERATED_DIR_FSYNC_CODES.has(errnoOf(error))\n}\n\n/**\n * 目录 fsync:把 rename 造成的目录项变更推给磁盘。\n *\n * 按 errno 而非 `process.platform` 判断:WSL / Wine 之类环境下平台名并不可靠,\n * 而 errno 才是真正决定「这个平台支不支持」的信号(issue #26 给的两种建议里,\n * 按 errno 的那种才是对的)。其余 errno(EIO、ENOSPC……)照旧抛出。\n */\nexport function fsyncDirectory(dirPath: string, fsync: (fd: number) => void = fsyncSync): void {\n const fd = openSync(dirPath, 'r')\n try {\n fsync(fd)\n } catch (error) {\n if (!isToleratedDirectoryFsyncError(error)) throw error\n } finally {\n closeSync(fd)\n }\n}\n\n/** Durable at-most-once dispatch. Unknown outcomes are never automatically retried. */\nexport class DispatchJournal<TRequest = unknown, TResult = unknown> {\n private entries: Record<string, JournalEntry> = Object.create(null)\n private inFlight = new Map<string, Promise<TResult>>()\n /** 只由构造期的解析失败置位,见下方 catch;运行期落盘失败不碰它。 */\n private healthy = true\n private readonly maxFileBytes: number\n private readonly capacity: number\n private readonly retentionMs: number\n private readonly joinInFlight: boolean\n\n constructor(private readonly options: DispatchJournalOptions<TRequest, TResult>) {\n this.maxFileBytes = options.maxFileBytes ?? 8 * 1024 * 1024\n this.capacity = options.capacity ?? DEFAULT_CAPACITY\n this.retentionMs = options.retentionMs ?? DEFAULT_RETENTION_MS\n this.joinInFlight = options.joinInFlight ?? true\n const path = options.path\n if (path === undefined || !existsSync(path)) return\n try {\n if (statSync(path).size > this.maxFileBytes) throw new Error('oversized journal')\n const parsed = JSON.parse(readFileSync(path, 'utf8')) as { version?: unknown; entries?: unknown }\n if (parsed.version !== 1 || !Array.isArray(parsed.entries) || parsed.entries.length > this.capacity) {\n throw new Error('invalid journal')\n }\n const loaded = this.options.codec.parse(parsed.entries)\n for (const key of Object.keys(loaded)) this.entries[key] = loaded[key]!\n } catch {\n // 唯一会把 healthy 拉黑的地方:文件读不出来或不合法。宁可整个进程都拒绝\n // 投递,也不按一个可能是错的格式续写(续写会污染此后每一次回放)。\n this.healthy = false\n }\n }\n\n private key(deviceId: string, id: string): string {\n return createHash('sha256').update(JSON.stringify([deviceId, id])).digest('hex')\n }\n\n /** id 的纪元前缀是否还在保留窗口内(未来 5 分钟以上同样算非法)。 */\n private expired(id: string, now = Date.now()): boolean {\n const age = now - Number(id.slice(0, 13))\n return age > this.retentionMs || age < -SWEEP_GRACE_MS\n }\n\n private save(): void {\n const path = this.options.path\n if (path === undefined) return\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 })\n const temp = path + '.' + randomUUID() + '.tmp'\n const fd = openSync(temp, 'wx', 0o600)\n try {\n writeFileSync(fd, JSON.stringify({ version: 1, entries: this.options.codec.serialize(this.entries) }))\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n renameSync(temp, path)\n fsyncDirectory(dirname(path), this.options.fsyncFileDescriptor)\n }\n\n /**\n * 落盘一次,失败只报不降级。\n *\n * 与 `healthy` 的分工:`healthy` 只由构造期的解析失败置位,运行期的磁盘错误\n * 不再拉黑整个进程——此前一次 save() 失败就让本进程余下的所有投递永久返回\n * unknown,直到 DSH 重启(issue #20 / #26)。现在只影响当次投递,下一次\n * dispatch 会重新尝试。\n */\n private persist(): boolean {\n try {\n this.save()\n return true\n } catch (error) {\n this.options.log?.('journal 落盘失败,本次投递按未确认处理,下次投递会重新尝试:' + errnoOf(error))\n return false\n }\n }\n\n /** 查询既有回执;`request` 交给 codec 的 matches 判定(缺省即不提供 lookup)。 */\n lookup(deviceId: string, id: string, request?: unknown): TResult | undefined {\n const codec = this.options.codec\n if (codec.matches === undefined) return undefined\n if (!this.healthy) return codec.resultOf({ kind: 'unavailable' }, id)\n const entry = this.entries[this.key(deviceId, id)]\n if (entry !== undefined && codec.matches(entry, request)) return codec.resultOf({ kind: 'replay', entry }, id)\n return codec.miss?.(id, this.expired(id)) ?? codec.resultOf({ kind: 'unavailable' }, id)\n }\n\n /**\n * 幂等投递。未知结果绝不自动重试:条目保持 unknown,重放时由 codec 决定\n * 调用方看到什么。\n */\n async dispatch(deviceId: string, id: string, request: TRequest, operation: () => Promise<OperationResult>): Promise<TResult> {\n const codec = this.options.codec\n // id 守卫在最前(与迁移前 mutation 的次序一致):形状非法的请求不落盘。\n if (codec.requiresValidId === true && !validSendId(id)) {\n return codec.resultOf({ kind: 'invalid-id' }, id)\n }\n const key = this.key(deviceId, id)\n const fingerprint = codec.fingerprint(request)\n const existing = this.entries[key]\n if (existing !== undefined) {\n if (existing.fingerprint !== fingerprint) return codec.resultOf({ kind: 'mismatch' }, id)\n // 搭同在途那次(prompt):并发重复共享一次上游调用,拿同一最终回执。\n const pending = this.inFlight.get(key)\n if (this.joinInFlight && pending !== undefined) return pending\n return codec.resultOf({ kind: 'replay', entry: existing }, id)\n }\n if (!this.healthy) return codec.resultOf({ kind: 'unavailable' }, id)\n if (this.expired(id)) return codec.resultOf({ kind: 'expired' }, id)\n\n const now = Date.now()\n for (const [entryKey, entry] of Object.entries(this.entries)) {\n if (now - entry.createdAt > this.retentionMs + SWEEP_GRACE_MS && !this.inFlight.has(entryKey)) {\n delete this.entries[entryKey]\n }\n }\n if (Object.keys(this.entries).length >= this.capacity) return codec.resultOf({ kind: 'full' }, id)\n\n // 先落盘预约再跑上游:进程在两次之间死掉,重启后也能识别「结果未知」。\n const entry: JournalEntry = { fingerprint, createdAt: Number(id.slice(0, 13)), ...codec.reserve(request, id) }\n this.entries[key] = entry\n if (!this.persist()) {\n // 预约没落盘就不能跑上游。条目**保留**在内存里:save() 可能是在 rename\n // 之后才抛的,磁盘上或许已经有这条 unknown,抹掉等于把它从表里除名。\n return codec.resultOf({ kind: 'reserve-failed' }, id)\n }\n\n const run = (async (): Promise<TResult> => {\n let ran: OperationResult\n try {\n ran = await operation()\n if (ran.ok) codec.accepted(entry, id, ran.value)\n else codec.rejected(entry, id, ran.code)\n } catch {\n // 上游可能在传输失败前已经接受:条目保持 unknown,绝不自动重试。\n return codec.resultOf({ kind: 'crashed' }, id)\n }\n // 结果落盘失败不回滚条目:operation 已经跑过,回滚等于把一次可能已生效的\n // 上游调用从表里除名。下次投递若写成功,会把整表(含本条目)一起写回去。\n this.persist()\n // 刚跑完的那一次:operation 的结果原样带出,不标 replayed。\n return codec.resultOf({ kind: 'ran', entry, result: ran }, id)\n })()\n this.inFlight.set(key, run)\n try { return await run } finally { this.inFlight.delete(key) }\n }\n\n /** 等所有在途投递结束;供进程收尾。 */\n async settled(): Promise<void> {\n while (this.inFlight.size > 0) {\n await Promise.all([...this.inFlight.values()])\n }\n }\n}\n\n// ---------- opener ----------\n\nconst journals = new Map<string, DispatchJournal<never, never>>()\n\n/**\n * 按 path + codec 身份取单例。身份进键是必要的:同一路径用不同 codec/persistValues\n * 打开必须得到不同实例——迁移前的键只有 path,`persistValues` 因此会被静默忽略。\n */\nexport function openDispatchJournal<TRequest, TResult>(\n options: DispatchJournalOptions<TRequest, TResult>,\n): DispatchJournal<TRequest, TResult> {\n const { path, codec } = options\n if (path === undefined) {\n return new DispatchJournal<TRequest, TResult>(options)\n }\n const cacheKey = path + '|' + codec.identity\n const cached = journals.get(cacheKey)\n if (cached !== undefined) return cached as unknown as DispatchJournal<TRequest, TResult>\n const journal = new DispatchJournal<TRequest, TResult>(options)\n journals.set(cacheKey, journal as unknown as DispatchJournal<never, never>)\n return journal\n}\n\n// ---------- prompt 投递 codec ----------\n\n/** prompt 投递的回执:手机侧按 clientSendId 对账。 */\nexport type DeliveryStatus = 'accepted' | 'rejected' | 'unknown' | 'notFound' | 'expired'\nexport interface DeliveryReceipt {\n clientSendId: string\n status: DeliveryStatus\n userSeq?: number\n code?: string\n}\n\n/** prompt 的落盘条目:回执内嵌,sessionId 单独存一份供 lookup 比对。 */\ninterface PromptEntry extends JournalEntry {\n sessionId: string\n receipt: DeliveryReceipt\n}\n\n/** 受理即 accepted;四种会被 APNs 终态清理的失败码之外一律原样上抛。 */\nconst PROMPT_RECEIPT_CODES = ['E_BUSY', 'E_NOT_FOUND', 'E_PROTOCOL', 'E_UNSUPPORTED'] as const\n\n/**\n * prompt 投递方言:\n * - 指纹覆盖 [sessionId, content](同一条 prompt 换会话重发视为不同请求);\n * - 并发重复搭同在途那次(joinInFlight),因此重复方拿到同一最终回执;\n * - 有 lookup,且 sessionId 不匹配即视为未命中;\n * - 落盘是 [key, entry] 二元组数组(历史格式,零迁移)。\n */\nexport const promptDeliveryCodec: DispatchCodec<\n { sessionId: string; content: unknown },\n DeliveryReceipt\n> & { identity: string } = {\n identity: 'prompt-delivery',\n fingerprint: (request) => createHash('sha256')\n .update(JSON.stringify([request.sessionId, request.content]))\n .digest('hex'),\n reserve: (request, id) => ({\n sessionId: request.sessionId,\n receipt: { clientSendId: id, status: 'unknown' },\n }),\n accepted: (entry, id, value) => {\n const receipt = entry.receipt as DeliveryReceipt\n entry.receipt = { clientSendId: id, status: 'accepted', userSeq: value as number }\n },\n rejected: (entry, id, code) => {\n const receipt = entry.receipt as DeliveryReceipt\n entry.receipt = { clientSendId: id, status: 'rejected', code }\n },\n resultOf: (outcome, id) => {\n switch (outcome.kind) {\n case 'replay':\n case 'ran': return (outcome.entry.receipt ?? { clientSendId: id, status: 'unknown' }) as DeliveryReceipt\n case 'mismatch': return { clientSendId: id, status: 'rejected', code: 'E_PROTOCOL' }\n case 'unavailable':\n case 'crashed':\n case 'reserve-failed': return { clientSendId: id, status: 'unknown' }\n case 'expired': return { clientSendId: id, status: 'expired' }\n case 'full': return { clientSendId: id, status: 'rejected', code: 'E_BUSY' }\n case 'invalid-id': return { clientSendId: id, status: 'rejected', code: 'E_PROTOCOL' }\n }\n },\n // prompt 不做 id 守卫:wire 层已在 validateRequest/行内校验保证形状。\n requiresValidId: false,\n matches: (entry, request) => entry.sessionId === request,\n miss: (id, expired) => ({ clientSendId: id, status: expired ? 'expired' : 'notFound' }),\n parse: (raw) => {\n const out: Record<string, JournalEntry> = Object.create(null)\n for (const [key, value] of raw as Array<[string, PromptEntry]>) {\n if (typeof key !== 'string' || !/^[a-f0-9]{64}$/.test(key) || !value || typeof value.sessionId !== 'string' ||\n !Number.isFinite(value.createdAt) || typeof value.fingerprint !== 'string' ||\n !validSendId(value.receipt?.clientSendId) ||\n !['accepted', 'rejected', 'unknown'].includes(value.receipt.status)) throw new Error('invalid entry')\n if (!/^[a-f0-9]{64}$/.test(value.fingerprint) ||\n value.createdAt !== Number(value.receipt.clientSendId.slice(0, 13)) ||\n (value.receipt.status === 'accepted' && !Number.isSafeInteger(value.receipt.userSeq)) ||\n (value.receipt.status === 'rejected' && !(PROMPT_RECEIPT_CODES as readonly string[]).includes(String(value.receipt.code)))) {\n throw new Error('invalid receipt')\n }\n out[key] = value\n }\n return out\n },\n serialize: (entries) => Object.entries(entries).map(([key, entry]) => [key, entry]),\n}\n\n// ---------- schedule/fork mutation codec ----------\n\n/** mutation 的结果:replayed 让调用方知道这是重放而非新执行。 */\nexport type MutationErrorCode = WireErrorCode\n\nexport type MutationOperationResult<T> =\n | { ok: true; value: T }\n | { ok: false; code: MutationErrorCode; message?: string }\n\nexport type MutationDispatchResult<T> =\n | { ok: true; value?: T; replayed?: boolean }\n | { ok: false; code: MutationErrorCode; message?: string; replayed?: boolean }\n\ninterface MutationEntry extends JournalEntry {\n status: 'accepted' | 'rejected' | 'unknown'\n code?: MutationErrorCode\n value?: unknown\n}\n\n/**\n * mutation 方言(schedule 与 fork 共用,fork 打开 persistValues):\n * - 有 id 守卫,且在最前面(形状非法的 clientRequestId 不落盘);\n * - 并发重复不搭在途那次:重复方立刻拿到 unknown → E_INTERNAL「不得自动重试」;\n * - 成功值只在 persistValues 时落盘——fork 需要重启后仍能重放 sessionId,\n * schedule 的 authoritative 资源由客户端重新拉取,不在此复制第二份;\n * - 落盘是对象数组(历史格式,零迁移)。\n */\nexport function scheduleMutationCodec(persistValues: boolean): DispatchCodec<unknown, MutationDispatchResult<unknown>> & { identity: string } {\n const isErrorCode = (value: unknown): value is MutationErrorCode =>\n typeof value === 'string' && value in ERROR_CODES\n return {\n identity: 'mutation:' + (persistValues ? 'persist' : 'memory'),\n fingerprint: (request) => createHash('sha256').update(JSON.stringify(request)).digest('hex'),\n reserve: () => ({ status: 'unknown' }),\n accepted: (entry, _id, value) => {\n entry.status = 'accepted'\n if (persistValues) entry.value = value\n },\n rejected: (entry, _id, code) => {\n entry.status = 'rejected'\n entry.code = code\n },\n resultOf: (outcome, id) => {\n switch (outcome.kind) {\n case 'ran': return outcome.result as MutationDispatchResult<unknown>\n case 'replay': {\n const entry = outcome.entry as MutationEntry\n if (entry.status === 'accepted') return { ok: true, value: entry.value, replayed: true }\n if (entry.status === 'rejected' && entry.code !== undefined) return { ok: false, code: entry.code, replayed: true }\n return { ok: false, code: 'E_INTERNAL', message: 'mutation outcome is unknown; do not retry automatically', replayed: true }\n }\n case 'mismatch': return { ok: false, code: 'E_PROTOCOL', message: 'clientRequestId was reused with different content', replayed: true }\n case 'invalid-id': return { ok: false, code: 'E_PROTOCOL', message: 'invalid clientRequestId' }\n case 'unavailable': return { ok: false, code: 'E_INTERNAL', message: 'mutation journal unavailable' }\n case 'expired': return { ok: false, code: 'E_PROTOCOL', message: 'clientRequestId is outside the retry window' }\n case 'full': return { ok: false, code: 'E_BUSY', message: 'mutation journal is full' }\n case 'reserve-failed': return { ok: false, code: 'E_INTERNAL', message: 'mutation journal could not persist the request' }\n case 'crashed': return { ok: false, code: 'E_INTERNAL', message: 'mutation outcome is unknown; do not retry automatically' }\n }\n },\n requiresValidId: true,\n // mutation 没有 lookup:权威资源由客户端重新拉取。\n parse: (raw) => {\n const out: Record<string, JournalEntry> = Object.create(null)\n for (const value of raw as MutationEntry[]) {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('invalid mutation entry')\n const entry = value as Record<string, unknown>\n if (typeof entry.fingerprint !== 'string' || !/^[a-f0-9]{64}$/.test(entry.fingerprint) ||\n typeof entry.createdAt !== 'number' || !Number.isFinite(entry.createdAt) ||\n !['accepted', 'rejected', 'unknown'].includes(String(entry.status))) throw new Error('invalid mutation entry')\n if (entry.status === 'rejected' && !isErrorCode(entry.code)) throw new Error('invalid mutation code')\n const key = String((value as { key?: unknown }).key)\n if (!/^[a-f0-9]{64}$/.test(key)) throw new Error('invalid mutation key')\n out[key] = {\n fingerprint: entry.fingerprint as string,\n createdAt: entry.createdAt as number,\n status: entry.status as MutationEntry['status'],\n ...(isErrorCode(entry.code) ? { code: entry.code } : {}),\n ...(persistValues && entry.value !== undefined ? { value: entry.value } : {}),\n }\n }\n return out\n },\n serialize: (entries) => Object.entries(entries).map(([key, entry]) => ({ key, ...entry })),\n }\n}\n","import type { SessionSummary } from './protocol.ts'\nimport type { DeviceScope } from './device-auth.ts'\nimport type { PushNotification } from './protocol.ts'\nimport type { WireErrorCode } from './wire-errors.ts'\n\n/* Stable bridge-facing structural types mapped to rc.2 controllers by\n * DshApiProxy. */\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 fork?(req: RpcRequestLike<{ sessionId: string; atSeq?: number }>): Promise<RpcResponseLike<{ sessionId: 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 /** Complete projection baseline for one session; null when it is gone. */\n projections(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ asOfSeq: number; values: Record<string, unknown> } | null>>\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 unarchiveSession?(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ archivedSessionIds: string[] }>>\n}\n\nexport type ScheduleKind = 'after' | 'at' | 'every' | 'daily' | 'weekly' | 'cron'\n\nexport interface ScheduleTaskViewLike {\n id: string\n kind: ScheduleKind\n title: string\n prompt: string\n scheduledAt: string\n state: 'scheduled' | 'overdue'\n deliveryMode: 'host'\n afterSeconds?: number\n everySeconds?: number\n time?: string\n timeZone?: string\n weekdays?: number[]\n expression?: string\n}\n\nexport interface ScheduleHistoryViewLike {\n id: string\n records: Array<{\n scheduledAt: string\n deliveredAt: string\n messageId: string\n prompt?: string\n }>\n earlierRecordsUnavailable: boolean\n earlierRecordsPruned?: boolean\n retention: { days: number; records: number }\n nextBefore?: string\n}\n\nexport interface ScheduleApiLike {\n list(req: RpcRequestLike<{ sessionId: string }>):\n Promise<RpcResponseLike<{ sessionId: string; tasks: ScheduleTaskViewLike[] }>>\n history(req: RpcRequestLike<{ sessionId: string; id: string; limit: number; before?: string }>):\n Promise<RpcResponseLike<{ sessionId: string; history: ScheduleHistoryViewLike }>>\n create(req: RpcRequestLike<{ sessionId: string; title: string; prompt: string; [key: string]: unknown }>):\n Promise<RpcResponseLike<ScheduleTaskViewLike>>\n update(req: RpcRequestLike<{ sessionId: string; id: string; expected: unknown; title?: string; prompt?: string; change?: unknown }>):\n Promise<RpcResponseLike<{ id: string; updated: boolean; record?: ScheduleTaskViewLike; code?: string }>>\n delete(req: RpcRequestLike<{ sessionId: string; id: string }>):\n Promise<RpcResponseLike<{ id: string; deleted: boolean; code?: 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\n/**\n * Bridge 方法的结果。失败直接携带 wire 错误码(error vocabulary 见\n * wire-errors.ts):调用方(wire-registry 的行)原样透给手机,不再经过\n * kind 中间层翻译。\n */\nexport type ModelBridgeResult<T> =\n | { ok: true; value: T }\n | { ok: false; code: WireErrorCode; message: string }\n\nexport type SessionManagementResult<T> =\n | { ok: true; value: T }\n | { ok: false; code: WireErrorCode; 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 *\n * `parentSessionId` alone is NOT a subagent signal: a session forked from\n * another one (c2s.session.fork) also carries it, as fork lineage, while\n * being an ordinary top-level session the phone must show. Only the host's\n * explicit `origin` marks a worker — mirror the same rule already used for\n * the live mux stream (see dsh-api-proxy.ts's `isSubagent` derivation).\n */\nexport function isSubagentRow(row: PhoneSessionRow): boolean {\n return row.origin === 'subagent';\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 /** Internal Host identity hint; never serialized into the phone protocol. */\n isSubagent?: boolean\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 callId?: 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 schedule?: ScheduleApiLike\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","/**\n * 宿主能力探测(host capability probe)的唯一属主。\n *\n * `welcome.capabilities` 的每一位都必须由这里的一张表推导;此前同一条事实\n * 存在两份——getter 里的表达式与各 Bridge 方法内的 `typeof` 再探测——\n * 已经漂移过两次:`models` 位要求 `models && selectModel`,而\n * `c2s.session.models` 只需要 `models`(门过严);`schedules` 位只探\n * `list && create`,而五个 schedule 方法只要求服务存在(部分 Host 上会 TypeError)。\n *\n * 规则:一位一行,表达式取「该位所闸的帧真正需要的最小依赖」。位与帧的绑定\n * 由 wire 注册表的 `capability` 字段声明(见 wire-registry.ts),host-bridge\n * 只负责把表算出来,不再各自判断。\n */\n\nimport type { ApiProxyLike, PushOutlet } from './host-api.ts'\nimport type { WelcomeCapabilities } from './protocol.ts'\n\n/** 由宿主表达式挣得的位;表在 HOST_CAPABILITY_PROBES。 */\nexport type ProbedCapability =\n | 'models'\n | 'sessionManagement'\n | 'sessionFork'\n | 'sessionRestore'\n | 'projectSelection'\n | 'schedules'\n\n/** 每位一行:Host 上必须存在的依赖。缺失即该位为 false,相关帧回 E_UNSUPPORTED。 */\nexport const HOST_CAPABILITY_PROBES: Record<ProbedCapability, (proxy: ApiProxyLike) => boolean> = {\n // PROTOCOL.md:模型列表必须由 Host 的 session.models 动态提供。切换模型另由\n // c2s.session.selectModel 自己的探测兜底(缺 selectModel 时回 E_UNSUPPORTED)。\n models: (proxy) => typeof proxy.sessions.models === 'function',\n sessionManagement: (proxy) =>\n typeof proxy.sessions.rename === 'function' &&\n typeof proxy.workspace?.archiveSession === 'function',\n sessionFork: (proxy) => typeof proxy.sessions.fork === 'function',\n sessionRestore: (proxy) => typeof proxy.workspace?.unarchiveSession === 'function',\n projectSelection: (proxy) =>\n typeof proxy.workspace?.list === 'function' &&\n typeof proxy.workspace?.create === 'function',\n // 五个 schedule 帧都只要求 Schedule 服务存在;历史上按 list&&create 探测的取值\n // 会在只实现了部分方法的 Host 上把位压成 false,而方法体内又只判服务存在。\n schedules: (proxy) => proxy.schedule !== undefined,\n}\n\n/** 由 Bridge 自身恒真的位(见 BRIDGE_INVARIANT_CAPABILITIES)。 */\nexport type BridgeInvariantCapability = (typeof BRIDGE_INVARIANT_CAPABILITIES)[number]\n\n/** 由推送出口就绪状态决定的位(APNs 凭据或中继注册)。 */\nexport type OutletCapability = 'push'\n\n/**\n * 门禁必须留在 handler 内的位。`push` 是唯一一个:零配置注册(enrollKey)\n * 必须先于能力门执行,否则首次注册恰好发生在推送尚未就绪时就会被拒,\n * 分布式构建的自动启用链就此断掉(见 wire-push.ts 的同名说明)。\n */\nexport const HANDLER_GATED_CAPABILITIES = ['push'] as const satisfies ReadonlyArray<OutletCapability>\n\n/** 行上的能力门可以引用三类位中的任意一种。 */\nexport type CapabilityGate = ProbedCapability | BridgeInvariantCapability | OutletCapability\n\n/**\n * Bridge 自身恒为真的位:与宿主无关,列出是为了让读者一眼看出 welcome 上哪些位\n * 不是从 Host 推导的。缺失这些位中的任何一个都意味着 Bridge 实现被改动,\n * 改这里不改帧的 gate 属于遗漏。\n */\nexport const BRIDGE_INVARIANT_CAPABILITIES = [\n 'historyPaging',\n 'replay',\n 'approvals',\n 'questions',\n 'pendingSnapshot',\n 'promptDelivery',\n 'notifyAllCategories',\n 'widgetPush',\n 'liveActivityPush',\n 'deviceRevoke',\n] as const satisfies ReadonlyArray<keyof WelcomeCapabilities>\n\n/**\n * 按当前 apiProxy 与推送出口算出 welcome 能力位。`push` 位描述「当前离线推送\n * 可用」:APNs 凭据或中继注册就绪才为 true,否则客户端不应压下自己的本地通知。\n */\nexport function capabilityBits(\n proxy: ApiProxyLike,\n pushOutlet: PushOutlet | undefined,\n): WelcomeCapabilities {\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: HOST_CAPABILITY_PROBES.models(proxy),\n sessionManagement: HOST_CAPABILITY_PROBES.sessionManagement(proxy),\n sessionFork: HOST_CAPABILITY_PROBES.sessionFork(proxy),\n sessionRestore: HOST_CAPABILITY_PROBES.sessionRestore(proxy),\n projectSelection: HOST_CAPABILITY_PROBES.projectSelection(proxy),\n schedules: HOST_CAPABILITY_PROBES.schedules(proxy),\n push: pushOutlet?.isAvailable() === true,\n widgetPush: true,\n liveActivityPush: true,\n deviceRevoke: true,\n }\n}\n","import {\n openDispatchJournal,\n promptDeliveryCodec,\n scheduleMutationCodec,\n type DeliveryReceipt,\n type MutationDispatchResult,\n} from './dispatch-journal.ts'\nimport { randomUUID } from 'node:crypto'\nimport type { Envelope, MessageProjection, NotifyCategory, PendingSnapshotPayload, PushNotification, SessionEventKind, SessionSummary, SessionTodoItem, SessionTodoStatus, SessionUsageStats, WelcomeCapabilities } 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 ScheduleHistoryViewLike,\n ScheduleTaskViewLike,\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 DEFAULT_HISTORY_PAGE_MESSAGES,\n MAX_HISTORY_PAGE_MESSAGES,\n MIN_TAIL_MESSAGES,\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 type { DispatchJournal } from './dispatch-journal.ts'\nimport { pushScopeFor } from './connection-policy.ts'\nimport { capabilityBits } from './host-capabilities.ts'\nimport { wireCodeFor, wireErrorOf, type WireErrorCode } from './wire-errors.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 toolArguments?: string\n}\n\ninterface PendingQuestion {\n rpcId: string\n sessionId: string\n questions: unknown\n}\n\n/**\n * 失败结果直接携带 wire 错误码(error vocabulary 见 wire-errors.ts)。\n *\n * 迁移前这里有 kind 中间层('not-found' | 'busy' | 'conflict' | 'invalid'…),\n * 由 5 个映射函数在「Host code ↔ kind ↔ E_*」之间来回翻译,其中\n * E_BUSY→conflict→E_BUSY 的往返已证明有损。现在每个域查一次表,调用方拿到的\n * 就是手机上会看到的错误码。\n */\nexport type ScheduleBridgeResult<T> =\n | { ok: true; value: T; replayed?: boolean }\n | { ok: false; code: WireErrorCode; message: string; replayed?: boolean }\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 activeTools = new Map<string, Map<string, string>>()\n private approvals = new Map<string, PendingApproval>()\n private questions = new Map<string, PendingQuestion>()\n private archivedSessionIds = new Set<string>()\n /** Mirrors archived rows from the last sessions.list so the phone can browse\n * and restore them. Excluded from `summaries` and from the live broadcast. */\n private archivedSummaries = new Map<string, SessionSummary>()\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: DispatchJournal<{ sessionId: string; content: unknown }, DeliveryReceipt>\n readonly scheduleMutations: DispatchJournal<unknown, MutationDispatchResult<unknown>>\n readonly forkMutations: DispatchJournal<unknown, MutationDispatchResult<unknown>>\n\n constructor(\n private readonly apiProxy: ApiProxyLike,\n private readonly historyBufferMax: number = MAX_RING_DEFAULT,\n deliveryJournalPath?: string,\n scheduleJournalPath?: string,\n forkJournalPath?: string,\n /** 三个 journal 的落盘失败诊断输出;缺省即静默。不打任何消息体。 */\n private readonly log?: (message: string) => void,\n ) {\n // 三个实例是同一个 module 的三次配置:条目方言由 codec 决定(prompt 回执 /\n // schedule 结果 / fork 结果带持久化 value),落盘路径各自独立、互不影响。\n // log 必须在**首次**构造时就带上:openDispatchJournal 是按 path+codec 身份\n // 缓存的单例,事后补传不会生效。\n this.promptDeliveries = openDispatchJournal({\n path: deliveryJournalPath,\n codec: promptDeliveryCodec,\n joinInFlight: true,\n maxFileBytes: 8 * 1024 * 1024,\n log: this.log,\n })\n this.scheduleMutations = openDispatchJournal({\n path: scheduleJournalPath,\n codec: scheduleMutationCodec(false),\n joinInFlight: false,\n maxFileBytes: 4 * 1024 * 1024,\n log: this.log,\n })\n this.forkMutations = openDispatchJournal({\n path: forkJournalPath,\n codec: scheduleMutationCodec(true),\n joinInFlight: false,\n maxFileBytes: 4 * 1024 * 1024,\n log: this.log,\n })\n }\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 /**\n * welcome 能力位。委托 host-capabilities.ts 的探测表:此前同一条事实在这里\n * 和各方法体内各存一份,已经漂移过两次(models 位过严、schedules 位与\n * schedule 方法的探测不同源)。\n */\n get capabilities(): WelcomeCapabilities {\n return capabilityBits(this.apiProxy, this.pushOutlet)\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 ((args.category === 'turn.completed' || args.category === 'session.error') &&\n 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/schedule-changed':\n this.record('s2c.schedule.changed', {})\n break\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 if (frame.isSubagent === true) this.subagentSessionIds.add(sessionId);\n if (this.subagentSessionIds.has(sessionId)) break;\n this.noteActivity(sessionId, event);\n this.captureAssistantText(sessionId, event);\n const projection = projectEvent(sessionId, event);\n this.captureActivity(sessionId, event, projection?.data.tool as { name?: string; summary?: string } | undefined);\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; callId?: 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 if (p.callId) void this.loadApprovalArguments(p.approvalId, p.callId);\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 // Archived sessions stay out of the live list and its broadcast so\n // existing clients keep their current behaviour; they are mirrored here\n // and served on demand through c2s.sessions.archived.\n const nextArchived = new Map<string, SessionSummary>();\n for (const row of response.result.value.items ?? []) {\n if (isSubagentRow(row)) this.subagentSessionIds.add(row.sessionId);\n if (this.subagentSessionIds.has(row.sessionId)) continue\n const summary = toSummary(row, this.approvals, this.questions, workspaceBySession.get(row.sessionId));\n if (this.archivedSessionIds.has(row.sessionId)) {\n nextArchived.set(row.sessionId, { ...summary, archived: true });\n continue\n }\n next.set(row.sessionId, summary);\n }\n for (const [id, calls] of this.activeTools) {\n const row = next.get(id);\n if (!row || (row.status !== 'running' && !row.pendingApproval && !row.pendingQuestion)) this.activeTools.delete(id);\n else row.activity = [...calls.values()].at(-1) ?? null;\n }\n // Worker identity is immutable for this bridge lifetime. A stale list or\n // a removed worker must not erase identity learned from the event stream.\n this.summaries = next;\n this.archivedSummaries = nextArchived;\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 captureActivity(sessionId: string, event: SessionEventLike, tool?: { name?: string; summary?: string }): void {\n const row = this.summaries.get(sessionId);\n if (!row) return;\n const data = event.data as { callId?: string } | undefined;\n if (event.type === 'tool/call' && data?.callId) {\n const calls = this.activeTools.get(sessionId) ?? new Map<string, string>();\n const detail = [tool?.name, tool?.summary].filter(Boolean).join(': ');\n calls.set(data.callId, Array.from(detail).slice(0, 160).join(''));\n if (calls.size > 64) calls.delete(calls.keys().next().value!);\n this.activeTools.set(sessionId, calls);\n } else if (event.type === 'tool/result' && data?.callId) {\n this.activeTools.get(sessionId)?.delete(data.callId);\n } else if (event.type === 'turn/start' || event.type === 'turn/end') {\n this.activeTools.delete(sessionId);\n } else return;\n const activity = [...(this.activeTools.get(sessionId)?.values() ?? [])].at(-1) ?? null;\n if (row.activity === activity) return;\n row.activity = activity;\n // Tool progress must not reorder the session list or trigger Widget pushes.\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 * Archived rows from the last sessions.list, newest first. Served only on\n * demand so the live session list and its broadcast keep their shape for\n * clients that predate `c2s.sessions.archived`.\n */\n listArchivedSessions(): SessionSummary[] {\n return [...this.archivedSummaries.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 ...(pending.toolArguments !== undefined ? { toolArguments: pending.toolArguments } : {}),\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 /** Resolve only the exact invocation in this session; never guess from the latest tool. */\n private async loadApprovalArguments(requestId: string, callId: string): Promise<void> {\n const pending = this.approvals.get(requestId);\n if (!pending) return;\n try {\n const response = await this.apiProxy.sessions.history({\n rpcId: randomUUID(),\n payload: { sessionId: pending.sessionId, maxMessages: 200 },\n });\n if (this.disposed || this.approvals.get(requestId) !== pending || !response.result?.ok) return;\n const event = (response.result.value.events ?? []).map(row => row.event).find(event => {\n const data = event.data as { callId?: string; name?: string } | undefined;\n return event.type === 'tool/call' && data?.callId === callId && data?.name === pending.toolName;\n });\n const args = (event?.data as { arguments?: unknown } | undefined)?.arguments;\n if (typeof args !== 'string' || !args.trim()) return;\n pending.toolArguments = args;\n this.record('s2c.pending.approval', {\n requestId, sessionId: pending.sessionId, toolName: pending.toolName,\n summary: pending.reason, riskLevel: riskOf(pending.toolName), toolArguments: args,\n });\n } catch {\n // Keep the approval answerable with explicitly unavailable execution details.\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 // DSH exposes a complete per-session projection baseline; fold it\n // into the summary row when the phone opens a session so the first paint\n // does not depend on list-row hints or frames missed while offline.\n void this.refreshProjections(sessionId);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Pull one session's projection baseline and fold every key\n * through applyProjection — unknown keys are ignored there, `null` means the\n * session no longer exists, and any failure degrades to a diagnostic: opening\n * a session must never fail because a baseline could not be read.\n */\n private async refreshProjections(sessionId: string): Promise<void> {\n try {\n const response = await this.apiProxy.sessions.projections({\n rpcId: randomUUID(),\n payload: { sessionId },\n });\n if (this.disposed) return;\n const result = response.result;\n if (!result) return;\n if (!result.ok) {\n this.diagnostic('sessions.projections failed: ' + result.error.code);\n return;\n }\n const baseline = result.value;\n if (baseline === null || baseline === undefined) return;\n for (const [key, value] of Object.entries(baseline.values ?? {})) {\n this.applyProjection(sessionId, key, value);\n }\n } catch (error) {\n this.diagnostic('sessions.projections threw: ' + String((error as { message?: unknown })?.message ?? error));\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, code: 'E_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, code: 'E_INTERNAL', message: 'model catalog returned no result' }\n if (!response.result.ok) return wireErrorOf('model', response.result.error)\n return { ok: true, value: projectSessionModels(response.result.value) }\n } catch (error) {\n return { ok: false, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'model selection returned no result' }\n if (!response.result.ok) return wireErrorOf('model', response.result.error)\n return { ok: true, value: { ...response.result.value.selected } }\n } catch (error) {\n return { ok: false, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'session rename returned no result' }\n if (!response.result.ok) return wireErrorOf('session', 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, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'session archive returned no result' }\n if (!response.result.ok) return wireErrorOf('session', 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, code: 'E_INTERNAL', message: String(error) }\n }\n }\n\n async unarchiveSession(sessionId: string): Promise<SessionManagementResult<true>> {\n const unarchive = this.apiProxy.workspace?.unarchiveSession\n if (typeof unarchive !== 'function') {\n return { ok: false, code: 'E_UNSUPPORTED', message: 'session restore unavailable on this host version' }\n }\n try {\n const response = await unarchive.call(this.apiProxy.workspace, {\n rpcId: randomUUID(),\n payload: { sessionId },\n })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'session restore returned no result' }\n if (!response.result.ok) return wireErrorOf('session', response.result.error)\n this.archivedSessionIds = new Set(\n (response.result.value.archivedSessionIds ?? []).map(String),\n )\n // Rebuild both mirrors from the Host instead of hand-moving the row:\n // refreshSummaries re-emits s2c.sessions.delta, which carries the restored\n // session back to the client's live list.\n await this.refreshSummaries()\n return { ok: true, value: true }\n } catch (error) {\n return { ok: false, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'session cancel returned no result' }\n if (!response.result.ok) return wireErrorOf('session', response.result.error)\n return { ok: true, value: true }\n } catch (error) {\n return { ok: false, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'workspace list returned no result' }\n if (!response.result.ok) return wireErrorOf('session', response.result.error)\n return { ok: true, value: (response.result.value.items ?? []).map(projectWorkspace) }\n } catch (error) {\n return { ok: false, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'workspace create returned no result' }\n if (!response.result.ok) return wireErrorOf('session', 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, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'directory list returned no result' }\n if (!response.result.ok) return wireErrorOf('session', response.result.error)\n return { ok: true, value: response.result.value }\n } catch (error) {\n return { ok: false, code: 'E_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, code: 'E_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, code: 'E_INTERNAL', message: 'directory picker returned no result' }\n if (!response.result.ok) return wireErrorOf('session', response.result.error)\n return { ok: true, value: response.result.value.path }\n } catch (error) {\n return { ok: false, code: 'E_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 forkSession(\n deviceId: string,\n payload: { clientRequestId: string; sessionId: string; atSeq?: number },\n ): Promise<ScheduleBridgeResult<{ sessionId: string }>> {\n const fork = this.apiProxy.sessions.fork\n if (typeof fork !== 'function') return { ok: false, code: 'E_UNSUPPORTED', message: 'session fork unavailable on this host version' }\n if (!this.summaries.has(payload.sessionId)) return { ok: false, code: 'E_NOT_FOUND', message: 'session not found' }\n if (this.archivedSessionIds.has(payload.sessionId) || this.subagentSessionIds.has(payload.sessionId)) {\n return { ok: false, code: 'E_PROTOCOL', message: 'archived or subagent sessions cannot be forked' }\n }\n const result = await this.forkMutations.dispatch(\n deviceId,\n payload.clientRequestId,\n { sessionId: payload.sessionId, ...(payload.atSeq !== undefined ? { atSeq: payload.atSeq } : {}) },\n async () => {\n const response = await fork.call(this.apiProxy.sessions, {\n rpcId: randomUUID(),\n payload: { sessionId: payload.sessionId, ...(payload.atSeq !== undefined ? { atSeq: payload.atSeq } : {}) },\n })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'session fork returned no result' }\n if (!response.result.ok) return wireErrorOf('schedule', response.result.error)\n return { ok: true, value: { sessionId: response.result.value.sessionId } }\n },\n )\n if (result.ok) {\n await this.refreshSummaries()\n return { ok: true, value: result.value as { sessionId: string }, replayed: result.replayed }\n }\n return { ok: false, code: result.code, message: result.message ?? result.code, replayed: result.replayed }\n }\n\n async listSchedules(sessionId: string): Promise<ScheduleBridgeResult<ScheduleTaskViewLike[]>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, code: 'E_UNSUPPORTED', message: 'schedules unavailable on this host version' }\n try {\n const response = await schedule.list({ rpcId: randomUUID(), payload: { sessionId } })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule list returned no result' }\n if (!response.result.ok) return wireErrorOf('schedule', response.result.error)\n return { ok: true, value: response.result.value.tasks }\n } catch (error) {\n return { ok: false, code: 'E_INTERNAL', message: String(error) }\n }\n }\n\n async scheduleHistory(\n sessionId: string,\n id: string,\n limit: number,\n before?: string,\n ): Promise<ScheduleBridgeResult<ScheduleHistoryViewLike>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, code: 'E_UNSUPPORTED', message: 'schedules unavailable on this host version' }\n try {\n const response = await schedule.history({\n rpcId: randomUUID(),\n payload: { sessionId, id, limit, ...(before !== undefined ? { before } : {}) },\n })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule history returned no result' }\n if (!response.result.ok) return wireErrorOf('schedule', response.result.error)\n return { ok: true, value: response.result.value.history }\n } catch (error) {\n return { ok: false, code: 'E_INTERNAL', message: String(error) }\n }\n }\n\n async createSchedule(\n deviceId: string,\n payload: Record<string, unknown> & { sessionId: string; clientRequestId: string; title: string; prompt: string },\n ): Promise<ScheduleBridgeResult<ScheduleTaskViewLike>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, code: 'E_UNSUPPORTED', message: 'schedules unavailable on this host version' }\n const { clientRequestId, sessionId, ...request } = payload\n const result = await this.scheduleMutations.dispatch(\n deviceId,\n clientRequestId,\n { sessionId, request },\n async () => {\n const response = await schedule.create({ rpcId: randomUUID(), payload: { sessionId, ...request } })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule create returned no result' }\n if (!response.result.ok) return wireErrorOf('schedule', response.result.error)\n return { ok: true, value: response.result.value }\n },\n )\n if (result.ok) {\n this.record('s2c.schedule.changed', {})\n return { ok: true, value: result.value as ScheduleTaskViewLike, replayed: result.replayed }\n }\n return { ok: false, code: result.code, message: result.message ?? result.code, replayed: result.replayed }\n }\n\n async updateSchedule(\n deviceId: string,\n payload: Record<string, unknown> & { sessionId: string; id: string; clientRequestId: string; expected: unknown },\n ): Promise<ScheduleBridgeResult<ScheduleTaskViewLike>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, code: 'E_UNSUPPORTED', message: 'schedules unavailable on this host version' }\n const { clientRequestId, ...request } = payload\n const result = await this.scheduleMutations.dispatch(\n deviceId,\n clientRequestId,\n request,\n async () => {\n const response = await schedule.update({ rpcId: randomUUID(), payload: request })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule update returned no result' }\n if (!response.result.ok) return wireErrorOf('schedule', response.result.error)\n const value = response.result.value\n if (value.updated !== true || value.record === undefined) {\n return { ok: false, code: wireCodeFor('schedule', value.code), message: value.code ?? 'schedule update rejected' }\n }\n return { ok: true, value: value.record }\n },\n )\n if (result.ok) {\n this.record('s2c.schedule.changed', {})\n return { ok: true, value: result.value as ScheduleTaskViewLike, replayed: result.replayed }\n }\n return { ok: false, code: result.code, message: result.message ?? result.code, replayed: result.replayed }\n }\n\n async deleteSchedule(\n deviceId: string,\n payload: { sessionId: string; id: string; clientRequestId: string },\n ): Promise<ScheduleBridgeResult<{ id: string; deleted: true }>> {\n const schedule = this.apiProxy.schedule\n if (schedule === undefined) return { ok: false, code: 'E_UNSUPPORTED', message: 'schedules unavailable on this host version' }\n const result = await this.scheduleMutations.dispatch(\n deviceId,\n payload.clientRequestId,\n { sessionId: payload.sessionId, id: payload.id },\n async () => {\n const response = await schedule.delete({\n rpcId: randomUUID(),\n payload: { sessionId: payload.sessionId, id: payload.id },\n })\n if (!response.result) return { ok: false, code: 'E_INTERNAL', message: 'schedule delete returned no result' }\n if (!response.result.ok) return wireErrorOf('schedule', response.result.error)\n if (response.result.value.deleted !== true) {\n return { ok: false, code: 'E_NOT_FOUND', message: response.result.value.code ?? 'schedule not found' }\n }\n return { ok: true, value: { id: response.result.value.id, deleted: true as const } }\n },\n )\n if (result.ok) {\n this.record('s2c.schedule.changed', {})\n return { ok: true, value: result.value as { id: string; deleted: true }, replayed: result.replayed }\n }\n return { ok: false, code: result.code, message: result.message ?? result.code, replayed: result.replayed }\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, code: 'E_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 wireErrorOf('session', 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, code: 'E_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\n/**\n * 尾部条数收敛到 [MIN_TAIL_MESSAGES, MAX_HISTORY_PAGE_MESSAGES]。\n * 区间与 wire 行校验(tailCount 1..10000、limit 1..500)共用投影 module 的\n * 常量——「一页能要多少条消息」本是一条规则,原先散在三处。\n */\nfunction clampTail(n: number): number {\n if (!Number.isFinite(n)) return DEFAULT_HISTORY_PAGE_MESSAGES;\n return Math.max(MIN_TAIL_MESSAGES, Math.min(MAX_HISTORY_PAGE_MESSAGES, 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/** 把 Host 的模型目录投影成 wire 形状:字段全部收敛为字符串,缺省不补位。 */\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 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 HostWireStreamLike {\n open(endpoint: string, payload: unknown, uplink: undefined, peer: undefined, signal: AbortSignal): Promise<AsyncIterable<unknown>>\n}\n\ninterface HostGatewayLike {\n wireStream: HostWireStreamLike\n}\n\ninterface ClientTransportHooksLike {\n fetch(input: string, init: RequestInit): Promise<Response>\n openStream(endpoint: string, payload: unknown, signal: AbortSignal): AsyncIterable<unknown>\n ownsHost: true\n}\n\n/** The rc.2 Client sends relative RPC paths to its in-process carrier. */\nexport function inProcessRemoteRequest(input: string, init: RequestInit): Request {\n // The shared Fetch handler routes by pathname and never performs a network\n // request. Node's Request still requires an absolute URL for relative paths.\n return new Request(new URL(input, 'http://localhost/'), init)\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 DshRemoteInteractionHandlers {\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, undefined, undefined, 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 startDshRemoteInteractions(\n hostCtx: Context,\n handlers: DshRemoteInteractionHandlers,\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 Host connection is unavailable')\n if (gateway === undefined) throw new Error('DSH 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(inProcessRemoteRequest(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 * Adapter for the DSH rc.2 controller API.\n *\n * DeepPilot's phone protocol deliberately speaks one stable in-process\n * `apiProxy` vocabulary. This adapter maps it to the current public\n * Session/Workspace controllers and Gateway-backed Remote Events, keeping\n * the phone protocol isolated from the Host API.\n */\nimport { randomUUID } from 'node:crypto'\nimport type { Context } from '@deepseek-ai/cordis'\nimport {\n startDshRemoteInteractions,\n type RemoteApprovalRequest,\n type RemoteQuestionRequest,\n} from './dsh-remote-interactions.ts'\nimport { historyWindow, normalizePageLimit } from './host-event-projection.ts'\nimport type {\n ApiProxyLike,\n DirectoryListingLike,\n HistoryResult,\n HostSessionModels,\n MuxFrameLike,\n PhoneSessionRow,\n ScheduleHistoryViewLike,\n ScheduleTaskViewLike,\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 fork(request: { sessionId: string; atSeq?: number }): Promise<{ sessionId: 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 /** Non-activating projection baseline for one session. */\n projections(request: { sessionId: string }, signal?: AbortSignal):\n Promise<{ asOfSeq: number; values: Record<string, unknown> } | null>\n}\n\ninterface WorkspaceControllerLike {\n create(request: { path: string }): Promise<{ workspace: unknown; created: boolean }>\n archiveSession(request: { sessionId: string }): Promise<{ archivedSessionIds: readonly string[] }>\n unarchiveSession(request: { sessionId: string }): Promise<{ archivedSessionIds: readonly string[] }>\n follow(signal: AbortSignal): AsyncIterable<{ type: string; value?: unknown }>\n}\n\ninterface ScheduleControllerLike {\n list(request: { sessionId: string }): Promise<readonly unknown[]>\n history(request: { sessionId: string; id: string; limit: number; before?: string }): Promise<unknown>\n create(sessionId: string, request: Record<string, unknown>, signal?: AbortSignal): Promise<unknown>\n update(request: Record<string, unknown>, signal?: AbortSignal): Promise<unknown>\n delete(request: { sessionId: string; id: string }, signal?: AbortSignal): Promise<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 a Host waterfall result. */\n map(value: unknown): unknown\n}\n\n/** Which first-answer-wins interaction a phone may surface. */\nexport type DshInteractionKind = 'approval' | 'question'\n\nexport interface DshApiProxyOptions {\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 adapter with the shape HostBridge consumes. */\nexport class DshApiProxy implements ApiProxyLike {\n private readonly session: SessionControllerLike\n private readonly workspaceController: WorkspaceControllerLike | undefined\n private scheduleController: ScheduleControllerLike | undefined\n private scheduleApi: ApiProxyLike['schedule'] | 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: DshApiProxyOptions = {}) {\n const session = ctx.get('sessionController') as SessionControllerLike | undefined\n if (session === undefined) throw new Error('DSH sessionController is unavailable')\n this.session = session\n this.workspaceController = ctx.get('workspaceController') as WorkspaceControllerLike | undefined\n // A profile without the optional workspace service cannot restore a\n // session; keep the phone capability bit honest.\n if (this.workspaceController === undefined) delete this.workspace?.unarchiveSession\n this.directoryPicker = ctx.get('directoryPickerController') as DirectoryPickerControllerLike | undefined\n this.shouldSurfaceInteraction = options.shouldSurfaceInteraction ?? (() => true)\n this.resolveSchedule()\n }\n\n /**\n * Resolve the optional Schedule service lazily, on every read.\n *\n * The bridge is built from a `ctx.inject` on sessionController / connection\n * / typertGateway, and `schedule` is deliberately NOT in that list: it only\n * exists when the user enables the optional Automation tasks bundle. On a\n * DSH 0.2.0 host those three services become ready well before\n * ScheduleService finishes its own async init, so a value captured here in\n * the constructor stayed `undefined` for the bridge's whole lifetime and\n * welcome advertised `schedules=false` even with the bundle mounted.\n *\n * Once resolved the controller is kept: services are not torn down and\n * rebuilt underneath a live bridge, so re-resolving per call would be pure\n * overhead.\n */\n private resolveSchedule(): void {\n if (this.scheduleController !== undefined) return\n const controller = this.ctx.get('schedule') as ScheduleControllerLike | undefined\n if (controller === undefined) return\n this.scheduleController = controller\n this.scheduleApi = this.createScheduleApi(controller)\n }\n\n get schedule(): ApiProxyLike['schedule'] {\n this.resolveSchedule()\n return this.scheduleApi\n }\n\n private createScheduleApi(controller: ScheduleControllerLike): NonNullable<ApiProxyLike['schedule']> {\n return {\n list: async (request) => this.call(async () => ({\n sessionId: request.payload!.sessionId,\n tasks: (await controller.list({ sessionId: request.payload!.sessionId })).map(toScheduleTask),\n })),\n history: async (request) => this.call(async () => {\n const value = await controller.history({\n sessionId: request.payload!.sessionId,\n id: request.payload!.id,\n limit: request.payload!.limit,\n ...(request.payload!.before !== undefined ? { before: request.payload!.before } : {}),\n }) as Record<string, unknown>\n if (typeof value.code === 'string') {\n throw Object.assign(new Error(String(value.code)), { code: value.code })\n }\n return { sessionId: request.payload!.sessionId, history: toScheduleHistory(value) }\n }),\n create: async (request) => this.call(async () => {\n const { sessionId, ...createRequest } = request.payload!\n return toScheduleTask(await controller.create(sessionId, createRequest))\n }),\n update: async (request) => this.call(async () => {\n const payload = request.payload!\n const result = await controller.update({\n ...payload,\n expected: toScheduleExpected(payload.expected),\n }) as Record<string, unknown>\n return {\n id: String(result.id ?? payload.id),\n updated: result.updated === true,\n ...(result.record !== undefined ? { record: toScheduleTask(result.record) } : {}),\n ...(typeof result.code === 'string' ? { code: result.code } : {}),\n }\n }),\n delete: async (request) => this.call(async () => {\n const result = await controller.delete({ sessionId: request.payload!.sessionId, id: request.payload!.id }) as Record<string, unknown>\n return { id: String(result.id), deleted: result.deleted === true, ...(result.code !== undefined ? { code: String(result.code) } : {}) }\n }),\n }\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 // Keep worker identity internally so HostBridge can suppress notifications\n // as well as exclude these rows from the phone's session list.\n return { items: value.items.map(toPhoneSessionRow) }\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 // 分页窗口的策略住在 host-event-projection(与它依赖的投影规则同处);\n // 适配器只负责拉全量事件、把窗口映射成 HistoryResult。\n const window = historyWindow(inspected.events, {\n beforeSeq: request.payload?.beforeSeq,\n limit: normalizePageLimit(request.payload?.maxMessages),\n })\n return { events: window.events as HistoryResult['events'], hasMore: window.hasMore }\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 fork: async (request) => this.call(() => this.session.fork(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 projections: async (request) => this.call(() => this.session.projections(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 unarchiveSession: async (request) => this.call(async () => {\n if (this.workspaceController === undefined) throw unavailable('workspace controller unavailable')\n const value = await this.workspaceController.unarchiveSession(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; header?: { origin?: string } }, event: unknown) => {\n queue.push({\n type: 'session/event', sessionId: String(session.id),\n // Header origin is available before the next list refresh. A header's\n // parentSession alone is fork lineage, not proof of a worker session.\n isSubagent: session.header?.origin === 'subagent',\n event: event as MuxFrameLike['event'],\n })\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 startDshRemoteInteractions(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 ...(request.callId ? { callId: request.callId } : {}),\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 listen('schedule/changed', 'host/schedule-changed'),\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}\nfunction toScheduleExpected(value: unknown): Record<string, unknown> {\n const row = value !== null && typeof value === 'object' ? value as Record<string, unknown> : {}\n const { state: _state, deliveryMode: _deliveryMode, ...record } = row\n return record\n}\nfunction toScheduleTask(value: unknown): ScheduleTaskViewLike {\n const row = value as Record<string, unknown>\n const kind = ['after', 'at', 'every', 'daily', 'weekly', 'cron'].includes(String(row.kind))\n ? String(row.kind) as ScheduleTaskViewLike['kind']\n : 'at'\n const optionalNumber = (key: string): number | undefined => typeof row[key] === 'number' && Number.isFinite(row[key]) ? row[key] as number : undefined\n return {\n id: String(row.id ?? ''),\n kind,\n title: String(row.title ?? ''),\n prompt: String(row.prompt ?? ''),\n scheduledAt: String(row.scheduledAt ?? ''),\n state: row.state === 'overdue' ? 'overdue' : 'scheduled',\n deliveryMode: 'host',\n ...(optionalNumber('afterSeconds') !== undefined ? { afterSeconds: optionalNumber('afterSeconds')! } : {}),\n ...(optionalNumber('everySeconds') !== undefined ? { everySeconds: optionalNumber('everySeconds')! } : {}),\n ...(typeof row.time === 'string' ? { time: row.time } : {}),\n ...(typeof row.timeZone === 'string' ? { timeZone: row.timeZone } : {}),\n ...(Array.isArray(row.weekdays) ? { weekdays: row.weekdays.filter((day): day is number => typeof day === 'number') } : {}),\n ...(typeof row.expression === 'string' ? { expression: row.expression } : {}),\n }\n}\nfunction toScheduleHistory(value: unknown): ScheduleHistoryViewLike {\n const row = value as Record<string, unknown>\n const records = Array.isArray(row.records) ? row.records : []\n return {\n id: String(row.id ?? ''),\n records: records.map((entry) => {\n const item = entry as Record<string, unknown>\n return {\n scheduledAt: String(item.scheduledAt ?? ''),\n deliveredAt: String(item.deliveredAt ?? ''),\n messageId: String(item.messageId ?? ''),\n ...(typeof item.prompt === 'string' ? { prompt: item.prompt } : {}),\n }\n }),\n earlierRecordsUnavailable: row.earlierRecordsUnavailable === true,\n ...(typeof row.earlierRecordsPruned === 'boolean' ? { earlierRecordsPruned: row.earlierRecordsPruned } : {}),\n retention: {\n days: Number((row.retention as { days?: unknown } | undefined)?.days ?? 0),\n records: Number((row.retention as { records?: unknown } | undefined)?.records ?? 0),\n },\n ...(typeof row.nextBefore === 'string' ? { nextBefore: row.nextBefore } : {}),\n }\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 DeviceRenamer = (deviceId: string, customName: string | null) => Promise<string | null>\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 deviceRenamer: DeviceRenamer\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 deviceRenamer: DeviceRenamer,\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.deviceRenamer = deviceRenamer\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 setDeviceName(deviceId: string, customName: string | null): Promise<string | null> {\n return this.deviceRenamer(deviceId, customName)\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, TypertCodec, 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 /** Effective operator-facing name: customName when set, otherwise the app-reported name. */\n deviceName: string\n /** User-assigned label; absent means the app-reported name is in use. */\n customName?: 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 /** Private IPv4 candidates for local QR pairing. */\n lanAddresses: string[]\n /** Independent TLS-only 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 /** `sha256:` SPKI pin of the LAN certificate; present while `online`. */\n tlsFingerprint?: string\n /** The LAN private key was recreated this run: paired LAN devices must pair again. */\n tlsIdentityRegenerated?: boolean\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_NAME_ENDPOINT = 'deeppilot/setDeviceName'\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 const customName = s.customName\n if (customName !== undefined && (\n typeof customName !== 'string' ||\n customName.length === 0 ||\n customName.length > 64 ||\n customName.trim() !== customName ||\n /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(customName)\n )) reject('device.customName')\n return {\n deviceId: str(s, 'deviceId', 'device.deviceId'),\n deviceName: str(s, 'deviceName', 'device.deviceName'),\n ...(typeof customName === 'string' ? { customName } : {}),\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 const tlsFingerprint = s.tlsFingerprint\n if (tlsFingerprint !== undefined && typeof tlsFingerprint !== 'string') reject('local.tlsFingerprint')\n const tlsIdentityRegenerated = s.tlsIdentityRegenerated\n if (tlsIdentityRegenerated !== undefined && typeof tlsIdentityRegenerated !== 'boolean') reject('local.tlsIdentityRegenerated')\n return {\n phase: phase as DeepPilotReport['local']['phase'],\n port: int(s, 'port', 'local.port'),\n endpoints: endpoints as string[],\n ...(typeof tlsFingerprint === 'string' ? { tlsFingerprint } : {}),\n ...(tlsIdentityRegenerated === true ? { tlsIdentityRegenerated: true } : {}),\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 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 customNameSchema: TypertSchema<string | null> = {\n parse(value: unknown): string | null {\n if (value === null) return null\n if (typeof value !== 'string') reject('customName')\n const trimmed = value.trim()\n if (trimmed.length === 0 || trimmed.length > 64 || /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(value)) reject('customName')\n return trimmed\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/** The rc.2 Gateway materializes each strict codec through `create()`. */\nfunction strictCodec<T>(typeSymbol: string, schema: TypertSchema<T>): TypertCodec {\n return {\n mode: 'strict',\n typeSymbol,\n create: () => schema,\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeepPilotReport`, reportSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#PairingGrantSnapshot`, pairingGrantSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceId`, deviceIdSchema),\n }],\n result: strictCodec(`${REPORT_REMOTE_PACKAGE}#Boolean`, booleanSchema),\n}\n\nexport const SET_DEVICE_NAME_DESCRIPTOR: InvocationDescriptor = {\n id: `${REPORT_REMOTE_PACKAGE}#${SET_DEVICE_NAME_ENDPOINT}`,\n service: 'deeppilotReport',\n namespace: 'deeppilot',\n method: 'setDeviceName',\n invocation: { kind: 'direct' },\n parameters: [\n {\n name: 'deviceId', wire: 'deviceId', source: 'json',\n codec: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceId`, deviceIdSchema),\n },\n {\n name: 'customName', wire: 'customName', source: 'json',\n codec: strictCodec(`${REPORT_REMOTE_PACKAGE}#CustomDeviceName`, customNameSchema),\n },\n ],\n result: strictCodec(`${REPORT_REMOTE_PACKAGE}#CustomDeviceName`, customNameSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceId`, deviceIdSchema),\n },\n {\n name: 'scopes', wire: 'scopes', source: 'json',\n codec: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceScopes`, scopesSchema),\n },\n ],\n result: strictCodec(`${REPORT_REMOTE_PACKAGE}#DeviceScopes`, scopesSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#RelayTestResult`, relayTestSchema),\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: strictCodec(`${REPORT_REMOTE_PACKAGE}#PushTestResult`, pushTestSchema),\n}\n\nconst INVOCATION_DESCRIPTORS = [\n REPORT_DESCRIPTOR,\n BEGIN_PAIRING_DESCRIPTOR,\n REVOKE_DEVICE_DESCRIPTOR,\n SET_DEVICE_NAME_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 // This 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 { DeviceRenamer, 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 deviceRenamer: DeviceRenamer,\n deviceScopeUpdater: DeviceScopeUpdater,\n relayTester: RelayTester,\n pushTester: PushTester,\n): void {\n ctx.inject(['typert'], (remoteCtx) => {\n new DeepPilotReportService(remoteCtx, snapshot, pairingStarter, deviceRevoker, deviceRenamer, 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","import { networkInterfaces } from 'node:os'\n\nfunction octetsOf(address: string): [number, number, number, number] | null {\n const octets = address.split('.').map(Number)\n if (octets.length !== 4 || octets.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {\n return null\n }\n return octets as [number, number, number, number]\n}\n\n/** RFC1918 私有地址。名字保持诚实:它**不**包含 CGNAT 段,见 isSharedAddressSpaceIPv4。 */\nexport function isPrivateIPv4(address: string): boolean {\n const parsed = octetsOf(address)\n if (parsed === null) return false\n const [a, b] = parsed\n return a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168)\n}\n\n/**\n * RFC 6598 共享地址空间(100.64.0.0/10)。\n *\n * Tailscale 与 Headscale 都从这个段里给节点分配地址(Headscale 的\n * `prefixes.v4` 默认就是它),因此它在实践中是私有的,只是不是 RFC1918——\n * 这正是 `isPrivateIPv4` 会把它拒掉的原因。把它单列成一个谓词而不是塞进\n * `isPrivateIPv4`,是为了不谎报那个名字(issue #24)。\n */\nexport function isSharedAddressSpaceIPv4(address: string): boolean {\n const parsed = octetsOf(address)\n if (parsed === null) return false\n const [a, b] = parsed\n return a === 100 && b >= 64 && b <= 127\n}\n\n/**\n * 可以交给手机的私有地址候选:RFC1918 加 CGNAT 段。\n *\n * 候选多于一个时,配对二维码页才会渲染地址选择器——只有一个候选时用户没有\n * 任何办法指定别的地址。把 tailnet 地址放进来,选择器才会出现,物理局域网\n * 离开之后用户仍可切到 tailnet 那个。\n *\n * 排序**不动**:物理 en* 接口仍然排在隧道接口之前,默认拿到的还是局域网地址,\n * 改变的只是「多了一个可选项」这件事本身。\n */\nfunction isRoutablePrivateIPv4(address: string): boolean {\n return isPrivateIPv4(address) || isSharedAddressSpaceIPv4(address)\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 && isRoutablePrivateIPv4(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","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","import { createHash, createPrivateKey, createPublicKey, X509Certificate } from 'node:crypto'\nimport { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { generate } from 'selfsigned'\n\nexport { LAN_TLS_FINGERPRINT_PATTERN, isLanTlsFingerprint } from './pairing-qr.ts'\n\nexport const LAN_TLS_COMMON_NAME = 'dsh-deeppilot'\nexport const LAN_TLS_KEY_FILE = 'key.pem'\nexport const LAN_TLS_CERT_FILE = 'cert.pem'\n\nconst CERT_VALIDITY_MS = 10 * 365 * 24 * 60 * 60_000\n/** Re-sign this far ahead of expiry so a long-running host never serves a stale leaf. */\nconst CERT_RENEW_LEAD_MS = 30 * 24 * 60 * 60_000\n\nexport interface LanTlsIdentity {\n /** PKCS#8 PEM private key. Never logged or reported. */\n key: string\n /** Self-signed X.509 PEM leaf certificate. */\n cert: string\n /** Pinned by paired devices; changes only when the private key changes. */\n fingerprint: string\n /** Unix ms when the current leaf certificate expires. */\n notAfter: number\n /**\n * The private key was newly created. Devices that pinned the previous\n * identity can no longer connect and must pair again.\n */\n regenerated: boolean\n /** A fresh leaf was signed with the existing key; the fingerprint is unchanged. */\n resigned: boolean\n}\n\n/** Compute the pinned public-key fingerprint of a PEM certificate. */\nexport function spkiFingerprint(certPem: string): string {\n const der = createPublicKey(certPem).export({ type: 'spki', format: 'der' })\n return 'sha256:' + createHash('sha256').update(der).digest('base64url')\n}\n\n/**\n * Load the LAN listener's TLS identity from `dir`, creating or repairing it\n * as needed. The private key is the durable identity: it is created once and\n * reused for every subsequent certificate, so pinned devices survive\n * certificate renewals. Only a missing or unreadable key forces a new one.\n */\nexport async function loadOrCreateLanTlsIdentity(dir: string, now: number = Date.now()): Promise<LanTlsIdentity> {\n await mkdir(dir, { recursive: true, mode: 0o700 })\n const keyPath = join(dir, LAN_TLS_KEY_FILE)\n const certPath = join(dir, LAN_TLS_CERT_FILE)\n\n let key = await readPem(keyPath)\n let regenerated = false\n if (key === undefined || !validPrivateKey(key)) {\n regenerated = true\n key = undefined\n }\n\n let cert = regenerated ? undefined : await readPem(certPath)\n let resigned = false\n const existing = key !== undefined && cert !== undefined ? inspectCertificate(cert, key, now) : undefined\n if (existing === undefined) {\n const issued = await issueCertificate(key, now)\n if (key === undefined) {\n key = pemFile(issued.key)\n await writePrivate(keyPath, key)\n } else {\n resigned = true\n }\n cert = pemFile(issued.cert)\n await writePrivate(certPath, cert)\n }\n if (key === undefined || cert === undefined) throw new Error('LAN TLS identity unavailable')\n\n return {\n key,\n cert,\n fingerprint: spkiFingerprint(cert),\n notAfter: existing ?? new X509Certificate(cert).validToDate.getTime(),\n regenerated,\n resigned,\n }\n}\n\nasync function readPem(path: string): Promise<string | undefined> {\n try {\n const text = await readFile(path, 'utf8')\n return text.trim().length > 0 ? text : undefined\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n // Any other read failure is treated like a missing file: the caller\n // rewrites the identity and the operator sees the \"regenerated\" signal.\n return undefined\n }\n}\n\nfunction validPrivateKey(pem: string): boolean {\n try {\n const key = createPrivateKey(pem)\n return key.asymmetricKeyType === 'ec'\n } catch {\n return false\n }\n}\n\n/**\n * Return the certificate's expiry when it is usable with `keyPem`, or\n * `undefined` when it must be re-issued (malformed, wrong key, or expiring).\n */\nfunction inspectCertificate(certPem: string, keyPem: string, now: number): number | undefined {\n try {\n const cert = new X509Certificate(certPem)\n const certSpki = cert.publicKey.export({ type: 'spki', format: 'der' })\n const keySpki = createPublicKey(createPrivateKey(keyPem)).export({ type: 'spki', format: 'der' })\n if (!certSpki.equals(keySpki)) return undefined\n const notAfter = cert.validToDate.getTime()\n const notBefore = cert.validFromDate.getTime()\n if (!(notBefore <= now && notAfter - CERT_RENEW_LEAD_MS > now)) return undefined\n return notAfter\n } catch {\n return undefined\n }\n}\n\nasync function issueCertificate(existingKey: string | undefined, now: number): Promise<{ key: string; cert: string }> {\n // Back-date slightly so a phone whose clock trails the Mac still accepts a\n // certificate issued moments ago.\n const notBeforeDate = new Date(now - 5 * 60_000)\n const notAfterDate = new Date(now + CERT_VALIDITY_MS)\n const keyPair = existingKey === undefined\n ? undefined\n : {\n privateKey: createPrivateKey(existingKey).export({ type: 'pkcs8', format: 'pem' }) as string,\n publicKey: createPublicKey(existingKey).export({ type: 'spki', format: 'pem' }) as string,\n }\n const result = await generate(\n [{ name: 'commonName', value: LAN_TLS_COMMON_NAME }],\n {\n keyType: 'ec',\n curve: 'P-256',\n algorithm: 'sha256',\n notBeforeDate,\n notAfterDate,\n ...(keyPair ? { keyPair } : {}),\n extensions: [\n { name: 'basicConstraints', cA: false, critical: true },\n { name: 'keyUsage', digitalSignature: true, keyAgreement: true, critical: true },\n { name: 'extKeyUsage', serverAuth: true },\n { name: 'subjectAltName', altNames: [{ type: 2, value: LAN_TLS_COMMON_NAME }] },\n ],\n },\n )\n return { key: existingKey ?? result.private, cert: result.cert }\n}\n\n/** Exact on-disk form, so a freshly issued value equals its later reload. */\nfunction pemFile(pem: string): string {\n return pem.replace(/\\r\\n/g, '\\n').trimEnd() + '\\n'\n}\n\nasync function writePrivate(path: string, contents: string): Promise<void> {\n const tmp = `${path}.${process.pid}.tmp`\n try {\n await writeFile(tmp, contents, { mode: 0o600 })\n await rename(tmp, path)\n } catch (error) {\n await unlink(tmp).catch(() => {})\n throw error\n }\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 { PushGateway } from './push-gateway.ts'\nimport { createLocalTransport, createRemoteTransport } from './transport-reconciler.ts'\nimport { ConnectionGate } from './connection-gate.ts'\nimport { HostBridge } from './host-bridge.ts'\nimport { DshApiProxy, type DshInteractionKind } from './dsh-api-proxy.ts'\nimport { applyReportRemote } from './report-remote.ts'\nimport type { DeepPilotReport } from './report-wire.ts'\nimport { DeviceStore, MAX_DEVICES, bridgeDataDir, deviceDisplayName, 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 type { RemoteStatus } from './remote-supervisor.ts'\nimport { localLANIPv4Addresses } from './local-address.ts'\nimport { UpdateChecker, type UpdateInfo } from './update-check.ts'\nimport { normalizeOptions } from './config.ts'\nimport type { Config } from './config.ts'\nimport { rejectUpgrade, requestClientIdentity } from './phone-http.ts'\nimport { AuthRateLimiter } from './auth-rate-limit.ts'\nimport { MAX_APP_VERSION_CHARS, MAX_DEVICE_NAME_CHARS, sanitizeDeviceField } from './connection-policy.ts'\nimport { localEndpointURLs } from './local-policy.ts'\nimport { closeServer, createPhoneServer, listen } from './phone-server.ts'\nimport { loadOrCreateLanTlsIdentity, type LanTlsIdentity } from './lan-tls.ts'\n\n/**\n * dsh-deeppilot — data bridge between the DSH host and DeepPilot\n * clients. Owns independent, narrowly routed LAN (TLS-only, pinned by paired\n * devices) and loopback Funnel-origin listeners. The web UI and the rest of\n * DSH's API are never exposed by these listeners.\n *\n * Data plane: an in-process HostBridge consumes a local adapter over DSH\n * 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 web-service requirement: the plugin owns its own transport listeners. */\nexport const inject: string[] = []\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 let scheduleRemoteReconcile: (() => void) | undefined\n let scheduleLocalReconcile: (() => void) | undefined\n const currentConfig = (): Config => normalizeOptions(options)\n const enabledNow = (): boolean => currentConfig().enabled === true\n\n // rc.2 commits volatile config edits into live refs and emits on the owning\n // fiber. Reconcile transport listeners after the new values are published.\n ;(ctx as unknown as { on: (name: string, listener: () => void) => void }).on(\n 'loader/volatile-update',\n () => queueMicrotask(() => {\n scheduleLocalReconcile?.()\n scheduleRemoteReconcile?.()\n }),\n )\n\n // Master switch, resolved against the current profile entry.\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 // ---------- offline push (F-9) ----------\n\n // 推送的全部行为住在 PushGateway:enrollment 与持久化、中继注册、sender\n // 缓存与退避、两个 scheduler、PushOutlet 四方法、两个自测。这里只声明它并\n // 注入依赖——apply() 不再持有任何推送状态。详见 src/push-gateway.ts 文件头。\n const pushGateway = new PushGateway({\n config: currentConfig,\n dataDir,\n devices: () => auth.devices,\n audience: () => auth.audience,\n connections: () => connections,\n enabledNow,\n log,\n })\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 await pushGateway.restore()\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 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 /**\n * Unbind one device. Single path shared by the settings page (report-service\n * revokeDevice) and the wire-level c2s.device.revoke frame: mark the registry\n * tombstone (which also drops every APNs/WidgetKit/LiveActivity token, so the\n * push fan-out can no longer select it) and hard-drop its live sockets.\n * `except` is the connection that sent the revoke frame — it closes itself\n * with 4401 after acking, so it is not terminated here.\n */\n const revokeDevice = async (deviceId: string, except?: BridgeConnection): Promise<boolean> => {\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 === except || connection.connectedDeviceId !== deviceId) continue\n connection.terminate()\n connections.delete(connection)\n }\n log(`device revoked id=${auditLabel(deviceId)}`)\n }\n return revoked\n }\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_FRAME_BYTES })\n // The LAN TLS identity is loaded once per plugin lifetime: port or enable\n // toggles reuse it so paired devices keep their pin. `tlsIdentityRegenerated`\n // stays raised for the settings page until the next restart because it\n // means every previously paired LAN device must pair again. 身份留在\n // apply()——它被 listener 启动、配对回显与 report 三处消费,协调器不懂 TLS。\n let lanTlsIdentity: Promise<LanTlsIdentity> | undefined\n let tlsIdentityRegenerated = false\n const loadLanTls = (): Promise<LanTlsIdentity> => {\n lanTlsIdentity ??= (async () => {\n await ready\n const identity = await loadOrCreateLanTlsIdentity(join(dataDir, 'lan-tls'))\n if (identity.regenerated) {\n tlsIdentityRegenerated = true\n log(`LAN TLS identity created: fingerprint=${identity.fingerprint}; previously paired LAN devices must pair again`)\n } else if (identity.resigned) {\n log(`LAN TLS certificate renewed (fingerprint unchanged: ${identity.fingerprint})`)\n }\n return identity\n })()\n // A failed load (disk error) must not poison later reconciles.\n lanTlsIdentity.catch(() => { lanTlsIdentity = undefined })\n return lanTlsIdentity\n }\n\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; customName?: 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, customName, appVersion, firstSeenTs, lastSeenTs, fingerprint, scopes, revokedAt, apns }) => ({\n deviceId,\n deviceName: deviceDisplayName({ deviceName, customName }),\n ...(customName ? { customName } : {}),\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 lanAddresses,\n local: localStatus(lanAddresses),\n remote: remoteStatus(),\n devices,\n }\n }, beginPairing, async (deviceId) => {\n // Settings-page revocation shares the exact path used by the wire-level\n // c2s.device.revoke frame (index.ts revokeDevice helper).\n return await revokeDevice(deviceId)\n }, async (deviceId, customName) => {\n const { devices } = await ready\n if (!devices) throw new Error('device registry unavailable')\n const effectiveName = await devices.setCustomName(deviceId, customName)\n if (effectiveName === null) throw new Error('active device not found')\n const normalized = customName === null ? '' : sanitizeDeviceField(customName, MAX_DEVICE_NAME_CHARS)\n log(`device custom name updated id=${auditLabel(deviceId)} custom=${String(normalized.length > 0)}`)\n return normalized === '' ? null : normalized\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 }, () => pushGateway.relayTest(), () => pushGateway.selfTest())\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 // Only a request that arrived over the LAN TLS listener echoes the pin;\n // Funnel pairings terminate TLS at tailscaled with a public CA cert.\n const overLanTls = (req.socket as { encrypted?: boolean }).encrypted === true\n const tlsFingerprint = overLanTls ? (await lanTlsIdentity)?.fingerprint : undefined\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 ...(tlsFingerprint ? { tlsFingerprint } : {}),\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 之外:finally 需要归还一个可能未创建成功的门的名额。\n let gate: ConnectionGate | undefined\n try {\n const { devices, audience } = await ready\n if (!audience || !devices) {\n rejectUpgrade(socket, 503, 'bridge degraded')\n return\n }\n const bridge = state.bridge\n if (!bridge) {\n rejectUpgrade(socket, 503, 'bridge not ready')\n return\n }\n // The gate is created before the ws exists, so the admission slot is\n // held even when the upgrade callback never runs (socket gone\n // mid-upgrade). Its attach timeout covers that case; once the socket\n // is live, the gate's hello deadline takes over.\n gate = new ConnectionGate({\n source: requestClientIdentity(req),\n devices,\n audience,\n limiter: authRateLimiter,\n log,\n auditLabel,\n })\n if (!gate.admitted) {\n rejectUpgrade(socket, 429, 'authentication rate limited')\n return\n }\n const live = gate\n wss.handleUpgrade(req, socket, head, (ws) => {\n if (auth.audience !== audience || state.bridge !== bridge) {\n live.markDead()\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().diagnostics?.debug === true,\n source: live.source,\n rateLimiter: authRateLimiter,\n auditLabel,\n onClosed: (closed) => connections.delete(closed),\n onDeviceAuthenticated: (deviceId) => {\n log(`device authenticated id=${auditLabel(deviceId)} source=${auditLabel(live.source)}`)\n },\n onPushEnrollKey: (enrollKey) => pushGateway.enrollKey(enrollKey),\n // A device that unbinds itself from the app must not leave a\n // second socket (e.g. an older install) still live: the\n // registry tombstone is already written by the handler, so\n // this only drops the sibling sockets.\n onDeviceRevoke: (deviceId, except) => revokeDevice(deviceId, except),\n }, live)\n connections.add(connection)\n } catch (error) {\n live.markDead()\n ws.close(1011, 'connection setup failed')\n throw error\n }\n })\n } finally {\n // The attach window ends here: if no socket was produced (the upgrade\n // callback never ran), the slot goes back immediately instead of\n // waiting for the attach timeout. An attached gate keeps its slot\n // until a settle path or its hello deadline.\n gate?.releaseIfNeverAttached()\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 //\n // 差分、串行、拆除与状态发布的公共协议住在 TransportReconciler;两个传输\n // 各自的差异(skipWhenDisabled / appliedKey 时机 / 错误分支)在\n // createLocalTransport 与 createRemoteTransport 里显式声明并原样保留——\n // 统一它们会改变一条当前稳定路径上的并发语义,属于单独一轮的决策。\n const localTransport = createLocalTransport({\n handlers: phoneHandlers,\n config: currentConfig,\n tls: loadLanTls,\n log,\n })\n const remoteTransport = createRemoteTransport({\n handlers: phoneHandlers,\n config: currentConfig,\n originURL: () => originURL,\n dataDir,\n log,\n })\n const localStatus = (addresses: readonly string[]): DeepPilotReport['local'] => {\n const state = localTransport.status()\n return {\n ...state,\n endpoints: state.phase === 'online' ? localEndpointURLs(addresses, state.port) : [],\n ...(tlsIdentityRegenerated ? { tlsIdentityRegenerated: true } : {}),\n }\n }\n const remoteStatus = (): RemoteStatus => remoteTransport.status()\n\n const originServer = createPhoneServer(phoneHandlers)\n let originURL: string | undefined\n scheduleLocalReconcile = () => localTransport.scheduleReconcile()\n scheduleRemoteReconcile = () => remoteTransport.scheduleReconcile()\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 scheduleLocalReconcile = undefined\n scheduleRemoteReconcile = undefined\n await Promise.allSettled([\n closeServer(originServer),\n localTransport.dispose(),\n remoteTransport.dispose(),\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 // Build the bridge's stable protocol-facing adapter from the public\n // 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: DshApiProxy\n try {\n proxy = new DshApiProxy(apiCtx, { shouldSurfaceInteraction: hasPairedPhoneSurface })\n } catch (error) {\n log('DSH session bridge unavailable: ' + String(error))\n return\n }\n const bridge = new HostBridge(\n proxy,\n cfg.historyBufferMax,\n join(dataDir, 'prompt-deliveries-v1.json'),\n join(dataDir, 'schedule-mutations-v1.json'),\n join(dataDir, 'fork-mutations-v1.json'),\n log,\n )\n bridge.setPushOutlet(pushGateway)\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 ;(ctx as unknown as SubContext).effect(() => async () => {\n closeAllConnections()\n const bridge = state.bridge\n state.bridge = undefined\n bridge?.dispose()\n updateChecker.dispose()\n await pushGateway.dispose()\n const wssClosed = new Promise<void>((resolve) => wss.close(() => resolve()))\n await Promise.allSettled([wssClosed])\n }, 'deeppilot: process resources')\n}\n"],"mappings":"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"}