@archships/dim-plugin-devtools
Advanced tools
+48
-32
@@ -95,3 +95,3 @@ import { access, appendFile, mkdir, readFile, readdir, stat } from "node:fs/promises"; | ||
| const parsed = JSON.parse(line); | ||
| const currentRequestId = typeof parsed.requestId === "string" ? parsed.requestId : void 0; | ||
| const currentRequestId = readMetadataString(parsed.requestId); | ||
| if (requestId && currentRequestId !== requestId) continue; | ||
@@ -103,3 +103,3 @@ entries.push({ | ||
| requestId: currentRequestId, | ||
| event: typeof parsed.event === "string" ? parsed.event : void 0, | ||
| event: readMetadataString(parsed.event), | ||
| entry: toStructuredData(parsed) | ||
@@ -117,7 +117,8 @@ }); | ||
| if (sanitized && typeof sanitized === "object" && !Array.isArray(sanitized)) return sanitized; | ||
| return { value: sanitized }; | ||
| return sanitized === void 0 ? {} : { value: sanitized }; | ||
| } | ||
| function sanitizeValue(value, parentKey, seen = /* @__PURE__ */ new WeakSet()) { | ||
| if (parentKey && shouldRedact(parentKey)) return "[REDACTED]"; | ||
| if (value === null || typeof value === "number" || typeof value === "boolean") return value; | ||
| if (value === null) return void 0; | ||
| if (typeof value === "number" || typeof value === "boolean") return value; | ||
| if (typeof value === "string") return sanitizeString(value); | ||
@@ -142,3 +143,4 @@ if (value === void 0) return void 0; | ||
| value.forEach((entry, key) => { | ||
| result[key] = sanitizeValue(entry, key, seen); | ||
| const sanitized = sanitizeValue(entry, key, seen); | ||
| if (sanitized !== void 0) result[key] = sanitized; | ||
| }); | ||
@@ -156,3 +158,6 @@ return result; | ||
| if (Array.isArray(value)) { | ||
| const items = value.slice(0, MAX_ARRAY_ITEMS).map((item) => sanitizeValue(item, void 0, seen)); | ||
| const items = value.slice(0, MAX_ARRAY_ITEMS).flatMap((item) => { | ||
| const sanitized = sanitizeValue(item, void 0, seen); | ||
| return sanitized === void 0 ? [] : [sanitized]; | ||
| }); | ||
| if (value.length > MAX_ARRAY_ITEMS) items.push({ | ||
@@ -191,2 +196,5 @@ truncated: true, | ||
| } | ||
| function readMetadataString(value) { | ||
| return typeof value === "string" ? value : void 0; | ||
| } | ||
| //#endregion | ||
@@ -255,6 +263,6 @@ //#region src/runtime.ts | ||
| iteration: context.iteration, | ||
| ...context.metadata ? { metadata: toStructuredData(context.metadata) } : {}, | ||
| ...context.status ? { status: toStructuredData(context.status) } : {}, | ||
| payload: toStructuredData(payload) | ||
| }; | ||
| if (context.metadata) entry.metadata = toStructuredData(context.metadata); | ||
| if (context.status) entry.status = toStructuredData(context.status); | ||
| const journalStore = await this.getJournalStore(); | ||
@@ -360,2 +368,8 @@ this.broadcast("journal", entry); | ||
| ]); | ||
| const artifacts = { | ||
| journalDir: paths.journalDir, | ||
| providerHttpDir: paths.providerHttpDir, | ||
| journalFiles: await this.getJournalStore().then((store) => store.listFiles()), | ||
| providerHttpFiles: await listJsonFiles(paths.providerHttpDir) | ||
| }; | ||
| return { | ||
@@ -367,8 +381,3 @@ agent, | ||
| requestSummaries: buildRequestSummaries(events), | ||
| artifacts: { | ||
| journalDir: paths.journalDir, | ||
| providerHttpDir: paths.providerHttpDir, | ||
| journalFiles: await this.getJournalStore().then((store) => store.listFiles()), | ||
| providerHttpFiles: await listJsonFiles(paths.providerHttpDir) | ||
| } | ||
| artifacts | ||
| }; | ||
@@ -382,7 +391,6 @@ } | ||
| ]); | ||
| const liveSession = liveSessions.find((entry) => entry.sessionId === sessionId) ?? null; | ||
| const liveSession = liveSessions.find((entry) => entry.sessionId === sessionId); | ||
| const sessionEvents = events.filter((entry) => entry.sessionId === sessionId); | ||
| return { | ||
| const payload = { | ||
| sessionId, | ||
| liveSession, | ||
| persistedSnapshot, | ||
@@ -392,2 +400,4 @@ events: sessionEvents, | ||
| }; | ||
| if (liveSession) payload.liveSession = liveSession; | ||
| return payload; | ||
| } | ||
@@ -553,3 +563,5 @@ async createRequestPayload(requestId) { | ||
| if (event.hook !== "model.request") return void 0; | ||
| const model = asRecord(asRecord(event.payload.request)?.model); | ||
| const payload = readStructuredObject(event.payload); | ||
| const request = payload ? readStructuredObject(payload.request) : void 0; | ||
| const model = request ? readStructuredObject(request.model) : void 0; | ||
| if (!model) return void 0; | ||
@@ -561,12 +573,14 @@ if (typeof model.provider !== "string" || typeof model.modelId !== "string") return void 0; | ||
| if (event.hook === "run.stop") { | ||
| const payload = asRecord(event.payload); | ||
| const payload = readStructuredObject(event.payload); | ||
| return typeof payload?.stopReason === "string" ? payload.stopReason : void 0; | ||
| } | ||
| if (event.hook !== "model.event") return void 0; | ||
| const modelEvent = asRecord(event.payload.event); | ||
| const payload = readStructuredObject(event.payload); | ||
| const modelEvent = payload ? readStructuredObject(payload.event) : void 0; | ||
| if (!modelEvent || modelEvent.type !== "response_end") return void 0; | ||
| return typeof modelEvent.stopReason === "string" ? modelEvent.stopReason : void 0; | ||
| } | ||
| function asRecord(value) { | ||
| return value && typeof value === "object" && !Array.isArray(value) ? value : void 0; | ||
| function readStructuredObject(value) { | ||
| if (!value || typeof value !== "object" || Array.isArray(value)) return void 0; | ||
| return value; | ||
| } | ||
@@ -584,3 +598,2 @@ async function resolveUiRoot() { | ||
| } | ||
| return null; | ||
| } | ||
@@ -590,3 +603,3 @@ function resolveUiFile(rootDir, requestPath) { | ||
| const targetPath = path.resolve(rootDir, normalized); | ||
| if (!targetPath.startsWith(path.resolve(rootDir))) return null; | ||
| if (!targetPath.startsWith(path.resolve(rootDir))) return void 0; | ||
| return targetPath; | ||
@@ -653,10 +666,13 @@ } | ||
| return { | ||
| inspector: { getConfig: async () => ({ | ||
| id: normalized.id, | ||
| host: normalized.host, | ||
| port: normalized.port, | ||
| instanceId: normalized.instanceId ?? null, | ||
| providerHttpDir: normalized.providerHttpDir ?? null, | ||
| autoOpenBrowser: normalized.autoOpenBrowser | ||
| }) }, | ||
| inspector: { getConfig: async () => { | ||
| const config = { | ||
| id: normalized.id, | ||
| host: normalized.host, | ||
| port: normalized.port, | ||
| autoOpenBrowser: normalized.autoOpenBrowser | ||
| }; | ||
| if (normalized.instanceId) config.instanceId = normalized.instanceId; | ||
| if (normalized.providerHttpDir) config.providerHttpDir = normalized.providerHttpDir; | ||
| return config; | ||
| } }, | ||
| hooks: runtime.hookRegistration(), | ||
@@ -663,0 +679,0 @@ createSessionController: (controllerContext) => new DefaultDevtoolsSessionController(runtime, controllerContext) |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/journal.ts","../src/runtime.ts","../src/index.ts"],"sourcesContent":["import { appendFile, mkdir, readFile, readdir, stat } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { StructuredData } from '@archships/dim-agent-sdk'\n\nconst SECRET_KEYS = new Set([\n 'authorization',\n 'proxyauthorization',\n 'apikey',\n 'xapikey',\n 'xgoogapikey',\n 'token',\n 'secret',\n])\nconst MAX_TEXT_LENGTH = 4_000\nconst MAX_ARRAY_ITEMS = 128\nconst TRUNCATED = '[TRUNCATED]'\n\nexport interface DevtoolsJournalEntry {\n id: string\n timestamp: number\n hook: string\n sessionId?: string\n requestId?: string\n iteration?: number\n metadata?: StructuredData\n status?: StructuredData\n payload: StructuredData\n}\n\nexport interface DevtoolsFileSummary {\n name: string\n path: string\n size: number\n mtimeMs: number\n}\n\nexport interface ProviderHttpLogEntry {\n file: string\n path: string\n line: number\n requestId?: string\n event?: string\n entry: StructuredData\n}\n\nexport class JournalStore {\n readonly rootDir: string\n readonly eventsPath: string\n\n private entries?: DevtoolsJournalEntry[]\n private writeQueue = Promise.resolve()\n\n constructor(rootDir: string) {\n this.rootDir = path.resolve(rootDir)\n this.eventsPath = path.join(this.rootDir, 'events.jsonl')\n }\n\n async append(entry: DevtoolsJournalEntry): Promise<void> {\n const entries = await this.loadEntries()\n entries.push(structuredClone(entry))\n const line = `${JSON.stringify(entry)}\\n`\n\n this.writeQueue = this.writeQueue\n .catch(() => undefined)\n .then(async () => {\n await mkdir(this.rootDir, { recursive: true })\n await appendFile(this.eventsPath, line, 'utf8')\n })\n .catch(() => undefined)\n\n await this.writeQueue\n }\n\n async list(): Promise<DevtoolsJournalEntry[]> {\n return structuredClone(await this.loadEntries())\n }\n\n async listFiles(): Promise<DevtoolsFileSummary[]> {\n return listJsonFiles(this.rootDir)\n }\n\n private async loadEntries(): Promise<DevtoolsJournalEntry[]> {\n if (this.entries) return this.entries\n\n try {\n const raw = await readFile(this.eventsPath, 'utf8')\n this.entries = raw\n .split('\\n')\n .filter(Boolean)\n .flatMap((line) => {\n try {\n const parsed = JSON.parse(line) as DevtoolsJournalEntry\n if (typeof parsed.id !== 'string' || typeof parsed.hook !== 'string') return []\n return [parsed]\n } catch {\n return []\n }\n })\n } catch {\n this.entries = []\n }\n\n return this.entries\n }\n}\n\nexport async function listJsonFiles(directory: string): Promise<DevtoolsFileSummary[]> {\n try {\n const entries = await readdir(directory, { withFileTypes: true })\n const files = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith('.jsonl'))\n .map(async (entry) => {\n const targetPath = path.join(directory, entry.name)\n const info = await stat(targetPath)\n return {\n name: entry.name,\n path: targetPath,\n size: info.size,\n mtimeMs: info.mtimeMs,\n }\n }),\n )\n\n return files.sort((left, right) => right.mtimeMs - left.mtimeMs)\n } catch {\n return []\n }\n}\n\nexport async function loadProviderHttpEntries(\n directory: string,\n requestId?: string,\n): Promise<ProviderHttpLogEntry[]> {\n const files = await listJsonFiles(directory)\n const entries: ProviderHttpLogEntry[] = []\n\n for (const file of files) {\n let raw: string\n try {\n raw = await readFile(file.path, 'utf8')\n } catch {\n continue\n }\n\n const lines = raw.split('\\n')\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index]?.trim()\n if (!line) continue\n\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>\n const currentRequestId =\n typeof parsed.requestId === 'string' ? parsed.requestId : undefined\n if (requestId && currentRequestId !== requestId) continue\n entries.push({\n file: file.name,\n path: file.path,\n line: index + 1,\n requestId: currentRequestId,\n event: typeof parsed.event === 'string' ? parsed.event : undefined,\n entry: toStructuredData(parsed),\n })\n } catch {\n continue\n }\n }\n }\n\n return entries\n}\n\nexport function toStructuredData(value: unknown): StructuredData {\n const sanitized = sanitizeValue(value)\n if (sanitized && typeof sanitized === 'object' && !Array.isArray(sanitized))\n return sanitized as StructuredData\n return { value: sanitized as never }\n}\n\nfunction sanitizeValue(\n value: unknown,\n parentKey?: string,\n seen: WeakSet<object> = new WeakSet(),\n): unknown {\n if (parentKey && shouldRedact(parentKey)) return '[REDACTED]'\n if (value === null || typeof value === 'number' || typeof value === 'boolean') return value\n if (typeof value === 'string') return sanitizeString(value)\n if (value === undefined) return undefined\n if (typeof value === 'bigint') return value.toString()\n if (typeof value === 'function') return `[Function ${value.name || 'anonymous'}]`\n if (typeof value === 'symbol') return value.toString()\n if (value instanceof Date) return value.toISOString()\n if (value instanceof URL) return value.toString()\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: sanitizeString(value.stack ?? ''),\n }\n }\n if (typeof AbortSignal !== 'undefined' && value instanceof AbortSignal) {\n return {\n type: 'AbortSignal',\n aborted: value.aborted,\n }\n }\n if (typeof Headers !== 'undefined' && value instanceof Headers) {\n const result: Record<string, unknown> = {}\n value.forEach((entry, key) => {\n result[key] = sanitizeValue(entry, key, seen)\n })\n return result\n }\n if (ArrayBuffer.isView(value)) {\n return {\n type: value.constructor.name,\n byteLength: value.byteLength,\n }\n }\n if (value instanceof ArrayBuffer) {\n return {\n type: 'ArrayBuffer',\n byteLength: value.byteLength,\n }\n }\n if (Array.isArray(value)) {\n const items = value.slice(0, MAX_ARRAY_ITEMS).map((item) => sanitizeValue(item, undefined, seen))\n if (value.length > MAX_ARRAY_ITEMS) {\n items.push({\n truncated: true,\n totalItems: value.length,\n })\n }\n return items\n }\n if (typeof value === 'object') {\n if (seen.has(value)) return '[Circular]'\n seen.add(value)\n const result: Record<string, unknown> = {}\n for (const [key, child] of Object.entries(value)) {\n const next = sanitizeValue(child, key, seen)\n if (next !== undefined) result[key] = next\n }\n seen.delete(value)\n return result\n }\n\n return sanitizeString(String(value))\n}\n\nfunction sanitizeString(value: string): string | Record<string, unknown> {\n if (value.length <= MAX_TEXT_LENGTH) return value\n return {\n preview: `${value.slice(0, MAX_TEXT_LENGTH)}${TRUNCATED}`,\n truncated: true,\n length: value.length,\n }\n}\n\nfunction shouldRedact(key: string): boolean {\n return SECRET_KEYS.has(normalizeKey(key))\n}\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n","import { access, readFile, stat } from 'node:fs/promises'\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport { createHash, randomUUID } from 'node:crypto'\nimport { spawn } from 'node:child_process'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type {\n InspectGateway,\n StructuredData,\n} from '@archships/dim-agent-sdk'\nimport type {\n HookHandlerInput,\n HookName,\n HookPayloadMap,\n HookRegistration,\n HookRegistrationEntry,\n LoggerGateway,\n PluginRuntimeContext,\n} from '@archships/dim-plugin-api'\nimport {\n JournalStore,\n listJsonFiles,\n loadProviderHttpEntries,\n type DevtoolsJournalEntry,\n toStructuredData,\n} from './journal'\n\nexport interface DevtoolsRuntimeOptions {\n hostDataDir: string\n inspect: InspectGateway\n logger: LoggerGateway\n host: string\n port: number\n instanceId?: string\n providerHttpDir?: string\n autoOpenBrowser?: boolean\n}\n\ninterface RuntimePaths {\n instanceId: string\n journalDir: string\n providerHttpDir: string\n}\n\ninterface RequestSummary {\n requestId: string\n sessionId?: string\n iteration?: number\n startedAt: number\n updatedAt: number\n eventCount: number\n model?: string\n stopReason?: string\n}\n\nexport class DevtoolsRuntime {\n private readonly options: DevtoolsRuntimeOptions\n private readonly retainedSessionIds = new Set<string>()\n private readonly subscribers = new Set<ServerResponse>()\n private readonly hooks: HookRegistration\n private initPromise?: Promise<RuntimePaths>\n private journalStore?: JournalStore\n private server?: Server\n private serverUrl?: string\n private startPromise?: Promise<string>\n private browserOpenPromise?: Promise<void>\n private openedBrowserUrl?: string\n\n constructor(options: DevtoolsRuntimeOptions) {\n this.options = options\n this.hooks = createDevtoolsHooks(this)\n }\n\n hookRegistration(): HookRegistration {\n return this.hooks\n }\n\n retainSession(sessionId: string): void {\n this.retainedSessionIds.add(sessionId)\n }\n\n async releaseSession(sessionId: string): Promise<void> {\n this.retainedSessionIds.delete(sessionId)\n if (this.retainedSessionIds.size > 0) return\n await this.closeServer()\n }\n\n async getInspectorUrl(): Promise<string> {\n let url = this.serverUrl\n if (!url) {\n if (this.startPromise) {\n url = await this.startPromise\n } else {\n this.startPromise = this.startServer()\n try {\n url = await this.startPromise\n this.serverUrl = url\n } finally {\n this.startPromise = undefined\n }\n }\n }\n\n if (!url) throw new Error('Devtools inspector URL was not initialized')\n await this.maybeOpenBrowser(url)\n return url\n }\n\n async getInspectorConfig(): Promise<StructuredData> {\n const paths = await this.resolvePaths()\n return {\n instanceId: paths.instanceId,\n journalDir: paths.journalDir,\n providerHttpDir: paths.providerHttpDir,\n host: this.options.host,\n port: this.options.port,\n }\n }\n\n async recordHook<N extends HookName>(\n hook: N,\n payload: HookPayloadMap[N],\n context: PluginRuntimeContext,\n ): Promise<void> {\n const entry: DevtoolsJournalEntry = {\n id: randomUUID(),\n timestamp: Date.now(),\n hook,\n sessionId: context.sessionId,\n requestId: context.requestId,\n iteration: context.iteration,\n ...(context.metadata ? { metadata: toStructuredData(context.metadata) } : {}),\n ...(context.status ? { status: toStructuredData(context.status) } : {}),\n payload: toStructuredData(payload),\n }\n\n const journalStore = await this.getJournalStore()\n this.broadcast('journal', entry)\n await journalStore.append(entry)\n }\n\n async dispose(): Promise<void> {\n await this.closeServer()\n }\n\n private async startServer(): Promise<string> {\n await this.resolvePaths()\n\n const server = createServer((request, response) => {\n void this.handleRequest(request, response).catch((error) => {\n this.sendJson(response, 500, {\n error: error instanceof Error ? error.message : String(error),\n })\n })\n })\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(this.options.port, this.options.host, () => {\n server.off('error', reject)\n resolve()\n })\n })\n\n this.server = server\n const address = server.address()\n const port = typeof address === 'object' && address ? address.port : this.options.port\n const url = `http://${this.options.host}:${port}`\n this.options.logger.emit({\n level: 'info',\n source: 'devtools',\n message: `DIM Devtools inspector listening at ${url}`,\n metadata: {\n url,\n },\n })\n return url\n }\n\n private async closeServer(): Promise<void> {\n for (const subscriber of this.subscribers) subscriber.end()\n this.subscribers.clear()\n\n const server = this.server\n this.server = undefined\n this.serverUrl = undefined\n this.browserOpenPromise = undefined\n this.openedBrowserUrl = undefined\n if (!server) return\n\n await new Promise<void>((resolve) => {\n server.close(() => resolve())\n })\n }\n\n private async handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> {\n const requestUrl = new URL(request.url ?? '/', 'http://127.0.0.1')\n const pathname = requestUrl.pathname\n\n if (pathname === '/api/events') {\n this.handleEventStream(request, response)\n return\n }\n if (pathname === '/api/bootstrap') {\n this.sendJson(response, 200, await this.createBootstrapPayload())\n return\n }\n if (pathname.startsWith('/api/sessions/')) {\n const sessionId = decodeURIComponent(pathname.slice('/api/sessions/'.length))\n this.sendJson(response, 200, await this.createSessionPayload(sessionId))\n return\n }\n if (pathname.startsWith('/api/requests/')) {\n const requestId = decodeURIComponent(pathname.slice('/api/requests/'.length))\n this.sendJson(response, 200, await this.createRequestPayload(requestId))\n return\n }\n\n await this.serveUiAsset(pathname, response)\n }\n\n private handleEventStream(\n request: IncomingMessage,\n response: ServerResponse,\n ): void {\n response.writeHead(200, {\n 'Content-Type': 'text/event-stream; charset=utf-8',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n })\n response.write('retry: 1000\\n')\n response.write(`event: ready\\ndata:${JSON.stringify({ ok: true })}\\n\\n`)\n this.subscribers.add(response)\n\n request.on('close', () => {\n this.subscribers.delete(response)\n response.end()\n })\n }\n\n private broadcast(event: string, payload: unknown): void {\n const line = `event: ${event}\\ndata:${JSON.stringify(payload)}\\n\\n`\n for (const subscriber of [...this.subscribers]) {\n try {\n subscriber.write(line)\n } catch {\n this.subscribers.delete(subscriber)\n subscriber.end()\n }\n }\n }\n\n private async createBootstrapPayload(): Promise<Record<string, unknown>> {\n const [agent, liveSessions, persistedSessions, events, paths] = await Promise.all([\n this.options.inspect.getAgentSnapshot(),\n this.options.inspect.listLiveSessions(),\n this.options.inspect.listPersistedSessions(),\n this.getJournalStore().then((store) => store.list()),\n this.resolvePaths(),\n ])\n\n return {\n agent,\n liveSessions,\n persistedSessions,\n events,\n requestSummaries: buildRequestSummaries(events),\n artifacts: {\n journalDir: paths.journalDir,\n providerHttpDir: paths.providerHttpDir,\n journalFiles: await this.getJournalStore().then((store) => store.listFiles()),\n providerHttpFiles: await listJsonFiles(paths.providerHttpDir),\n },\n }\n }\n\n private async createSessionPayload(sessionId: string): Promise<Record<string, unknown>> {\n const [liveSessions, persistedSnapshot, events] = await Promise.all([\n this.options.inspect.listLiveSessions(),\n this.options.inspect.loadPersistedSession(sessionId),\n this.getJournalStore().then((store) => store.list()),\n ])\n const liveSession = liveSessions.find((entry) => entry.sessionId === sessionId) ?? null\n const sessionEvents = events.filter((entry) => entry.sessionId === sessionId)\n\n return {\n sessionId,\n liveSession,\n persistedSnapshot,\n events: sessionEvents,\n requestSummaries:\n buildRequestSummaries(sessionEvents).sort((left, right) => right.updatedAt - left.updatedAt),\n }\n }\n\n private async createRequestPayload(requestId: string): Promise<Record<string, unknown>> {\n const [events, paths] = await Promise.all([\n this.getJournalStore().then((store) => store.list()),\n this.resolvePaths(),\n ])\n const requestEvents = events.filter((entry) => entry.requestId === requestId)\n const providerEntries = await loadProviderHttpEntries(paths.providerHttpDir, requestId)\n\n return {\n requestId,\n summary: buildRequestSummaries(requestEvents)[0] ?? { requestId },\n events: requestEvents,\n providerEntries,\n }\n }\n\n private async serveUiAsset(pathname: string, response: ServerResponse): Promise<void> {\n const uiRoot = await resolveUiRoot()\n if (!uiRoot) {\n this.sendJson(response, 503, {\n error: 'Devtools UI assets are not built yet. Run the devtools package build first.',\n })\n return\n }\n\n const normalizedPath = pathname === '/' ? '/index.html' : pathname\n const filePath = resolveUiFile(uiRoot, normalizedPath)\n if (!filePath) {\n this.sendJson(response, 404, {\n error: 'Not found',\n })\n return\n }\n\n try {\n await access(filePath)\n const body = await readFile(filePath)\n response.writeHead(200, {\n 'Content-Type': contentTypeForPath(filePath),\n })\n response.end(body)\n } catch {\n this.sendJson(response, 404, {\n error: 'Not found',\n })\n }\n }\n\n private async resolvePaths(): Promise<RuntimePaths> {\n if (this.initPromise) return this.initPromise\n\n this.initPromise = (async () => {\n const agent = await this.options.inspect.getAgentSnapshot()\n const instanceSeed = agent.cwd || this.options.hostDataDir || agent.agentId\n const instanceId =\n this.options.instanceId ??\n createHash('sha1')\n .update(instanceSeed)\n .digest('hex')\n .slice(0, 12)\n const journalDir = path.join(this.options.hostDataDir, 'devtools', instanceId)\n const providerHttpDir = this.options.providerHttpDir\n ? path.resolve(this.options.providerHttpDir)\n : path.join(this.options.hostDataDir, 'provider-http')\n\n this.journalStore = new JournalStore(journalDir)\n return {\n instanceId,\n journalDir,\n providerHttpDir,\n }\n })()\n\n return this.initPromise\n }\n\n private async getJournalStore(): Promise<JournalStore> {\n await this.resolvePaths()\n if (!this.journalStore) throw new Error('Devtools journal store is not initialized')\n return this.journalStore\n }\n\n private sendJson(response: ServerResponse, statusCode: number, payload: unknown): void {\n response.writeHead(statusCode, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n })\n response.end(JSON.stringify(payload))\n }\n\n private async maybeOpenBrowser(url: string): Promise<void> {\n if (this.options.autoOpenBrowser !== true) return\n if (this.openedBrowserUrl === url) return\n if (this.browserOpenPromise) {\n await this.browserOpenPromise\n return\n }\n\n this.browserOpenPromise = launchDefaultBrowser(url)\n .then(() => {\n this.openedBrowserUrl = url\n })\n .catch((error) => {\n this.options.logger.emit({\n level: 'warn',\n source: 'devtools',\n message: `Failed to auto-open DIM Devtools inspector at ${url}`,\n metadata: {\n url,\n error: error instanceof Error ? error.message : String(error),\n },\n })\n })\n .finally(() => {\n this.browserOpenPromise = undefined\n })\n\n await this.browserOpenPromise\n }\n}\n\nfunction createDevtoolsHooks(runtime: DevtoolsRuntime): HookRegistration {\n const orderedHooks: HookName[] = [\n 'run.start',\n 'turn.start',\n 'prompt.resolve',\n 'model.request',\n 'model.event',\n 'tool.beforeExecute',\n 'tool.afterExecute',\n 'notify.message',\n 'snapshot.saved',\n 'run.stop',\n 'run.end',\n 'session.error',\n ]\n const observerHooks: HookName[] = [\n 'run.start',\n 'model.event',\n 'notify.message',\n 'snapshot.saved',\n 'run.stop',\n 'run.end',\n 'session.error',\n ]\n const observerHookSet = new Set(observerHooks)\n\n return orderedHooks.map((name) =>\n observerHookSet.has(name) ? createObserverEntry(name, runtime) : createMiddlewareEntry(name, runtime),\n ) as HookRegistration\n}\n\nfunction createObserverEntry<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n): HookRegistrationEntry<N> {\n return {\n descriptor: { name: hook },\n observers: [createHookObserver(hook, runtime)],\n }\n}\n\nfunction createMiddlewareEntry<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n): HookRegistrationEntry<N> {\n return {\n descriptor: { name: hook },\n middleware: [createHookMiddleware(hook, runtime)],\n }\n}\n\nfunction createHookObserver<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n) {\n return async ({ payload, context }: HookHandlerInput<HookPayloadMap[N]>) => {\n await runtime.recordHook(hook, payload, context)\n }\n}\n\nfunction createHookMiddleware<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n) {\n return async ({ payload, context }: HookHandlerInput<HookPayloadMap[N]>) => {\n await runtime.recordHook(hook, payload, context)\n return payload\n }\n}\n\nfunction buildRequestSummaries(events: DevtoolsJournalEntry[]): RequestSummary[] {\n const byRequestId = new Map<string, RequestSummary>()\n\n for (const event of events) {\n if (!event.requestId) continue\n const existing = byRequestId.get(event.requestId)\n const next =\n existing ??\n ({\n requestId: event.requestId,\n sessionId: event.sessionId,\n iteration: event.iteration,\n startedAt: event.timestamp,\n updatedAt: event.timestamp,\n eventCount: 0,\n } satisfies RequestSummary)\n\n next.eventCount += 1\n next.updatedAt = Math.max(next.updatedAt, event.timestamp)\n next.startedAt = Math.min(next.startedAt, event.timestamp)\n next.sessionId ??= event.sessionId\n next.iteration ??= event.iteration\n next.model ??= readModelLabel(event)\n next.stopReason ??= readStopReason(event)\n byRequestId.set(event.requestId, next)\n }\n\n return [...byRequestId.values()].sort((left, right) => right.updatedAt - left.updatedAt)\n}\n\nfunction readModelLabel(event: DevtoolsJournalEntry): string | undefined {\n if (event.hook !== 'model.request') return undefined\n const request = asRecord(event.payload.request)\n const model = asRecord(request?.model)\n if (!model) return undefined\n if (typeof model.provider !== 'string' || typeof model.modelId !== 'string') return undefined\n return `${model.provider}/${model.modelId}`\n}\n\nfunction readStopReason(event: DevtoolsJournalEntry): string | undefined {\n if (event.hook === 'run.stop') {\n const payload = asRecord(event.payload)\n return typeof payload?.stopReason === 'string' ? payload.stopReason : undefined\n }\n if (event.hook !== 'model.event') return undefined\n const modelEvent = asRecord(event.payload.event)\n if (!modelEvent || modelEvent.type !== 'response_end') return undefined\n return typeof modelEvent.stopReason === 'string' ? modelEvent.stopReason : undefined\n}\n\nfunction asRecord(value: unknown): Record<string, any> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, any>)\n : undefined\n}\n\nasync function resolveUiRoot(): Promise<string | null> {\n const candidates = [\n fileURLToPath(new URL('./ui', import.meta.url)),\n fileURLToPath(new URL('../dist/ui', import.meta.url)),\n fileURLToPath(new URL('../ui', import.meta.url)),\n ]\n\n for (const candidate of candidates) {\n try {\n const info = await stat(candidate)\n if (info.isDirectory()) return candidate\n } catch {\n continue\n }\n }\n\n return null\n}\n\nfunction resolveUiFile(rootDir: string, requestPath: string): string | null {\n const normalized = requestPath.startsWith('/') ? requestPath.slice(1) : requestPath\n const targetPath = path.resolve(rootDir, normalized)\n if (!targetPath.startsWith(path.resolve(rootDir))) return null\n return targetPath\n}\n\nfunction contentTypeForPath(targetPath: string): string {\n const ext = path.extname(targetPath)\n if (ext === '.html') return 'text/html; charset=utf-8'\n if (ext === '.css') return 'text/css; charset=utf-8'\n if (ext === '.js') return 'application/javascript; charset=utf-8'\n if (ext === '.json') return 'application/json; charset=utf-8'\n if (ext === '.svg') return 'image/svg+xml'\n return 'application/octet-stream'\n}\n\nfunction launchDefaultBrowser(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child =\n process.platform === 'darwin'\n ? spawn('open', [url], { detached: true, stdio: 'ignore' })\n : process.platform === 'win32'\n ? spawn('cmd.exe', ['/c', 'start', '', url], {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n })\n : spawn('xdg-open', [url], { detached: true, stdio: 'ignore' })\n\n child.once('error', reject)\n child.once('spawn', () => {\n child.unref()\n resolve()\n })\n })\n}\n","import type {\n DimPlugin,\n HookRegistration,\n PluginSessionControllerContext,\n} from '@archships/dim-plugin-api'\nimport { DevtoolsRuntime, type DevtoolsRuntimeOptions } from './runtime'\n\nexport interface DevtoolsPluginOptions {\n id?: string\n instanceId?: string\n providerHttpDir?: string\n host?: string\n port?: number\n autoOpenBrowser?: boolean\n}\n\nexport interface DevtoolsSessionController {\n getInspectorUrl(): Promise<string>\n}\n\ninterface NormalizedDevtoolsPluginOptions<TId extends string = string> {\n id: TId\n instanceId?: string\n providerHttpDir?: string\n host: string\n port: number\n autoOpenBrowser: boolean\n}\n\nexport function createDevtoolsPlugin(): DimPlugin<'devtools', DevtoolsSessionController>\nexport function createDevtoolsPlugin(\n options: DevtoolsPluginOptions,\n): DimPlugin<'devtools', DevtoolsSessionController>\nexport function createDevtoolsPlugin<TId extends string>(\n options: DevtoolsPluginOptions & { id: TId },\n): DimPlugin<TId, DevtoolsSessionController>\nexport function createDevtoolsPlugin<TId extends string>(\n options: DevtoolsPluginOptions & { id?: TId } = {},\n): DimPlugin<TId, DevtoolsSessionController> {\n const normalized = normalizeOptions(options)\n\n return {\n manifest: {\n id: normalized.id,\n version: '0.1.0',\n apiVersion: 1,\n permissions: {},\n capabilities: ['devtools'],\n },\n setup(context) {\n if (!context.hostDataDir)\n throw new Error(\n 'createDevtoolsPlugin requires createAgent({ hostDataDir }) so journals and inspector state can be persisted outside the workspace',\n )\n\n const runtime = new DevtoolsRuntime({\n hostDataDir: context.hostDataDir,\n inspect: context.services.inspect,\n logger: context.services.logger,\n host: normalized.host,\n port: normalized.port,\n instanceId: normalized.instanceId,\n providerHttpDir: normalized.providerHttpDir,\n autoOpenBrowser: normalized.autoOpenBrowser,\n } satisfies DevtoolsRuntimeOptions)\n\n return {\n inspector: {\n getConfig: async () => ({\n id: normalized.id,\n host: normalized.host,\n port: normalized.port,\n instanceId: normalized.instanceId ?? null,\n providerHttpDir: normalized.providerHttpDir ?? null,\n autoOpenBrowser: normalized.autoOpenBrowser,\n }),\n },\n hooks: runtime.hookRegistration() as HookRegistration,\n createSessionController: (controllerContext) =>\n new DefaultDevtoolsSessionController(runtime, controllerContext),\n }\n },\n }\n}\n\nclass DefaultDevtoolsSessionController implements DevtoolsSessionController {\n private readonly runtime: DevtoolsRuntime\n private readonly context: PluginSessionControllerContext\n private disposed = false\n\n constructor(runtime: DevtoolsRuntime, context: PluginSessionControllerContext) {\n this.runtime = runtime\n this.context = context\n this.runtime.retainSession(context.sessionId)\n }\n\n async getInspectorUrl(): Promise<string> {\n this.assertActive()\n return this.runtime.getInspectorUrl()\n }\n\n async dispose(): Promise<void> {\n if (this.disposed) return\n this.disposed = true\n await this.runtime.releaseSession(this.context.sessionId)\n }\n\n private assertActive(): void {\n if (!this.disposed) return\n throw new Error(`Devtools controller has been disposed: ${this.context.sessionId}`)\n }\n}\n\nfunction normalizeOptions<TId extends string>(\n options: DevtoolsPluginOptions & { id?: TId },\n): NormalizedDevtoolsPluginOptions<TId> {\n return {\n id: (options.id ?? 'devtools') as TId,\n instanceId: options.instanceId?.trim() || undefined,\n providerHttpDir: options.providerHttpDir?.trim() || undefined,\n host: options.host?.trim() || '127.0.0.1',\n port: options.port ?? 0,\n autoOpenBrowser: options.autoOpenBrowser ?? true,\n }\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/journal.ts","../src/runtime.ts","../src/index.ts"],"sourcesContent":["import { appendFile, mkdir, readFile, readdir, stat } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { MetadataMap, StructuredData } from '@archships/dim-agent-sdk'\nimport type { JsonValue } from '@archships/dim-plugin-api'\n\nconst SECRET_KEYS = new Set([\n 'authorization',\n 'proxyauthorization',\n 'apikey',\n 'xapikey',\n 'xgoogapikey',\n 'token',\n 'secret',\n])\nconst MAX_TEXT_LENGTH = 4_000\nconst MAX_ARRAY_ITEMS = 128\nconst TRUNCATED = '[TRUNCATED]'\n\nexport interface DevtoolsJournalEntry {\n id: string\n timestamp: number\n hook: string\n sessionId?: string\n requestId?: string\n iteration?: number\n metadata?: StructuredData\n status?: StructuredData\n payload: StructuredData\n}\n\nexport interface DevtoolsFileSummary {\n name: string\n path: string\n size: number\n mtimeMs: number\n}\n\nexport interface ProviderHttpLogEntry {\n file: string\n path: string\n line: number\n requestId?: string\n event?: string\n entry: StructuredData\n}\n\ninterface ProviderHttpEntryCandidate {\n requestId?: MetadataMap[string]\n event?: MetadataMap[string]\n}\n\ninterface StructuredJsonRecord {\n [key: string]: JsonValue\n}\n\nexport class JournalStore {\n readonly rootDir: string\n readonly eventsPath: string\n\n private entries?: DevtoolsJournalEntry[]\n private writeQueue = Promise.resolve()\n\n constructor(rootDir: string) {\n this.rootDir = path.resolve(rootDir)\n this.eventsPath = path.join(this.rootDir, 'events.jsonl')\n }\n\n async append(entry: DevtoolsJournalEntry): Promise<void> {\n const entries = await this.loadEntries()\n entries.push(structuredClone(entry))\n const line = `${JSON.stringify(entry)}\\n`\n\n this.writeQueue = this.writeQueue\n .catch(() => undefined)\n .then(async () => {\n await mkdir(this.rootDir, { recursive: true })\n await appendFile(this.eventsPath, line, 'utf8')\n })\n .catch(() => undefined)\n\n await this.writeQueue\n }\n\n async list(): Promise<DevtoolsJournalEntry[]> {\n return structuredClone(await this.loadEntries())\n }\n\n async listFiles(): Promise<DevtoolsFileSummary[]> {\n return listJsonFiles(this.rootDir)\n }\n\n private async loadEntries(): Promise<DevtoolsJournalEntry[]> {\n if (this.entries) return this.entries\n\n try {\n const raw = await readFile(this.eventsPath, 'utf8')\n this.entries = raw\n .split('\\n')\n .filter(Boolean)\n .flatMap((line) => {\n try {\n const parsed = JSON.parse(line) as DevtoolsJournalEntry\n if (typeof parsed.id !== 'string' || typeof parsed.hook !== 'string') return []\n return [parsed]\n } catch {\n return []\n }\n })\n } catch {\n this.entries = []\n }\n\n return this.entries\n }\n}\n\nexport async function listJsonFiles(directory: string): Promise<DevtoolsFileSummary[]> {\n try {\n const entries = await readdir(directory, { withFileTypes: true })\n const files = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith('.jsonl'))\n .map(async (entry) => {\n const targetPath = path.join(directory, entry.name)\n const info = await stat(targetPath)\n return {\n name: entry.name,\n path: targetPath,\n size: info.size,\n mtimeMs: info.mtimeMs,\n }\n }),\n )\n\n return files.sort((left, right) => right.mtimeMs - left.mtimeMs)\n } catch {\n return []\n }\n}\n\nexport async function loadProviderHttpEntries(\n directory: string,\n requestId?: string,\n): Promise<ProviderHttpLogEntry[]> {\n const files = await listJsonFiles(directory)\n const entries: ProviderHttpLogEntry[] = []\n\n for (const file of files) {\n let raw: string\n try {\n raw = await readFile(file.path, 'utf8')\n } catch {\n continue\n }\n\n const lines = raw.split('\\n')\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index]?.trim()\n if (!line) continue\n\n try {\n const parsed = JSON.parse(line) as ProviderHttpEntryCandidate\n const currentRequestId = readMetadataString(parsed.requestId)\n if (requestId && currentRequestId !== requestId) continue\n entries.push({\n file: file.name,\n path: file.path,\n line: index + 1,\n requestId: currentRequestId,\n event: readMetadataString(parsed.event),\n entry: toStructuredData(parsed),\n })\n } catch {\n continue\n }\n }\n }\n\n return entries\n}\n\nexport function toStructuredData(value: unknown): StructuredData {\n const sanitized = sanitizeValue(value)\n if (sanitized && typeof sanitized === 'object' && !Array.isArray(sanitized))\n return sanitized as StructuredData\n return sanitized === undefined ? {} : { value: sanitized }\n}\n\nfunction sanitizeValue(\n value: unknown,\n parentKey?: string,\n seen: WeakSet<object> = new WeakSet(),\n): JsonValue | undefined {\n if (parentKey && shouldRedact(parentKey)) return '[REDACTED]'\n if (value === null) return undefined\n if (typeof value === 'number' || typeof value === 'boolean') return value\n if (typeof value === 'string') return sanitizeString(value)\n if (value === undefined) return undefined\n if (typeof value === 'bigint') return value.toString()\n if (typeof value === 'function') return `[Function ${value.name || 'anonymous'}]`\n if (typeof value === 'symbol') return value.toString()\n if (value instanceof Date) return value.toISOString()\n if (value instanceof URL) return value.toString()\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: sanitizeString(value.stack ?? ''),\n }\n }\n if (typeof AbortSignal !== 'undefined' && value instanceof AbortSignal) {\n return {\n type: 'AbortSignal',\n aborted: value.aborted,\n }\n }\n if (typeof Headers !== 'undefined' && value instanceof Headers) {\n const result: StructuredJsonRecord = {}\n value.forEach((entry, key) => {\n const sanitized = sanitizeValue(entry, key, seen)\n if (sanitized !== undefined) result[key] = sanitized\n })\n return result\n }\n if (ArrayBuffer.isView(value)) {\n return {\n type: value.constructor.name,\n byteLength: value.byteLength,\n }\n }\n if (value instanceof ArrayBuffer) {\n return {\n type: 'ArrayBuffer',\n byteLength: value.byteLength,\n }\n }\n if (Array.isArray(value)) {\n const items = value\n .slice(0, MAX_ARRAY_ITEMS)\n .flatMap((item) => {\n const sanitized = sanitizeValue(item, undefined, seen)\n return sanitized === undefined ? [] : [sanitized]\n })\n if (value.length > MAX_ARRAY_ITEMS) {\n items.push({\n truncated: true,\n totalItems: value.length,\n })\n }\n return items\n }\n if (typeof value === 'object') {\n if (seen.has(value)) return '[Circular]'\n seen.add(value)\n const result: StructuredJsonRecord = {}\n for (const [key, child] of Object.entries(value)) {\n const next = sanitizeValue(child, key, seen)\n if (next !== undefined) result[key] = next\n }\n seen.delete(value)\n return result\n }\n\n return sanitizeString(String(value))\n}\n\nfunction sanitizeString(value: string): string | StructuredJsonRecord {\n if (value.length <= MAX_TEXT_LENGTH) return value\n return {\n preview: `${value.slice(0, MAX_TEXT_LENGTH)}${TRUNCATED}`,\n truncated: true,\n length: value.length,\n }\n}\n\nfunction shouldRedact(key: string): boolean {\n return SECRET_KEYS.has(normalizeKey(key))\n}\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n\nfunction readMetadataString(value: MetadataMap[string] | undefined): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n","import { access, readFile, stat } from 'node:fs/promises'\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport { createHash, randomUUID } from 'node:crypto'\nimport { spawn } from 'node:child_process'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type {\n AgentSnapshot,\n InspectGateway,\n LiveSessionInspectSnapshot,\n MetadataMap,\n PersistedSessionSummary,\n SessionSnapshot,\n StructuredData,\n} from '@archships/dim-agent-sdk'\nimport type {\n HookHandlerInput,\n HookName,\n HookPayloadMap,\n HookRegistration,\n HookRegistrationEntry,\n LoggerGateway,\n PluginRuntimeContext,\n} from '@archships/dim-plugin-api'\nimport {\n JournalStore,\n listJsonFiles,\n loadProviderHttpEntries,\n type DevtoolsFileSummary,\n type DevtoolsJournalEntry,\n type ProviderHttpLogEntry,\n toStructuredData,\n} from './journal'\n\nexport interface DevtoolsRuntimeOptions {\n hostDataDir: string\n inspect: InspectGateway\n logger: LoggerGateway\n host: string\n port: number\n instanceId?: string\n providerHttpDir?: string\n autoOpenBrowser?: boolean\n}\n\ninterface RuntimePaths {\n instanceId: string\n journalDir: string\n providerHttpDir: string\n}\n\ninterface RequestSummary {\n requestId: string\n sessionId?: string\n iteration?: number\n startedAt: number\n updatedAt: number\n eventCount: number\n model?: string\n stopReason?: string\n}\n\ninterface RuntimeArtifactsPayload {\n journalDir: string\n providerHttpDir: string\n journalFiles: DevtoolsFileSummary[]\n providerHttpFiles: DevtoolsFileSummary[]\n}\n\ninterface BootstrapPayload {\n agent: AgentSnapshot\n liveSessions: LiveSessionInspectSnapshot[]\n persistedSessions: PersistedSessionSummary[]\n events: DevtoolsJournalEntry[]\n requestSummaries: RequestSummary[]\n artifacts: RuntimeArtifactsPayload\n}\n\ninterface SessionPayload {\n sessionId: string\n liveSession?: LiveSessionInspectSnapshot\n persistedSnapshot?: SessionSnapshot\n events: DevtoolsJournalEntry[]\n requestSummaries: RequestSummary[]\n}\n\ninterface RequestPayload {\n requestId: string\n summary: RequestSummary\n events: DevtoolsJournalEntry[]\n providerEntries: ProviderHttpLogEntry[]\n}\n\ntype DevtoolsJsonPayload = BootstrapPayload | SessionPayload | RequestPayload | { error: string }\n\nexport class DevtoolsRuntime {\n private readonly options: DevtoolsRuntimeOptions\n private readonly retainedSessionIds = new Set<string>()\n private readonly subscribers = new Set<ServerResponse>()\n private readonly hooks: HookRegistration\n private initPromise?: Promise<RuntimePaths>\n private journalStore?: JournalStore\n private server?: Server\n private serverUrl?: string\n private startPromise?: Promise<string>\n private browserOpenPromise?: Promise<void>\n private openedBrowserUrl?: string\n\n constructor(options: DevtoolsRuntimeOptions) {\n this.options = options\n this.hooks = createDevtoolsHooks(this)\n }\n\n hookRegistration(): HookRegistration {\n return this.hooks\n }\n\n retainSession(sessionId: string): void {\n this.retainedSessionIds.add(sessionId)\n }\n\n async releaseSession(sessionId: string): Promise<void> {\n this.retainedSessionIds.delete(sessionId)\n if (this.retainedSessionIds.size > 0) return\n await this.closeServer()\n }\n\n async getInspectorUrl(): Promise<string> {\n let url = this.serverUrl\n if (!url) {\n if (this.startPromise) {\n url = await this.startPromise\n } else {\n this.startPromise = this.startServer()\n try {\n url = await this.startPromise\n this.serverUrl = url\n } finally {\n this.startPromise = undefined\n }\n }\n }\n\n if (!url) throw new Error('Devtools inspector URL was not initialized')\n await this.maybeOpenBrowser(url)\n return url\n }\n\n async getInspectorConfig(): Promise<StructuredData> {\n const paths = await this.resolvePaths()\n return {\n instanceId: paths.instanceId,\n journalDir: paths.journalDir,\n providerHttpDir: paths.providerHttpDir,\n host: this.options.host,\n port: this.options.port,\n }\n }\n\n async recordHook<N extends HookName>(\n hook: N,\n payload: HookPayloadMap[N],\n context: PluginRuntimeContext,\n ): Promise<void> {\n const entry: DevtoolsJournalEntry = {\n id: randomUUID(),\n timestamp: Date.now(),\n hook,\n sessionId: context.sessionId,\n requestId: context.requestId,\n iteration: context.iteration,\n payload: toStructuredData(payload),\n }\n if (context.metadata) entry.metadata = toStructuredData(context.metadata)\n if (context.status) entry.status = toStructuredData(context.status)\n\n const journalStore = await this.getJournalStore()\n this.broadcast('journal', entry)\n await journalStore.append(entry)\n }\n\n async dispose(): Promise<void> {\n await this.closeServer()\n }\n\n private async startServer(): Promise<string> {\n await this.resolvePaths()\n\n const server = createServer((request, response) => {\n void this.handleRequest(request, response).catch((error) => {\n this.sendJson(response, 500, {\n error: error instanceof Error ? error.message : String(error),\n })\n })\n })\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(this.options.port, this.options.host, () => {\n server.off('error', reject)\n resolve()\n })\n })\n\n this.server = server\n const address = server.address()\n const port = typeof address === 'object' && address ? address.port : this.options.port\n const url = `http://${this.options.host}:${port}`\n this.options.logger.emit({\n level: 'info',\n source: 'devtools',\n message: `DIM Devtools inspector listening at ${url}`,\n metadata: {\n url,\n },\n })\n return url\n }\n\n private async closeServer(): Promise<void> {\n for (const subscriber of this.subscribers) subscriber.end()\n this.subscribers.clear()\n\n const server = this.server\n this.server = undefined\n this.serverUrl = undefined\n this.browserOpenPromise = undefined\n this.openedBrowserUrl = undefined\n if (!server) return\n\n await new Promise<void>((resolve) => {\n server.close(() => resolve())\n })\n }\n\n private async handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> {\n const requestUrl = new URL(request.url ?? '/', 'http://127.0.0.1')\n const pathname = requestUrl.pathname\n\n if (pathname === '/api/events') {\n this.handleEventStream(request, response)\n return\n }\n if (pathname === '/api/bootstrap') {\n this.sendJson(response, 200, await this.createBootstrapPayload())\n return\n }\n if (pathname.startsWith('/api/sessions/')) {\n const sessionId = decodeURIComponent(pathname.slice('/api/sessions/'.length))\n this.sendJson(response, 200, await this.createSessionPayload(sessionId))\n return\n }\n if (pathname.startsWith('/api/requests/')) {\n const requestId = decodeURIComponent(pathname.slice('/api/requests/'.length))\n this.sendJson(response, 200, await this.createRequestPayload(requestId))\n return\n }\n\n await this.serveUiAsset(pathname, response)\n }\n\n private handleEventStream(\n request: IncomingMessage,\n response: ServerResponse,\n ): void {\n response.writeHead(200, {\n 'Content-Type': 'text/event-stream; charset=utf-8',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n })\n response.write('retry: 1000\\n')\n response.write(`event: ready\\ndata:${JSON.stringify({ ok: true })}\\n\\n`)\n this.subscribers.add(response)\n\n request.on('close', () => {\n this.subscribers.delete(response)\n response.end()\n })\n }\n\n private broadcast(event: 'journal', payload: DevtoolsJournalEntry): void {\n const line = `event: ${event}\\ndata:${JSON.stringify(payload)}\\n\\n`\n for (const subscriber of [...this.subscribers]) {\n try {\n subscriber.write(line)\n } catch {\n this.subscribers.delete(subscriber)\n subscriber.end()\n }\n }\n }\n\n private async createBootstrapPayload(): Promise<BootstrapPayload> {\n const [agent, liveSessions, persistedSessions, events, paths] = await Promise.all([\n this.options.inspect.getAgentSnapshot(),\n this.options.inspect.listLiveSessions(),\n this.options.inspect.listPersistedSessions(),\n this.getJournalStore().then((store) => store.list()),\n this.resolvePaths(),\n ])\n\n const artifacts: RuntimeArtifactsPayload = {\n journalDir: paths.journalDir,\n providerHttpDir: paths.providerHttpDir,\n journalFiles: await this.getJournalStore().then((store) => store.listFiles()),\n providerHttpFiles: await listJsonFiles(paths.providerHttpDir),\n }\n\n return {\n agent,\n liveSessions,\n persistedSessions,\n events,\n requestSummaries: buildRequestSummaries(events),\n artifacts,\n }\n }\n\n private async createSessionPayload(sessionId: string): Promise<SessionPayload> {\n const [liveSessions, persistedSnapshot, events] = await Promise.all([\n this.options.inspect.listLiveSessions(),\n this.options.inspect.loadPersistedSession(sessionId),\n this.getJournalStore().then((store) => store.list()),\n ])\n const liveSession = liveSessions.find((entry) => entry.sessionId === sessionId)\n const sessionEvents = events.filter((entry) => entry.sessionId === sessionId)\n\n const payload: SessionPayload = {\n sessionId,\n persistedSnapshot,\n events: sessionEvents,\n requestSummaries:\n buildRequestSummaries(sessionEvents).sort((left, right) => right.updatedAt - left.updatedAt),\n }\n if (liveSession) payload.liveSession = liveSession\n return payload\n }\n\n private async createRequestPayload(requestId: string): Promise<RequestPayload> {\n const [events, paths] = await Promise.all([\n this.getJournalStore().then((store) => store.list()),\n this.resolvePaths(),\n ])\n const requestEvents = events.filter((entry) => entry.requestId === requestId)\n const providerEntries = await loadProviderHttpEntries(paths.providerHttpDir, requestId)\n\n return {\n requestId,\n summary: buildRequestSummaries(requestEvents)[0] ?? { requestId },\n events: requestEvents,\n providerEntries,\n }\n }\n\n private async serveUiAsset(pathname: string, response: ServerResponse): Promise<void> {\n const uiRoot = await resolveUiRoot()\n if (!uiRoot) {\n this.sendJson(response, 503, {\n error: 'Devtools UI assets are not built yet. Run the devtools package build first.',\n })\n return\n }\n\n const normalizedPath = pathname === '/' ? '/index.html' : pathname\n const filePath = resolveUiFile(uiRoot, normalizedPath)\n if (!filePath) {\n this.sendJson(response, 404, {\n error: 'Not found',\n })\n return\n }\n\n try {\n await access(filePath)\n const body = await readFile(filePath)\n response.writeHead(200, {\n 'Content-Type': contentTypeForPath(filePath),\n })\n response.end(body)\n } catch {\n this.sendJson(response, 404, {\n error: 'Not found',\n })\n }\n }\n\n private async resolvePaths(): Promise<RuntimePaths> {\n if (this.initPromise) return this.initPromise\n\n this.initPromise = (async () => {\n const agent = await this.options.inspect.getAgentSnapshot()\n const instanceSeed = agent.cwd || this.options.hostDataDir || agent.agentId\n const instanceId =\n this.options.instanceId ??\n createHash('sha1')\n .update(instanceSeed)\n .digest('hex')\n .slice(0, 12)\n const journalDir = path.join(this.options.hostDataDir, 'devtools', instanceId)\n const providerHttpDir = this.options.providerHttpDir\n ? path.resolve(this.options.providerHttpDir)\n : path.join(this.options.hostDataDir, 'provider-http')\n\n this.journalStore = new JournalStore(journalDir)\n return {\n instanceId,\n journalDir,\n providerHttpDir,\n }\n })()\n\n return this.initPromise\n }\n\n private async getJournalStore(): Promise<JournalStore> {\n await this.resolvePaths()\n if (!this.journalStore) throw new Error('Devtools journal store is not initialized')\n return this.journalStore\n }\n\n private sendJson(response: ServerResponse, statusCode: number, payload: DevtoolsJsonPayload): void {\n response.writeHead(statusCode, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n })\n response.end(JSON.stringify(payload))\n }\n\n private async maybeOpenBrowser(url: string): Promise<void> {\n if (this.options.autoOpenBrowser !== true) return\n if (this.openedBrowserUrl === url) return\n if (this.browserOpenPromise) {\n await this.browserOpenPromise\n return\n }\n\n this.browserOpenPromise = launchDefaultBrowser(url)\n .then(() => {\n this.openedBrowserUrl = url\n })\n .catch((error) => {\n this.options.logger.emit({\n level: 'warn',\n source: 'devtools',\n message: `Failed to auto-open DIM Devtools inspector at ${url}`,\n metadata: {\n url,\n error: error instanceof Error ? error.message : String(error),\n },\n })\n })\n .finally(() => {\n this.browserOpenPromise = undefined\n })\n\n await this.browserOpenPromise\n }\n}\n\nfunction createDevtoolsHooks(runtime: DevtoolsRuntime): HookRegistration {\n const orderedHooks: HookName[] = [\n 'run.start',\n 'turn.start',\n 'prompt.resolve',\n 'model.request',\n 'model.event',\n 'tool.beforeExecute',\n 'tool.afterExecute',\n 'notify.message',\n 'snapshot.saved',\n 'run.stop',\n 'run.end',\n 'session.error',\n ]\n const observerHooks: HookName[] = [\n 'run.start',\n 'model.event',\n 'notify.message',\n 'snapshot.saved',\n 'run.stop',\n 'run.end',\n 'session.error',\n ]\n const observerHookSet = new Set(observerHooks)\n\n return orderedHooks.map((name) =>\n observerHookSet.has(name) ? createObserverEntry(name, runtime) : createMiddlewareEntry(name, runtime),\n ) as HookRegistration\n}\n\nfunction createObserverEntry<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n): HookRegistrationEntry<N> {\n return {\n descriptor: { name: hook },\n observers: [createHookObserver(hook, runtime)],\n }\n}\n\nfunction createMiddlewareEntry<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n): HookRegistrationEntry<N> {\n return {\n descriptor: { name: hook },\n middleware: [createHookMiddleware(hook, runtime)],\n }\n}\n\nfunction createHookObserver<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n) {\n return async ({ payload, context }: HookHandlerInput<HookPayloadMap[N]>) => {\n await runtime.recordHook(hook, payload, context)\n }\n}\n\nfunction createHookMiddleware<N extends HookName>(\n hook: N,\n runtime: DevtoolsRuntime,\n) {\n return async ({ payload, context }: HookHandlerInput<HookPayloadMap[N]>) => {\n await runtime.recordHook(hook, payload, context)\n return payload\n }\n}\n\nfunction buildRequestSummaries(events: DevtoolsJournalEntry[]): RequestSummary[] {\n const byRequestId = new Map<string, RequestSummary>()\n\n for (const event of events) {\n if (!event.requestId) continue\n const existing = byRequestId.get(event.requestId)\n const next =\n existing ??\n ({\n requestId: event.requestId,\n sessionId: event.sessionId,\n iteration: event.iteration,\n startedAt: event.timestamp,\n updatedAt: event.timestamp,\n eventCount: 0,\n } satisfies RequestSummary)\n\n next.eventCount += 1\n next.updatedAt = Math.max(next.updatedAt, event.timestamp)\n next.startedAt = Math.min(next.startedAt, event.timestamp)\n next.sessionId ??= event.sessionId\n next.iteration ??= event.iteration\n next.model ??= readModelLabel(event)\n next.stopReason ??= readStopReason(event)\n byRequestId.set(event.requestId, next)\n }\n\n return [...byRequestId.values()].sort((left, right) => right.updatedAt - left.updatedAt)\n}\n\nfunction readModelLabel(event: DevtoolsJournalEntry): string | undefined {\n if (event.hook !== 'model.request') return undefined\n const payload = readStructuredObject(event.payload)\n const request = payload ? readStructuredObject(payload.request) : undefined\n const model = request ? readStructuredObject(request.model) : undefined\n if (!model) return undefined\n if (typeof model.provider !== 'string' || typeof model.modelId !== 'string') return undefined\n return `${model.provider}/${model.modelId}`\n}\n\nfunction readStopReason(event: DevtoolsJournalEntry): string | undefined {\n if (event.hook === 'run.stop') {\n const payload = readStructuredObject(event.payload)\n return typeof payload?.stopReason === 'string' ? payload.stopReason : undefined\n }\n if (event.hook !== 'model.event') return undefined\n const payload = readStructuredObject(event.payload)\n const modelEvent = payload ? readStructuredObject(payload.event) : undefined\n if (!modelEvent || modelEvent.type !== 'response_end') return undefined\n return typeof modelEvent.stopReason === 'string' ? modelEvent.stopReason : undefined\n}\n\nfunction readStructuredObject(value: MetadataMap[string] | StructuredData | undefined): MetadataMap | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as MetadataMap\n}\n\nasync function resolveUiRoot(): Promise<string | undefined> {\n const candidates = [\n fileURLToPath(new URL('./ui', import.meta.url)),\n fileURLToPath(new URL('../dist/ui', import.meta.url)),\n fileURLToPath(new URL('../ui', import.meta.url)),\n ]\n\n for (const candidate of candidates) {\n try {\n const info = await stat(candidate)\n if (info.isDirectory()) return candidate\n } catch {\n continue\n }\n }\n\n return undefined\n}\n\nfunction resolveUiFile(rootDir: string, requestPath: string): string | undefined {\n const normalized = requestPath.startsWith('/') ? requestPath.slice(1) : requestPath\n const targetPath = path.resolve(rootDir, normalized)\n if (!targetPath.startsWith(path.resolve(rootDir))) return undefined\n return targetPath\n}\n\nfunction contentTypeForPath(targetPath: string): string {\n const ext = path.extname(targetPath)\n if (ext === '.html') return 'text/html; charset=utf-8'\n if (ext === '.css') return 'text/css; charset=utf-8'\n if (ext === '.js') return 'application/javascript; charset=utf-8'\n if (ext === '.json') return 'application/json; charset=utf-8'\n if (ext === '.svg') return 'image/svg+xml'\n return 'application/octet-stream'\n}\n\nfunction launchDefaultBrowser(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child =\n process.platform === 'darwin'\n ? spawn('open', [url], { detached: true, stdio: 'ignore' })\n : process.platform === 'win32'\n ? spawn('cmd.exe', ['/c', 'start', '', url], {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n })\n : spawn('xdg-open', [url], { detached: true, stdio: 'ignore' })\n\n child.once('error', reject)\n child.once('spawn', () => {\n child.unref()\n resolve()\n })\n })\n}\n","import type {\n DimPlugin,\n HookRegistration,\n PluginSessionControllerContext,\n} from '@archships/dim-plugin-api'\nimport { DevtoolsRuntime, type DevtoolsRuntimeOptions } from './runtime'\n\nexport interface DevtoolsPluginOptions {\n id?: string\n instanceId?: string\n providerHttpDir?: string\n host?: string\n port?: number\n autoOpenBrowser?: boolean\n}\n\nexport interface DevtoolsSessionController {\n getInspectorUrl(): Promise<string>\n}\n\ninterface NormalizedDevtoolsPluginOptions<TId extends string = string> {\n id: TId\n instanceId?: string\n providerHttpDir?: string\n host: string\n port: number\n autoOpenBrowser: boolean\n}\n\ninterface DevtoolsInspectorConfig {\n id: string\n host: string\n port: number\n instanceId?: string\n providerHttpDir?: string\n autoOpenBrowser: boolean\n}\n\nexport function createDevtoolsPlugin(): DimPlugin<'devtools', DevtoolsSessionController>\nexport function createDevtoolsPlugin(\n options: DevtoolsPluginOptions,\n): DimPlugin<'devtools', DevtoolsSessionController>\nexport function createDevtoolsPlugin<TId extends string>(\n options: DevtoolsPluginOptions & { id: TId },\n): DimPlugin<TId, DevtoolsSessionController>\nexport function createDevtoolsPlugin<TId extends string>(\n options: DevtoolsPluginOptions & { id?: TId } = {},\n): DimPlugin<TId, DevtoolsSessionController> {\n const normalized = normalizeOptions(options)\n\n return {\n manifest: {\n id: normalized.id,\n version: '0.1.0',\n apiVersion: 1,\n permissions: {},\n capabilities: ['devtools'],\n },\n setup(context) {\n if (!context.hostDataDir)\n throw new Error(\n 'createDevtoolsPlugin requires createAgent({ hostDataDir }) so journals and inspector state can be persisted outside the workspace',\n )\n\n const runtime = new DevtoolsRuntime({\n hostDataDir: context.hostDataDir,\n inspect: context.services.inspect,\n logger: context.services.logger,\n host: normalized.host,\n port: normalized.port,\n instanceId: normalized.instanceId,\n providerHttpDir: normalized.providerHttpDir,\n autoOpenBrowser: normalized.autoOpenBrowser,\n } satisfies DevtoolsRuntimeOptions)\n\n return {\n inspector: {\n getConfig: async (): Promise<DevtoolsInspectorConfig> => {\n const config: DevtoolsInspectorConfig = {\n id: normalized.id,\n host: normalized.host,\n port: normalized.port,\n autoOpenBrowser: normalized.autoOpenBrowser,\n }\n if (normalized.instanceId) config.instanceId = normalized.instanceId\n if (normalized.providerHttpDir) config.providerHttpDir = normalized.providerHttpDir\n return config\n },\n },\n hooks: runtime.hookRegistration() as HookRegistration,\n createSessionController: (controllerContext) =>\n new DefaultDevtoolsSessionController(runtime, controllerContext),\n }\n },\n }\n}\n\nclass DefaultDevtoolsSessionController implements DevtoolsSessionController {\n private readonly runtime: DevtoolsRuntime\n private readonly context: PluginSessionControllerContext\n private disposed = false\n\n constructor(runtime: DevtoolsRuntime, context: PluginSessionControllerContext) {\n this.runtime = runtime\n this.context = context\n this.runtime.retainSession(context.sessionId)\n }\n\n async getInspectorUrl(): Promise<string> {\n this.assertActive()\n return this.runtime.getInspectorUrl()\n }\n\n async dispose(): Promise<void> {\n if (this.disposed) return\n this.disposed = true\n await this.runtime.releaseSession(this.context.sessionId)\n }\n\n private assertActive(): void {\n if (!this.disposed) return\n throw new Error(`Devtools controller has been disposed: ${this.context.sessionId}`)\n }\n}\n\nfunction normalizeOptions<TId extends string>(\n options: DevtoolsPluginOptions & { id?: TId },\n): NormalizedDevtoolsPluginOptions<TId> {\n return {\n id: (options.id ?? 'devtools') as TId,\n instanceId: options.instanceId?.trim() || undefined,\n providerHttpDir: options.providerHttpDir?.trim() || undefined,\n host: options.host?.trim() || '127.0.0.1',\n port: options.port ?? 0,\n autoOpenBrowser: options.autoOpenBrowser ?? true,\n }\n}\n"],"mappings":"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"} |
+3
-3
| { | ||
| "name": "@archships/dim-plugin-devtools", | ||
| "version": "0.0.2", | ||
| "version": "0.0.3", | ||
| "description": "Official devtools inspector plugin for dim-agent-sdk.", | ||
@@ -27,4 +27,4 @@ "homepage": "https://dimcode.dev/", | ||
| "devDependencies": { | ||
| "@archships/dim-agent-sdk": "0.0.45", | ||
| "@archships/dim-plugin-api": "0.0.16" | ||
| "@archships/dim-agent-sdk": "0.0.59", | ||
| "@archships/dim-plugin-api": "0.0.25" | ||
| }, | ||
@@ -31,0 +31,0 @@ "scripts": { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
140513
2.47%1555
1.04%2
-33.33%