@kb-labs/shared-testing-e2e 2.118.2 → 2.119.0-canary.0b4b21a55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/mock-cli-input.ts","../src/cli/mock-object.ts","../src/cli/captured-ui.ts","../src/cli/mock-context.ts"],"names":["noopUI"],"mappings":"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","file":"cli.js","sourcesContent":["import type { CLIInput } from '@kb-labs/shared-command-kit';\n\nexport interface MockCLIInputOptions<F> {\n flags?: Partial<F>;\n argv?: string[];\n}\n\n/**\n * Build a typed CLIInput for handler-level tests.\n * Flags not provided default to undefined (matching real CLI behavior when flag is omitted).\n */\nexport function mockCLIInput<F>(opts: MockCLIInputOptions<F> = {}): CLIInput<F> {\n return {\n flags: (opts.flags ?? {}) as F,\n argv: opts.argv ?? [],\n };\n}\n","/**\n * Generic mock factory — creates a partial override of any object/interface.\n * Useful for mocking HTTP clients in handler tests without spawning real daemons.\n *\n * @example\n * const client = mockObject(defaultWorkflowClient, {\n * runWorkflow: async () => ({ runId: 'r-123', status: 'queued' }),\n * })\n */\nexport function mockObject<T extends object>(defaults: T, overrides?: Partial<T>): T {\n return { ...defaults, ...overrides };\n}\n","import { noopUI } from '@kb-labs/plugin-contracts';\nimport type { UIFacade, UILogEntry, MessageOptions, TableColumn, ChainItem } from '@kb-labs/plugin-contracts';\n\nexport interface UICapture {\n /** Arguments passed to ctx.ui.json() */\n json: unknown[];\n /** Arguments passed to ctx.ui.table() */\n table: Array<{ rows: Record<string, unknown>[]; columns?: TableColumn[] }>;\n /** Arguments passed to ctx.ui.success() */\n success: Array<{ message: string; opts?: MessageOptions }>;\n /** First argument of ctx.ui.warn() calls */\n warnings: Array<{ message: string; opts?: MessageOptions }>;\n /** First argument of ctx.ui.error() calls (message or Error.message) */\n errors: string[];\n /** Arguments passed to ctx.ui.info() */\n infos: Array<{ message: string; opts?: MessageOptions }>;\n /** Arguments passed to ctx.ui.log() */\n logs: UILogEntry[];\n /** Raw strings passed to ctx.ui.write() */\n writes: string[];\n /** Arguments passed to ctx.ui.chain() — each element is the full ChainItem[] array */\n chain: ChainItem[][];\n}\n\nexport interface CapturedUI {\n ui: UIFacade;\n captured: UICapture;\n}\n\n/**\n * Creates a UIFacade that records all calls for assertion in handler tests.\n * Non-captured methods fall through to noopUI (spinner, confirm, etc.).\n */\nexport function createCapturedUI(): CapturedUI {\n const captured: UICapture = {\n json: [],\n table: [],\n success: [],\n warnings: [],\n errors: [],\n infos: [],\n logs: [],\n writes: [],\n chain: [],\n };\n\n const ui: UIFacade = {\n ...noopUI,\n\n write(text: string): void {\n captured.writes.push(text);\n },\n\n info(message: string, opts?: MessageOptions): void {\n captured.infos.push({ message, opts });\n },\n\n success(message: string, opts?: MessageOptions): void {\n captured.success.push({ message, opts });\n },\n\n warn(message: string, opts?: MessageOptions): void {\n captured.warnings.push({ message, opts });\n },\n\n error(error: Error | string, opts?: MessageOptions): void {\n captured.errors.push(typeof error === 'string' ? error : error.message);\n if (opts) {\n captured.warnings.push({ message: typeof error === 'string' ? error : error.message, opts });\n }\n },\n\n json(data: unknown): void {\n captured.json.push(data);\n },\n\n table(data: Record<string, unknown>[], columns?: TableColumn[]): void {\n captured.table.push({ rows: data, columns });\n },\n\n log(entry: UILogEntry): void {\n captured.logs.push(entry);\n },\n\n chain(items: ChainItem[]): void {\n captured.chain.push(items);\n },\n };\n\n return { ui, captured };\n}\n","/**\n * @module mock-context\n *\n * Lightweight PluginContextV3 factory for CLI handler tests.\n *\n * Intentionally self-contained — no dependency on @kb-labs/shared-testing\n * or any workspace package beyond plugin-contracts. This keeps the packed\n * tgz usable in isolated e2e environments.\n *\n * Platform, runtime and api fields are minimal vi.fn() stubs covering the\n * subset of APIs that CLI command handlers realistically call. Commands that\n * need richer mocks (LLM, vector store, etc.) should use createTestContext()\n * from @kb-labs/shared-testing directly.\n */\n\nimport { vi } from 'vitest';\nimport { noopUI } from '@kb-labs/plugin-contracts';\nimport type { PluginContextV3, UIFacade } from '@kb-labs/plugin-contracts';\n\nexport interface MockContextOptions {\n /** Override specific UIFacade methods (merged with noopUI). */\n ui?: Partial<UIFacade>;\n /** Working directory (default: process.cwd()) */\n cwd?: string;\n /** Plugin id for trace context */\n pluginId?: string;\n}\n\n/**\n * Creates a minimal PluginContextV3 for CLI handler tests.\n *\n * - ui: combined with noopUI so all methods are safe to call\n * - platform.logger: vi.fn() stubs (info/warn/error/debug/child)\n * - runtime.fs: vi.fn() stubs for common FS operations\n * - runtime.fetch / runtime.env: vi.fn() stubs\n * - api: vi.fn() stubs for lifecycle and state\n *\n * Use with createCapturedUI() to assert on command output:\n * ```typescript\n * const { ui, captured } = createCapturedUI();\n * const ctx = createMockContext({ ui });\n * ```\n */\nexport function createMockContext(opts: MockContextOptions = {}): PluginContextV3 {\n const ui: UIFacade = opts.ui ? { ...noopUI, ...opts.ui } : noopUI;\n\n // Minimal logger stub — commands may call ctx.platform.logger.*\n const noopLogger = {\n info: vi.fn(),\n warn: vi.fn(),\n error: vi.fn(),\n debug: vi.fn(),\n child: vi.fn().mockReturnThis(),\n };\n\n // Minimal platform — only logger is wired; everything else is an empty stub.\n // CLI commands that need LLM/cache/storage should use @kb-labs/shared-testing.\n const platform = {\n logger: noopLogger,\n } as unknown as PluginContextV3['platform'];\n\n // Minimal runtime — covers fs.glob / fs.readFile used by some commands (e.g. review)\n const runtime = {\n fs: {\n readFile: vi.fn(async () => ''),\n readFileBuffer: vi.fn(async () => new Uint8Array()),\n writeFile: vi.fn(async () => {}),\n readdir: vi.fn(async () => []),\n readdirWithStats: vi.fn(async () => []),\n mkdir: vi.fn(async () => {}),\n rm: vi.fn(async () => {}),\n copy: vi.fn(async () => {}),\n move: vi.fn(async () => {}),\n glob: vi.fn(async () => []),\n stat: vi.fn(async () => ({ isFile: () => false, isDirectory: () => false, size: 0, mtime: 0, ctime: 0 })),\n exists: vi.fn(async () => false),\n resolve: (p: string) => p,\n relative: (p: string) => p,\n join: (...s: string[]) => s.join('/'),\n dirname: (p: string) => p.split('/').slice(0, -1).join('/'),\n basename: (p: string) => p.split('/').pop() ?? '',\n extname: (p: string) => { const b = p.split('/').pop() ?? ''; const i = b.lastIndexOf('.'); return i > 0 ? b.slice(i) : ''; },\n },\n fetch: vi.fn(async () => new Response('mock')),\n env: vi.fn((_key: string) => undefined),\n } as unknown as PluginContextV3['runtime'];\n\n // Minimal api — covers the lifecycle and state methods most commands might call\n const api = {\n lifecycle: { onCleanup: vi.fn() },\n state: {\n get: vi.fn(async () => undefined),\n set: vi.fn(async () => {}),\n delete: vi.fn(async () => {}),\n has: vi.fn(async () => false),\n },\n shell: { exec: vi.fn(async () => ({ code: 0, stdout: '', stderr: '', ok: true })) },\n events: { emit: vi.fn(async () => {}) },\n } as unknown as PluginContextV3['api'];\n\n return {\n host: 'cli',\n requestId: 'test-request-id',\n pluginId: opts.pluginId ?? 'test-plugin',\n pluginVersion: '0.0.0',\n cwd: opts.cwd ?? process.cwd(),\n trace: {\n traceId: 'test-trace-id',\n spanId: 'test-span-id',\n parentSpanId: undefined,\n addEvent: () => {},\n setAttribute: () => {},\n recordError: () => {},\n },\n hostContext: { host: 'cli', argv: [] } as unknown as PluginContextV3['hostContext'],\n ui,\n platform,\n runtime,\n api,\n };\n}\n"]}
1
+ {"version":3,"sources":["../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/cli/mock-cli-input.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/cli/mock-object.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/cli/captured-ui.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/cli/mock-context.ts"],"names":["noopUI"],"mappings":"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","file":"cli.js","sourcesContent":["import type { CLIInput } from '@kb-labs/shared-command-kit';\n\nexport interface MockCLIInputOptions<F> {\n flags?: Partial<F>;\n argv?: string[];\n}\n\n/**\n * Build a typed CLIInput for handler-level tests.\n * Flags not provided default to undefined (matching real CLI behavior when flag is omitted).\n */\nexport function mockCLIInput<F>(opts: MockCLIInputOptions<F> = {}): CLIInput<F> {\n return {\n flags: (opts.flags ?? {}) as F,\n argv: opts.argv ?? [],\n };\n}\n","/**\n * Generic mock factory — creates a partial override of any object/interface.\n * Useful for mocking HTTP clients in handler tests without spawning real daemons.\n *\n * @example\n * const client = mockObject(defaultWorkflowClient, {\n * runWorkflow: async () => ({ runId: 'r-123', status: 'queued' }),\n * })\n */\nexport function mockObject<T extends object>(defaults: T, overrides?: Partial<T>): T {\n return { ...defaults, ...overrides };\n}\n","import { noopUI } from '@kb-labs/plugin-contracts';\nimport type { UIFacade, UILogEntry, MessageOptions, TableColumn, ChainItem } from '@kb-labs/plugin-contracts';\n\nexport interface UICapture {\n /** Arguments passed to ctx.ui.json() */\n json: unknown[];\n /** Arguments passed to ctx.ui.table() */\n table: Array<{ rows: Record<string, unknown>[]; columns?: TableColumn[] }>;\n /** Arguments passed to ctx.ui.success() */\n success: Array<{ message: string; opts?: MessageOptions }>;\n /** First argument of ctx.ui.warn() calls */\n warnings: Array<{ message: string; opts?: MessageOptions }>;\n /** First argument of ctx.ui.error() calls (message or Error.message) */\n errors: string[];\n /** Arguments passed to ctx.ui.info() */\n infos: Array<{ message: string; opts?: MessageOptions }>;\n /** Arguments passed to ctx.ui.log() */\n logs: UILogEntry[];\n /** Raw strings passed to ctx.ui.write() */\n writes: string[];\n /** Arguments passed to ctx.ui.chain() — each element is the full ChainItem[] array */\n chain: ChainItem[][];\n}\n\nexport interface CapturedUI {\n ui: UIFacade;\n captured: UICapture;\n}\n\n/**\n * Creates a UIFacade that records all calls for assertion in handler tests.\n * Non-captured methods fall through to noopUI (spinner, confirm, etc.).\n */\nexport function createCapturedUI(): CapturedUI {\n const captured: UICapture = {\n json: [],\n table: [],\n success: [],\n warnings: [],\n errors: [],\n infos: [],\n logs: [],\n writes: [],\n chain: [],\n };\n\n const ui: UIFacade = {\n ...noopUI,\n\n write(text: string): void {\n captured.writes.push(text);\n },\n\n info(message: string, opts?: MessageOptions): void {\n captured.infos.push({ message, opts });\n },\n\n success(message: string, opts?: MessageOptions): void {\n captured.success.push({ message, opts });\n },\n\n warn(message: string, opts?: MessageOptions): void {\n captured.warnings.push({ message, opts });\n },\n\n error(error: Error | string, opts?: MessageOptions): void {\n captured.errors.push(typeof error === 'string' ? error : error.message);\n if (opts) {\n captured.warnings.push({ message: typeof error === 'string' ? error : error.message, opts });\n }\n },\n\n json(data: unknown): void {\n captured.json.push(data);\n },\n\n table(data: Record<string, unknown>[], columns?: TableColumn[]): void {\n captured.table.push({ rows: data, columns });\n },\n\n log(entry: UILogEntry): void {\n captured.logs.push(entry);\n },\n\n chain(items: ChainItem[]): void {\n captured.chain.push(items);\n },\n };\n\n return { ui, captured };\n}\n","/**\n * @module mock-context\n *\n * Lightweight PluginContextV3 factory for CLI handler tests.\n *\n * Intentionally self-contained — no dependency on @kb-labs/shared-testing\n * or any workspace package beyond plugin-contracts. This keeps the packed\n * tgz usable in isolated e2e environments.\n *\n * Platform, runtime and api fields are minimal vi.fn() stubs covering the\n * subset of APIs that CLI command handlers realistically call. Commands that\n * need richer mocks (LLM, vector store, etc.) should use createTestContext()\n * from @kb-labs/shared-testing directly.\n */\n\nimport { vi } from 'vitest';\nimport { noopUI } from '@kb-labs/plugin-contracts';\nimport type { PluginContextV3, UIFacade } from '@kb-labs/plugin-contracts';\n\nexport interface MockContextOptions {\n /** Override specific UIFacade methods (merged with noopUI). */\n ui?: Partial<UIFacade>;\n /** Working directory (default: process.cwd()) */\n cwd?: string;\n /** Plugin id for trace context */\n pluginId?: string;\n}\n\n/**\n * Creates a minimal PluginContextV3 for CLI handler tests.\n *\n * - ui: combined with noopUI so all methods are safe to call\n * - platform.logger: vi.fn() stubs (info/warn/error/debug/child)\n * - runtime.fs: vi.fn() stubs for common FS operations\n * - runtime.fetch / runtime.env: vi.fn() stubs\n * - api: vi.fn() stubs for lifecycle and state\n *\n * Use with createCapturedUI() to assert on command output:\n * ```typescript\n * const { ui, captured } = createCapturedUI();\n * const ctx = createMockContext({ ui });\n * ```\n */\nexport function createMockContext(opts: MockContextOptions = {}): PluginContextV3 {\n const ui: UIFacade = opts.ui ? { ...noopUI, ...opts.ui } : noopUI;\n\n // Minimal logger stub — commands may call ctx.platform.logger.*\n const noopLogger = {\n info: vi.fn(),\n warn: vi.fn(),\n error: vi.fn(),\n debug: vi.fn(),\n child: vi.fn().mockReturnThis(),\n };\n\n // Minimal platform — only logger is wired; everything else is an empty stub.\n // CLI commands that need LLM/cache/storage should use @kb-labs/shared-testing.\n const platform = {\n logger: noopLogger,\n } as unknown as PluginContextV3['platform'];\n\n // Minimal runtime — covers fs.glob / fs.readFile used by some commands (e.g. review)\n const runtime = {\n fs: {\n readFile: vi.fn(async () => ''),\n readFileBuffer: vi.fn(async () => new Uint8Array()),\n writeFile: vi.fn(async () => {}),\n readdir: vi.fn(async () => []),\n readdirWithStats: vi.fn(async () => []),\n mkdir: vi.fn(async () => {}),\n rm: vi.fn(async () => {}),\n copy: vi.fn(async () => {}),\n move: vi.fn(async () => {}),\n glob: vi.fn(async () => []),\n stat: vi.fn(async () => ({ isFile: () => false, isDirectory: () => false, size: 0, mtime: 0, ctime: 0 })),\n exists: vi.fn(async () => false),\n resolve: (p: string) => p,\n relative: (p: string) => p,\n join: (...s: string[]) => s.join('/'),\n dirname: (p: string) => p.split('/').slice(0, -1).join('/'),\n basename: (p: string) => p.split('/').pop() ?? '',\n extname: (p: string) => { const b = p.split('/').pop() ?? ''; const i = b.lastIndexOf('.'); return i > 0 ? b.slice(i) : ''; },\n },\n fetch: vi.fn(async () => new Response('mock')),\n env: vi.fn((_key: string) => undefined),\n } as unknown as PluginContextV3['runtime'];\n\n // Minimal api — covers the lifecycle and state methods most commands might call\n const api = {\n lifecycle: { onCleanup: vi.fn() },\n state: {\n get: vi.fn(async () => undefined),\n set: vi.fn(async () => {}),\n delete: vi.fn(async () => {}),\n has: vi.fn(async () => false),\n },\n shell: { exec: vi.fn(async () => ({ code: 0, stdout: '', stderr: '', ok: true })) },\n events: { emit: vi.fn(async () => {}) },\n } as unknown as PluginContextV3['api'];\n\n return {\n host: 'cli',\n requestId: 'test-request-id',\n pluginId: opts.pluginId ?? 'test-plugin',\n pluginVersion: '0.0.0',\n cwd: opts.cwd ?? process.cwd(),\n trace: {\n traceId: 'test-trace-id',\n spanId: 'test-span-id',\n parentSpanId: undefined,\n addEvent: () => {},\n setAttribute: () => {},\n recordError: () => {},\n },\n hostContext: { host: 'cli', argv: [] } as unknown as PluginContextV3['hostContext'],\n ui,\n platform,\n runtime,\n api,\n };\n}\n"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/diag-collector.ts","../src/workspace-root.ts","../src/kb-dev-controller.ts","../src/diag-snapshot-hook.ts","../src/http-client.ts","../src/ws-client.ts","../src/sse-reader.ts","../src/jwt-helpers.ts","../src/isolated-project-root.ts","../src/namespace.ts","../src/sse/collect.ts","../src/sse/assert.ts","../src/ws/lifecycle.ts","../src/ws/assert.ts"],"names":["resolve","existsSync","writeFile"],"mappings":"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","file":"index.js","sourcesContent":["import { writeFile } from 'node:fs/promises';\n\nimport type {\n AdapterStageTrace,\n ConfigLayersDiag,\n DiagSnapshot,\n KbLogEvent,\n PluginDiscoveryDiag,\n PluginGovernanceTrace,\n ServiceDiag,\n} from './diag-types.js';\nimport type { StatusSnapshot } from './types.js';\n\n/**\n * Collects KB_DEBUG diagnostic events emitted by service processes.\n *\n * Instantiated by KbDevController when KB_DEBUG=true. Each stdout line from\n * subprocesses passes through parseLine(); lines that carry a kb.diag.* event\n * are parsed and routed into per-domain buckets. buildSnapshot() assembles the\n * final DiagSnapshot for attachment to failed tests.\n */\nexport class DiagCollector {\n private readonly pipelineTraces: AdapterStageTrace[] = [];\n private readonly governanceTraces: PluginGovernanceTrace[] = [];\n private configDiag: Partial<ConfigLayersDiag> = {};\n private discoveryDiag: Partial<PluginDiscoveryDiag> = {};\n private serviceMap: Record<string, ServiceDiag> = {};\n\n /**\n * Parse a single stdout line from a service process.\n * Lines that do not contain a kb.diag.* event are ignored cheaply.\n */\n parseLine(line: string): void {\n // Fast string check before JSON.parse to avoid cost on ordinary log lines\n if (!line.includes('\"event\":\"kb.diag.')) { return; }\n try {\n const obj = JSON.parse(line) as KbLogEvent;\n if (typeof obj.event !== 'string' || obj.v !== 1) { return; }\n switch (obj.event) {\n case 'kb.diag.pipeline':\n this.pipelineTraces.push(...(obj.data as AdapterStageTrace[]));\n break;\n case 'kb.diag.governance':\n this.governanceTraces.push(obj.data as PluginGovernanceTrace);\n break;\n case 'kb.diag.config':\n this.configDiag = obj.data as ConfigLayersDiag;\n break;\n case 'kb.diag.discovery':\n this.discoveryDiag = obj.data as PluginDiscoveryDiag;\n break;\n }\n } catch {\n // Malformed line — silently ignore; never throw inside logSink\n }\n }\n\n /** Merge live service status into the snapshot (call after ensureServices/status). */\n ingestStatusSnapshot(snap: StatusSnapshot): void {\n for (const [id, svc] of Object.entries(snap.services)) {\n this.serviceMap[id] = {\n port: svc.port,\n pid: svc.pid,\n url: svc.url,\n state: svc.state,\n };\n }\n }\n\n buildSnapshot(): DiagSnapshot {\n return {\n schemaVersion: 1,\n capturedAt: new Date().toISOString(),\n pipeline: [...this.pipelineTraces],\n governance: [...this.governanceTraces],\n config: { ...this.configDiag },\n discovery: { ...this.discoveryDiag },\n services: { ...this.serviceMap },\n };\n }\n\n async writeSnapshot(path: string): Promise<void> {\n const snapshot = this.buildSnapshot();\n await writeFile(path, JSON.stringify(snapshot, null, 2), 'utf8');\n }\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Walk up from a starting directory until we find a KB Labs workspace root.\n * Recognises both `.kb/devservices.yaml` (runtime, generated by kb-create) and\n * `.kb/devservices.dev.yaml` (committed, present in CI checkouts).\n * Returns the absolute path of the project root, or `null` if not found.\n */\nexport function findWorkspaceRoot(startDir?: string): string | null {\n let dir = startDir ?? process.cwd();\n // Safety: bail after 20 levels so we never climb past `/`.\n for (let i = 0; i < 20; i++) {\n if (\n existsSync(resolve(dir, '.kb/devservices.yaml')) ||\n existsSync(resolve(dir, '.kb/devservices.dev.yaml'))\n ) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the workspace root for the current package, honoring env overrides.\n * Precedence:\n * 1. `KB_PROJECT_ROOT` env var (matches kb-dev itself).\n * 2. Walk up from `process.cwd()`.\n * 3. Walk up from this source file's directory (handles running tests\n * from deeply nested package dirs).\n *\n * Throws if no root can be located.\n */\nexport function resolveWorkspaceRoot(): string {\n const fromEnv = process.env.KB_PROJECT_ROOT;\n if (fromEnv && existsSync(resolve(fromEnv, '.kb/devservices.yaml'))) {\n return fromEnv;\n }\n const fromCwd = findWorkspaceRoot(process.cwd());\n if (fromCwd) {\n return fromCwd;\n }\n const here = dirname(fileURLToPath(import.meta.url));\n const fromHere = findWorkspaceRoot(here);\n if (fromHere) {\n return fromHere;\n }\n throw new Error(\n 'Could not locate KB Labs workspace root (.kb/devservices.yaml). ' +\n 'Set KB_PROJECT_ROOT or run from inside the workspace.',\n );\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { DiagCollector } from './diag-collector.js';\nimport type {\n EnsureOptions,\n KbDevControllerOptions,\n KbDevResult,\n ServiceId,\n ServiceStatus,\n StatusSnapshot,\n} from './types.js';\nimport { resolveWorkspaceRoot } from './workspace-root.js';\n\n/**\n * Ring buffer for the last N lines of subprocess output.\n * Used so that on failure the harness can dump recent kb-dev noise\n * into the test output without swamping it with tens of thousands of lines.\n */\nclass RingBuffer {\n private buf: string[] = [];\n constructor(private readonly capacity: number) {}\n push(line: string): void {\n this.buf.push(line);\n if (this.buf.length > this.capacity) {\n this.buf.splice(0, this.buf.length - this.capacity);\n }\n }\n snapshot(): string[] {\n return [...this.buf];\n }\n}\n\ninterface SubprocessResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/**\n * Controller that drives kb-dev as a subprocess and exposes its JSON\n * agent protocol as a typed TypeScript API for e2e tests.\n *\n * Lifecycle: one controller per test file (beforeAll/afterAll).\n * Services booted through this controller are shared across every\n * `describe`/`it` in that file.\n */\nexport class KbDevController {\n readonly projectRoot: string;\n readonly kbDevBin: string;\n private readonly env: Record<string, string>;\n private readonly logSink?: (line: string) => void;\n private readonly ring = new RingBuffer(400);\n /** Services this controller started (and therefore should clean up). */\n private readonly startedByUs = new Set<ServiceId>();\n /** Cached last status snapshot (invalidated on any mutating call). */\n private lastStatus?: StatusSnapshot;\n /** Collects KB_DEBUG diagnostic events from service stdout. Undefined when KB_DEBUG is not set. */\n private readonly diagCollector: DiagCollector | undefined;\n\n constructor(opts: KbDevControllerOptions = {}) {\n this.projectRoot = opts.projectRoot ?? resolveWorkspaceRoot();\n this.kbDevBin = opts.kbDevBin ?? resolve(this.projectRoot, 'tools/kb-dev/kb-dev');\n if (!existsSync(this.kbDevBin)) {\n throw new Error(\n `kb-dev binary not found at ${this.kbDevBin}. ` +\n 'Build it with: cd tools/kb-dev && make build',\n );\n }\n this.env = {\n ...process.env as Record<string, string>,\n ...(opts.env ?? {}),\n KB_PROJECT_ROOT: this.projectRoot,\n };\n this.logSink = opts.logSink;\n // env is fully resolved at this point — reads KB_DEBUG from process.env or opts.env\n this.diagCollector = this.env.KB_DEBUG === 'true' ? new DiagCollector() : undefined;\n }\n\n /** Returns the DiagCollector instance, or undefined when KB_DEBUG is not set. */\n getDiagCollector(): DiagCollector | undefined {\n return this.diagCollector;\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n /**\n * Ensure every listed service is `alive`. Idempotent — if a service is\n * already running, kb-dev reports `skipped` and we don't respawn.\n *\n * Throws with a formatted hint + recent log tail on failure.\n */\n async ensureServices(\n ids: ServiceId[],\n opts: EnsureOptions = {},\n ): Promise<StatusSnapshot> {\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const args = ['ensure', ...ids, '--json'];\n if (opts.force) {args.push('--force');}\n\n const result = await this.runJson<KbDevResult>(args, timeoutMs);\n if (!result.ok) {\n throw this.formatError(`kb-dev ensure ${ids.join(' ')}`, result);\n }\n for (const action of result.actions ?? []) {\n if (action.action === 'started') {\n this.startedByUs.add(action.service as ServiceId);\n }\n }\n // Poll status until every requested service is alive (ensure returns\n // when spawn completes, but health may still be warming up).\n const snapshot = await this.waitUntilAlive(ids, timeoutMs);\n this.lastStatus = snapshot;\n this.diagCollector?.ingestStatusSnapshot(snapshot);\n return snapshot;\n }\n\n /**\n * Block until a single service reports `alive` or the timeout expires.\n */\n async ready(id: ServiceId, timeoutMs = 60_000): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const snap = await this.status();\n const svc = snap.services[id];\n if (svc?.state === 'alive') {return;}\n if (svc?.state === 'failed') {\n throw new Error(\n `Service ${id} entered 'failed' state.\\n` +\n `Logs tail:\\n${(svc.logsTail ?? []).join('\\n')}`,\n );\n }\n await sleep(500);\n }\n throw new Error(`Timeout waiting for ${id} to become alive (${timeoutMs}ms)`);\n }\n\n /** Query current status for all services. */\n async status(): Promise<StatusSnapshot> {\n const result = await this.runJson<StatusSnapshot>(['status', '--json'], 10_000);\n this.lastStatus = result;\n this.diagCollector?.ingestStatusSnapshot(result);\n return result;\n }\n\n /**\n * Stop the given services (or everything this controller started, if none given).\n * Always best-effort — errors are logged but never thrown.\n */\n async stopServices(ids?: ServiceId[]): Promise<void> {\n const toStop = ids ?? Array.from(this.startedByUs);\n if (toStop.length === 0) {return;}\n try {\n await this.runJson<KbDevResult>(['stop', ...toStop, '--json'], 30_000);\n } catch (err) {\n // Stop failures should never mask the real test failure.\n this.logSink?.(`[kb-dev] stop failed (ignored): ${(err as Error).message}`);\n }\n for (const id of toStop) {this.startedByUs.delete(id);}\n this.lastStatus = undefined;\n }\n\n /** Disposes the controller — stops every service it started. */\n async dispose(): Promise<void> {\n await this.stopServices();\n }\n\n /**\n * Return the HTTP base URL for a service, e.g. `http://localhost:4000`.\n * Throws if the service is not in the last known status snapshot or has no URL.\n */\n getServiceUrl(id: ServiceId): string {\n const svc = this.requireService(id);\n if (!svc.url) {\n throw new Error(`Service ${id} has no URL in its status (state=${svc.state})`);\n }\n return svc.url;\n }\n\n /** Return the port for a service, or throw if unknown. */\n getServicePort(id: ServiceId): number {\n const svc = this.requireService(id);\n if (!svc.port) {\n throw new Error(`Service ${id} has no port in its status (state=${svc.state})`);\n }\n return svc.port;\n }\n\n /** Snapshot of recent subprocess log lines, newest last. */\n dumpRecentLogs(): string[] {\n return this.ring.snapshot();\n }\n\n // ── Internals ─────────────────────────────────────────────────────────────\n\n private requireService(id: ServiceId): ServiceStatus {\n if (!this.lastStatus) {\n throw new Error(\n `No status snapshot yet for ${id}. Call ensureServices() or status() first.`,\n );\n }\n const svc = this.lastStatus.services[id];\n if (!svc) {\n throw new Error(`Service ${id} not found in status snapshot`);\n }\n return svc;\n }\n\n private async waitUntilAlive(\n ids: ServiceId[],\n timeoutMs: number,\n ): Promise<StatusSnapshot> {\n const deadline = Date.now() + timeoutMs;\n let lastSnap: StatusSnapshot | undefined;\n while (Date.now() < deadline) {\n lastSnap = await this.status();\n const allAlive = ids.every((id) => lastSnap?.services[id]?.state === 'alive');\n if (allAlive) {return lastSnap;}\n // Fail fast on hard failures — no point waiting for a service already marked `failed`.\n const failed = ids.find((id) => lastSnap?.services[id]?.state === 'failed');\n if (failed) {\n const svc = lastSnap!.services[failed]!;\n throw new Error(\n `Service ${failed} failed during ensure.\\n` +\n `Logs tail:\\n${(svc.logsTail ?? []).join('\\n')}`,\n );\n }\n await sleep(500);\n }\n throw new Error(\n `Timeout waiting for services to become alive: ${ids.join(', ')}.\\n` +\n `Last known states: ${ids\n .map((id) => `${id}=${lastSnap?.services[id]?.state ?? 'unknown'}`)\n .join(', ')}`,\n );\n }\n\n private formatError(prefix: string, result: KbDevResult): Error {\n const lines: string[] = [`${prefix} failed`];\n if (result.hint) {lines.push(`Hint: ${result.hint}`);}\n for (const action of result.actions ?? []) {\n if (action.action === 'failed' || action.error) {\n lines.push(` - ${action.service}: ${action.error ?? 'failed'}`);\n for (const log of action.logsTail ?? []) {\n lines.push(` ${log}`);\n }\n }\n }\n const recent = this.ring.snapshot();\n if (recent.length > 0) {\n lines.push('Recent kb-dev output:');\n for (const l of recent.slice(-40)) {lines.push(` ${l}`);}\n }\n return new Error(lines.join('\\n'));\n }\n\n /**\n * Run a kb-dev subcommand and parse the stdout as JSON.\n * kb-dev prints only the JSON object on stdout when `--json` is set;\n * any logs go to stderr.\n */\n private async runJson<T>(args: string[], timeoutMs: number): Promise<T> {\n const result = await this.run(args, timeoutMs);\n if (result.code !== 0 && !result.stdout.trim()) {\n throw new Error(\n `kb-dev ${args.join(' ')} exited with code ${result.code}\\n` +\n `stderr:\\n${result.stderr}`,\n );\n }\n try {\n return JSON.parse(result.stdout) as T;\n } catch (err) {\n throw new Error(\n `Failed to parse JSON from \\`kb-dev ${args.join(' ')}\\`:\\n` +\n ` error: ${(err as Error).message}\\n` +\n ` stdout: ${result.stdout.slice(0, 2000)}\\n` +\n ` stderr: ${result.stderr.slice(0, 2000)}`,\n );\n }\n }\n\n private run(args: string[], timeoutMs: number): Promise<SubprocessResult> {\n return new Promise((resolvePromise) => {\n const child = spawn(this.kbDevBin, args, {\n cwd: this.projectRoot,\n env: this.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n const onLine = (chunk: Buffer, stream: 'stdout' | 'stderr') => {\n const text = chunk.toString();\n if (stream === 'stdout') {stdout += text;}\n else {stderr += text;}\n for (const line of text.split('\\n')) {\n if (line) {\n this.ring.push(`[${stream}] ${line}`);\n this.logSink?.(`[kb-dev ${args[0]}] [${stream}] ${line}`);\n if (stream === 'stdout') {\n this.diagCollector?.parseLine(line);\n }\n }\n }\n };\n\n child.stdout.on('data', (d: Buffer) => onLine(d, 'stdout'));\n child.stderr.on('data', (d: Buffer) => onLine(d, 'stderr'));\n\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n }, timeoutMs);\n\n child.on('close', (code) => {\n clearTimeout(timer);\n resolvePromise({ code: code ?? -1, stdout, stderr });\n });\n child.on('error', (err) => {\n clearTimeout(timer);\n resolvePromise({ code: -1, stdout, stderr: stderr + '\\n' + err.message });\n });\n });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => { setTimeout(r, ms); });\n}\n","import type { KbDevController } from './kb-dev-controller.js';\n\nconst SNAPSHOT_PATH = '/tmp/kb-e2e-diag.json';\n\n/**\n * Register a Vitest onTestFailed hook that writes a DiagSnapshot when a test fails.\n *\n * Safe to call in non-Vitest environments (Playwright, Node scripts) — the vitest\n * import is dynamic and failures are caught silently.\n *\n * Usage in beforeAll:\n * await registerDiagSnapshotHook(ctrl);\n */\nexport async function registerDiagSnapshotHook(ctrl: KbDevController): Promise<void> {\n // Dynamic import keeps this file free of static vitest dep (Playwright-safe)\n const vitest = await import('vitest').catch(() => null);\n if (!vitest?.onTestFailed) { return; }\n\n vitest.onTestFailed(async () => {\n const collector = ctrl.getDiagCollector();\n if (!collector) { return; }\n\n try {\n await collector.writeSnapshot(SNAPSHOT_PATH);\n\n // Vitest 3.x attachment API — degrade gracefully if unavailable\n try {\n const { inject } = await import('vitest');\n const attachments = (inject as (key: string) => unknown | undefined)('testAttachments') as\n | { attach(name: string, opts: { path: string; contentType: string }): Promise<void> }\n | undefined;\n await attachments?.attach('kb-e2e-diag.json', {\n path: SNAPSHOT_PATH,\n contentType: 'application/json',\n });\n } catch {\n process.stderr.write(`[KB_DEBUG] DiagSnapshot written to ${SNAPSHOT_PATH}\\n`);\n }\n } catch {\n // Never let a diagnostic failure propagate into the test result\n }\n });\n}\n","/**\n * Minimal HTTP client wrapper used by e2e tests.\n *\n * Intentionally thin — tests should be able to read one line and know\n * exactly what request went out. No retries, no interceptors, no magic.\n */\n\nexport interface HttpClientOptions {\n /** Extra headers included on every request. */\n headers?: Record<string, string>;\n /** Per-request timeout in ms. Default 15_000. */\n timeoutMs?: number;\n}\n\nexport interface HttpResponse<T = unknown> {\n status: number;\n ok: boolean;\n headers: Headers;\n /** Parsed JSON body, or `undefined` if the response had no body / non-JSON content. */\n body: T | undefined;\n /** Raw text body, always populated. */\n text: string;\n}\n\nexport class HttpClient {\n constructor(\n private readonly baseUrl: string,\n private readonly defaults: HttpClientOptions = {},\n ) {}\n\n async get<T = unknown>(path: string, opts: HttpClientOptions = {}): Promise<HttpResponse<T>> {\n return this.request<T>('GET', path, undefined, opts);\n }\n\n async post<T = unknown>(\n path: string,\n body: unknown,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('POST', path, body, opts);\n }\n\n async delete<T = unknown>(\n path: string,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('DELETE', path, undefined, opts);\n }\n\n async put<T = unknown>(\n path: string,\n body: unknown,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('PUT', path, body, opts);\n }\n\n async options<T = unknown>(\n path: string,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('OPTIONS', path, undefined, opts);\n }\n\n /** Build an absolute URL for a path under this client's base. */\n url(path: string): string {\n if (path.startsWith('http://') || path.startsWith('https://')) {return path;}\n return `${this.baseUrl.replace(/\\/$/, '')}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n private async request<T>(\n method: string,\n path: string,\n body: unknown,\n opts: HttpClientOptions,\n ): Promise<HttpResponse<T>> {\n const timeoutMs = opts.timeoutMs ?? this.defaults.timeoutMs ?? 15_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n const headers: Record<string, string> = {\n ...this.defaults.headers,\n ...opts.headers,\n };\n if (body !== undefined && !headers['content-type'] && !headers['Content-Type']) {\n headers['content-type'] = 'application/json';\n }\n\n try {\n const res = await fetch(this.url(path), {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n const text = await res.text();\n let parsed: T | undefined;\n const contentType = res.headers.get('content-type') ?? '';\n if (text && contentType.includes('json')) {\n try {\n parsed = JSON.parse(text) as T;\n } catch {\n parsed = undefined;\n }\n }\n return {\n status: res.status,\n ok: res.ok,\n headers: res.headers,\n body: parsed,\n text,\n };\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nexport function httpClient(baseUrl: string, opts: HttpClientOptions = {}): HttpClient {\n return new HttpClient(baseUrl, opts);\n}\n","import { WebSocket, type RawData } from 'ws';\n\n/**\n * Test-friendly WebSocket wrapper.\n *\n * Adapted from `infra/kb-labs-gateway/apps/gateway-app/src/__tests__/live-gateway.e2e.test.ts`\n * — same tracking semantics so the harness can clean up leaked sockets\n * between tests even when an assertion fails mid-flight.\n */\n\nexport interface WsOptions {\n headers?: Record<string, string>;\n /** ms. Default 8000. */\n openTimeoutMs?: number;\n}\n\n/** Opaque handle returned from `connectWs`. */\nexport interface WsHandle {\n readonly socket: WebSocket;\n /** Send a JSON-stringified message. */\n send(data: unknown): void;\n /** Wait for the next message, optionally satisfying a predicate. */\n waitForMessage<T = unknown>(\n opts?: { timeoutMs?: number; predicate?: (msg: T) => boolean },\n ): Promise<T>;\n /** Collect the next N messages (parsed as JSON). */\n collect<T = unknown>(count: number, timeoutMs?: number): Promise<T[]>;\n close(code?: number): void;\n}\n\n/**\n * Shared registry of open sockets. Call `closeAllTrackedSockets()` from an\n * `afterEach` to guarantee cleanup.\n */\nconst openSockets = new Set<WebSocket>();\n\nexport async function closeAllTrackedSockets(graceMs = 150): Promise<void> {\n const toClose = [...openSockets];\n for (const ws of toClose) {\n if (ws.readyState === ws.OPEN || ws.readyState === ws.CONNECTING) {\n try {\n ws.close(1000);\n } catch {\n // intentionally empty: best-effort cleanup, socket may already be dead\n }\n }\n }\n openSockets.clear();\n if (toClose.length > 0) {\n await new Promise((r) => { setTimeout(r, graceMs); });\n }\n}\n\nexport function connectWs(url: string, opts: WsOptions = {}): Promise<WsHandle> {\n const openTimeoutMs = opts.openTimeoutMs ?? 8000;\n return new Promise((resolvePromise, reject) => {\n const ws = new WebSocket(url, {\n headers: opts.headers,\n });\n openSockets.add(ws);\n ws.on('close', () => openSockets.delete(ws));\n\n const timer = setTimeout(() => {\n reject(new Error(`WebSocket open timeout after ${openTimeoutMs}ms: ${url}`));\n try { ws.close(); } catch {\n // intentionally empty: best-effort cleanup on timeout\n }\n }, openTimeoutMs);\n\n ws.once('open', () => {\n clearTimeout(timer);\n resolvePromise(wrapHandle(ws));\n });\n ws.once('error', (err) => {\n clearTimeout(timer);\n reject(err);\n });\n });\n}\n\nfunction wrapHandle(ws: WebSocket): WsHandle {\n return {\n socket: ws,\n send(data: unknown) {\n ws.send(typeof data === 'string' ? data : JSON.stringify(data));\n },\n waitForMessage<T = unknown>(\n opts: { timeoutMs?: number; predicate?: (msg: T) => boolean } = {},\n ): Promise<T> {\n const timeoutMs = opts.timeoutMs ?? 5000;\n return new Promise((resolvePromise, reject) => {\n const cleanup = () => {\n ws.off('message', onMessage);\n ws.off('close', onClose);\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`WebSocket message timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n const onClose = (code: number, reason: Buffer) => {\n clearTimeout(timer);\n cleanup();\n reject(new Error(`WebSocket closed (code=${code}) before message: ${reason.toString() || '(no reason)'}`));\n };\n const onMessage = (raw: RawData) => {\n let msg: T;\n try {\n msg = JSON.parse(raw.toString()) as T;\n } catch (err) {\n clearTimeout(timer);\n cleanup();\n reject(new Error(`Non-JSON WebSocket message: ${(err as Error).message}`));\n return;\n }\n if (!opts.predicate || opts.predicate(msg)) {\n clearTimeout(timer);\n cleanup();\n resolvePromise(msg);\n }\n };\n ws.on('message', onMessage);\n ws.on('close', onClose);\n });\n },\n collect<T = unknown>(count: number, timeoutMs = 5000): Promise<T[]> {\n return new Promise((resolvePromise, reject) => {\n const msgs: T[] = [];\n const cleanup = () => { ws.off('message', onMessage); ws.off('close', onClose); };\n const timer = setTimeout(() => {\n cleanup();\n reject(\n new Error(\n `Timeout: expected ${count} WS messages, got ${msgs.length}: ${JSON.stringify(msgs)}`,\n ),\n );\n }, timeoutMs);\n const onClose = (code: number, reason: Buffer) => {\n clearTimeout(timer);\n cleanup();\n reject(new Error(`WebSocket closed (code=${code}) before collecting ${count} messages: ${reason.toString() || '(no reason)'}`));\n };\n const onMessage = (raw: RawData) => {\n msgs.push(JSON.parse(raw.toString()) as T);\n if (msgs.length >= count) {\n clearTimeout(timer);\n cleanup();\n resolvePromise(msgs);\n }\n };\n ws.on('message', onMessage);\n ws.on('close', onClose);\n });\n },\n close(code = 1000) {\n try {\n ws.close(code);\n } catch {\n // intentionally empty: best-effort cleanup\n }\n },\n };\n}\n","/**\n * Minimal Server-Sent Events reader.\n *\n * Consumes `text/event-stream` responses and yields one `SseEvent` per\n * `event:`/`data:` pair. Terminates on close, explicit `untilEvent`, or timeout.\n */\n\nexport interface SseEvent {\n /** SSE `event:` field. Empty string if absent. */\n event: string;\n /** SSE `data:` field, concatenated with newlines if multi-line. */\n data: string;\n /** Optional `id:` field. */\n id?: string;\n /** Parsed JSON body if `data` is valid JSON, else undefined. */\n json?: unknown;\n}\n\nexport interface SseOptions {\n headers?: Record<string, string>;\n /** If set, the iterator terminates after the first event with this name. */\n untilEvent?: string;\n /** Wall-clock timeout in ms. Default 30_000. */\n timeoutMs?: number;\n}\n\n/**\n * Async iterator over an SSE stream. Caller is responsible for iterating\n * (e.g. `for await (const event of readSse(url)) { ... }`).\n */\nexport async function* readSse(url: string, opts: SseOptions = {}): AsyncGenerator<SseEvent> {\n const timeoutMs = opts.timeoutMs ?? 30_000;\n // Use a race-based timeout instead of AbortController on the fetch /\n // reader: AbortController surfaces AbortError to callers that we cannot\n // suppress reliably (the response stream pipes through Playwright's\n // fixture cleanup, where re-throws happen outside this generator's\n // try/catch). Race the read against a sleep and treat timeout as a\n // clean end-of-stream — that is what every collectSseEvents-style\n // caller expects.\n const deadline = Date.now() + timeoutMs;\n\n let res: Response;\n try {\n res = await fetch(url, {\n headers: { accept: 'text/event-stream', ...opts.headers },\n });\n } catch (err) {\n throw new Error(`SSE fetch failed: ${(err as Error).message}`);\n }\n\n if (!res.ok || !res.body) {\n throw new Error(`SSE response not ok: ${res.status} ${res.statusText}`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n type ReadResult = { value?: Uint8Array; done: boolean };\n const TIMEOUT_MARKER: ReadResult = { done: true };\n\n try {\n while (true) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) { return; }\n\n // Race the next chunk against the deadline. A timeout returns a\n // synthetic \"done\" marker — no AbortError ever surfaces.\n const chunk: ReadResult = await Promise.race([\n reader.read() as Promise<ReadResult>,\n new Promise<ReadResult>((resolve) => setTimeout(() => resolve(TIMEOUT_MARKER), remaining)),\n ]);\n\n const { value, done } = chunk;\n if (done) { return; }\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by a blank line (\\n\\n).\n let sepIdx: number;\n while ((sepIdx = buffer.indexOf('\\n\\n')) !== -1) {\n const rawEvent = buffer.slice(0, sepIdx);\n buffer = buffer.slice(sepIdx + 2);\n const parsed = parseEvent(rawEvent);\n if (!parsed) { continue; }\n yield parsed;\n if (opts.untilEvent && parsed.event === opts.untilEvent) {\n return;\n }\n }\n }\n } finally {\n try { await reader.cancel(); } catch {\n // intentionally empty: reader may already be closed\n }\n }\n}\n\nfunction parseEvent(raw: string): SseEvent | null {\n if (!raw.trim()) {return null;}\n let eventName = '';\n const dataLines: string[] = [];\n let id: string | undefined;\n\n for (const line of raw.split('\\n')) {\n if (!line || line.startsWith(':')) {continue;} // comment / keep-alive\n const colonIdx = line.indexOf(':');\n if (colonIdx === -1) {continue;}\n const field = line.slice(0, colonIdx);\n // Per spec: strip a single leading space from value.\n const value = line.slice(colonIdx + 1).replace(/^ /, '');\n if (field === 'event') {eventName = value;}\n else if (field === 'data') {dataLines.push(value);}\n else if (field === 'id') {id = value;}\n }\n\n if (eventName === '' && dataLines.length === 0) {return null;}\n const data = dataLines.join('\\n');\n let json: unknown;\n if (data) {\n try { json = JSON.parse(data); } catch { /* not JSON, leave undefined */ }\n }\n return { event: eventName, data, id, json };\n}\n","/**\n * Gateway auth helpers.\n *\n * Extracted from `infra/kb-labs-gateway/apps/gateway-app/src/__tests__/live-gateway.e2e.test.ts`\n * (`getJwtToken`, `registerHost`) so every e2e test can reuse the same flow.\n *\n * Flow:\n * 1. POST /auth/register { name, namespaceId } -> { clientId, clientSecret, hostId }\n * 2. POST /auth/token { clientId, clientSecret } -> { accessToken }\n */\n\nimport type { HttpClient } from './http-client.js';\n\nexport interface AgentCredentials {\n accessToken: string;\n clientId: string;\n hostId: string;\n}\n\nexport interface HostCredentials {\n hostId: string;\n machineToken: string;\n}\n\nexport async function registerAgent(\n client: HttpClient,\n opts: { name?: string; namespaceId: string } = { namespaceId: 'e2e-default' },\n): Promise<AgentCredentials> {\n const name = opts.name ?? 'e2e-agent';\n const regRes = await client.post<{ clientId: string; clientSecret: string; hostId: string }>(\n '/auth/register',\n { name, namespaceId: opts.namespaceId },\n );\n if (!regRes.ok || !regRes.body) {\n throw new Error(`/auth/register failed: ${regRes.status} ${regRes.text}`);\n }\n const { clientId, clientSecret, hostId } = regRes.body;\n\n const tokenRes = await client.post<{ accessToken: string }>(\n '/auth/token',\n { clientId, clientSecret },\n );\n if (!tokenRes.ok || !tokenRes.body) {\n throw new Error(`/auth/token failed: ${tokenRes.status} ${tokenRes.text}`);\n }\n\n return { accessToken: tokenRes.body.accessToken, clientId, hostId };\n}\n\nexport async function registerHost(\n client: HttpClient,\n opts: {\n name?: string;\n namespaceId: string;\n capabilities?: string[];\n workspacePaths?: string[];\n },\n): Promise<HostCredentials> {\n const res = await client.post<HostCredentials>('/hosts/register', {\n name: opts.name ?? 'e2e-host',\n namespaceId: opts.namespaceId,\n capabilities: opts.capabilities ?? ['filesystem'],\n workspacePaths: opts.workspacePaths ?? [],\n });\n if (!res.ok || !res.body) {\n throw new Error(`/hosts/register failed: ${res.status} ${res.text}`);\n }\n return res.body;\n}\n","import { mkdir, mkdtemp, rm, writeFile, copyFile, readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/**\n * An isolated temporary project root with its own `.kb/` directory.\n *\n * Used by marketplace/plugin e2e tests so real workspace `.kb/marketplace.lock`\n * and `.kb/plugins.json` are never mutated.\n *\n * Pass the returned `root` via `KB_PROJECT_ROOT` env when starting kb-dev.\n */\nexport interface IsolatedProjectRoot {\n /** Absolute path to the temp project root. */\n root: string;\n /** Absolute path to `<root>/.kb/devservices.yaml`. */\n devConfigPath: string;\n /** Delete the temp dir. Safe to call multiple times. */\n cleanup(): Promise<void>;\n}\n\nexport interface IsolatedProjectRootOptions {\n /**\n * If given, copies the devservices.yaml from this existing workspace root.\n * If omitted, a minimal config with only `state-daemon` is written.\n */\n copyDevConfigFrom?: string;\n /** Prefix for the temp dir name (for human diagnosis). */\n prefix?: string;\n}\n\nconst MINIMAL_DEV_CONFIG = `name: KB Labs E2E Isolated Root\n\ngroups:\n infra: [state-daemon]\n\nservices:\n state-daemon:\n name: State Daemon\n description: Distributed state management\n group: infra\n type: node\n command: node ./plugins/state/daemon/core-state-daemon/dist/bin.cjs\n healthCheck: http://localhost:7777/health\n port: 7777\n url: http://localhost:7777\n env:\n KB_STATE_DAEMON_PORT: \"7777\"\n KB_STATE_DAEMON_HOST: localhost\n\nsettings:\n logsDir: .kb/logs/tmp\n pidDir: .kb/tmp\n startTimeout: 30000\n healthCheckInterval: 1000\n`;\n\nexport async function createIsolatedProjectRoot(\n opts: IsolatedProjectRootOptions = {},\n): Promise<IsolatedProjectRoot> {\n const prefix = opts.prefix ?? 'kb-e2e-';\n const root = await mkdtemp(join(tmpdir(), prefix));\n const kbDir = join(root, '.kb');\n await mkdir(kbDir, { recursive: true });\n await mkdir(join(kbDir, 'tmp'), { recursive: true });\n await mkdir(join(kbDir, 'logs', 'tmp'), { recursive: true });\n\n const devConfigPath = join(kbDir, 'devservices.yaml');\n\n if (opts.copyDevConfigFrom) {\n const source = resolve(opts.copyDevConfigFrom, '.kb/devservices.yaml');\n if (!existsSync(source)) {\n throw new Error(`copyDevConfigFrom: no devservices.yaml at ${source}`);\n }\n // Read to validate it exists and is readable.\n await readFile(source, 'utf8');\n await copyFile(source, devConfigPath);\n } else {\n await writeFile(devConfigPath, MINIMAL_DEV_CONFIG, 'utf8');\n }\n\n let disposed = false;\n const cleanup = async () => {\n if (disposed) {return;}\n disposed = true;\n try {\n await rm(root, { recursive: true, force: true });\n } catch {\n // intentionally empty: best-effort cleanup, tmpdir will be reaped eventually\n }\n };\n\n return { root, devConfigPath, cleanup };\n}\n","import { createHash } from 'node:crypto';\nimport { nanoid } from 'nanoid';\n\n/**\n * Build a deterministic-yet-unique namespace prefix for e2e test resources.\n *\n * Shape: `e2e-<fileHash>-<nanoid>`\n *\n * - `fileHash` is 6 hex chars of sha1(filePath) — lets you grep leaked resources\n * back to the test file that created them.\n * - `nanoid` is a 10-char random suffix — lets parallel runs never collide.\n *\n * Pass `import.meta.url` from the test file.\n */\nexport function makeTestNamespace(fileUrlOrPath: string, prefix = 'e2e'): string {\n const hash = createHash('sha1').update(fileUrlOrPath).digest('hex').slice(0, 6);\n return `${prefix}-${hash}-${nanoid(10)}`;\n}\n","import { readSse } from '../sse-reader.js';\nimport type { SseEvent } from '../sse-reader.js';\n\nexport type { SseEvent };\n\nexport interface CollectSseOptions {\n /** Stop after collecting this many events. */\n count?: number;\n /** Stop after receiving an event with this type (inclusive). */\n untilEvent?: string;\n /** Wall-clock timeout in ms. Default 30_000. */\n timeoutMs?: number;\n /** Extra HTTP headers forwarded to the SSE request. */\n headers?: Record<string, string>;\n}\n\n/**\n * Collects SSE events from `url` into an array.\n * Stops on `count`, `untilEvent`, stream close, or timeout.\n */\nexport async function collectSseEvents(url: string, opts: CollectSseOptions = {}): Promise<SseEvent[]> {\n const events: SseEvent[] = [];\n\n for await (const event of readSse(url, {\n untilEvent: opts.untilEvent,\n timeoutMs: opts.timeoutMs,\n headers: opts.headers,\n })) {\n events.push(event);\n if (opts.count !== undefined && events.length >= opts.count) {\n break;\n }\n }\n\n return events;\n}\n\n/**\n * Returns the first event matching `eventType`, or rejects on timeout.\n */\nexport async function waitForSseEvent(\n url: string,\n eventType: string,\n opts: { timeoutMs?: number; headers?: Record<string, string> } = {},\n): Promise<SseEvent> {\n for await (const event of readSse(url, { timeoutMs: opts.timeoutMs ?? 30_000, headers: opts.headers })) {\n if (event.event === eventType) {\n return event;\n }\n }\n throw new Error(`SSE stream ended before receiving event type \"${eventType}\"`);\n}\n\n/**\n * Asserts the SSE connection at `url` closes on its own without hanging.\n * Rejects if the stream is still open after `timeoutMs`.\n */\nexport async function expectSseTerminates(\n url: string,\n opts: { timeoutMs?: number; headers?: Record<string, string> } = {},\n): Promise<void> {\n const timeoutMs = opts.timeoutMs ?? 5_000;\n\n await Promise.race([\n (async () => {\n // Drain all events — the stream must close naturally.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _event of readSse(url, { timeoutMs, headers: opts.headers })) {\n // just consume\n }\n })(),\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error(`SSE stream did not terminate within ${timeoutMs}ms`)), timeoutMs),\n ),\n ]);\n}\n","import type { SseEvent } from '../sse-reader.js';\n\n/**\n * Asserts SSE events arrive in the exact order of `expectedTypes`.\n * Extra events between expected ones are allowed; missing events throw.\n */\nexport function assertSseOrder(events: SseEvent[], expectedTypes: string[]): void {\n let cursor = 0;\n for (const event of events) {\n if (cursor >= expectedTypes.length) { break; }\n if (event.event === expectedTypes[cursor]) {\n cursor++;\n }\n }\n if (cursor < expectedTypes.length) {\n const received = events.map((e) => e.event);\n throw new Error(\n `SSE order assertion failed.\\n` +\n `Expected (in order): ${expectedTypes.join(', ')}\\n` +\n `Received: ${received.join(', ')}\\n` +\n `Missing: ${expectedTypes[cursor]}`,\n );\n }\n}\n\n/**\n * Asserts no two events share the same event type AND id combination.\n * Events without an id field are compared by type + data.\n */\nexport function assertNoSseDuplicates(events: SseEvent[]): void {\n const seen = new Set<string>();\n for (const event of events) {\n const key = event.id ? `${event.event}::${event.id}` : `${event.event}::${event.data}`;\n if (seen.has(key)) {\n throw new Error(`Duplicate SSE event detected: type=\"${event.event}\" id=\"${event.id ?? '(none)'}\"`);\n }\n seen.add(key);\n }\n}\n","import { connectWs } from '../ws-client.js';\nimport type { WsHandle, WsOptions } from '../ws-client.js';\n\nexport type { WsHandle, WsOptions };\n\n/**\n * Opens a WebSocket, runs `fn`, then closes the socket.\n * The socket is always closed in a finally block — even if `fn` throws.\n */\nexport async function withWs<T>(\n url: string,\n fn: (ws: WsHandle) => Promise<T>,\n opts?: WsOptions,\n): Promise<T> {\n const ws = await connectWs(url, opts);\n try {\n return await fn(ws);\n } finally {\n try {\n ws.close(1000);\n } catch {\n // intentionally empty: best-effort cleanup\n }\n }\n}\n","import type { WsHandle } from '../ws-client.js';\n\n/**\n * Waits for the next WebSocket message that satisfies `predicate`.\n * Times out after `timeoutMs` (default 8000).\n */\nexport async function expectWsMessage<T = unknown>(\n ws: WsHandle,\n predicate: (msg: T) => boolean,\n opts: { timeoutMs?: number; label?: string } = {},\n): Promise<T> {\n const timeoutMs = opts.timeoutMs ?? 8_000;\n const label = opts.label ?? 'expected WS message';\n\n return ws.waitForMessage<T>({\n timeoutMs,\n predicate,\n }).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n const isTimeout = msg.includes('timeout');\n throw new Error(isTimeout ? `Timed out waiting for ${label} after ${timeoutMs}ms` : `${label}: ${msg}`);\n });\n}\n\n/**\n * Asserts the WebSocket closes with the given code (default 1000).\n * Times out after `timeoutMs` (default 5000).\n */\nexport function expectWsClose(\n ws: WsHandle,\n code = 1000,\n opts: { timeoutMs?: number } = {},\n): Promise<void> {\n const timeoutMs = opts.timeoutMs ?? 5_000;\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(`WebSocket did not close with code ${code} within ${timeoutMs}ms`)),\n timeoutMs,\n );\n\n ws.socket.once('close', (closeCode: number) => {\n clearTimeout(timer);\n if (code !== undefined && closeCode !== code) {\n reject(new Error(`WebSocket closed with code ${closeCode}, expected ${code}`));\n } else {\n resolve();\n }\n });\n });\n}\n"]}
1
+ {"version":3,"sources":["../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/diag-collector.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/workspace-root.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/kb-dev-controller.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/diag-snapshot-hook.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/http-client.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/ws-client.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/sse-reader.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/jwt-helpers.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/isolated-project-root.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/namespace.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/sse/collect.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/sse/assert.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/ws/lifecycle.ts","../../home/runner/work/kb-labs/kb-labs/shared/testing-e2e/src/ws/assert.ts"],"names":["resolve","existsSync","writeFile"],"mappings":"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","file":"index.js","sourcesContent":["import { writeFile } from 'node:fs/promises';\n\nimport type {\n AdapterStageTrace,\n ConfigLayersDiag,\n DiagSnapshot,\n KbLogEvent,\n PluginDiscoveryDiag,\n PluginGovernanceTrace,\n ServiceDiag,\n} from './diag-types.js';\nimport type { StatusSnapshot } from './types.js';\n\n/**\n * Collects KB_DEBUG diagnostic events emitted by service processes.\n *\n * Instantiated by KbDevController when KB_DEBUG=true. Each stdout line from\n * subprocesses passes through parseLine(); lines that carry a kb.diag.* event\n * are parsed and routed into per-domain buckets. buildSnapshot() assembles the\n * final DiagSnapshot for attachment to failed tests.\n */\nexport class DiagCollector {\n private readonly pipelineTraces: AdapterStageTrace[] = [];\n private readonly governanceTraces: PluginGovernanceTrace[] = [];\n private configDiag: Partial<ConfigLayersDiag> = {};\n private discoveryDiag: Partial<PluginDiscoveryDiag> = {};\n private serviceMap: Record<string, ServiceDiag> = {};\n\n /**\n * Parse a single stdout line from a service process.\n * Lines that do not contain a kb.diag.* event are ignored cheaply.\n */\n parseLine(line: string): void {\n // Fast string check before JSON.parse to avoid cost on ordinary log lines\n if (!line.includes('\"event\":\"kb.diag.')) { return; }\n try {\n const obj = JSON.parse(line) as KbLogEvent;\n if (typeof obj.event !== 'string' || obj.v !== 1) { return; }\n switch (obj.event) {\n case 'kb.diag.pipeline':\n this.pipelineTraces.push(...(obj.data as AdapterStageTrace[]));\n break;\n case 'kb.diag.governance':\n this.governanceTraces.push(obj.data as PluginGovernanceTrace);\n break;\n case 'kb.diag.config':\n this.configDiag = obj.data as ConfigLayersDiag;\n break;\n case 'kb.diag.discovery':\n this.discoveryDiag = obj.data as PluginDiscoveryDiag;\n break;\n }\n } catch {\n // Malformed line — silently ignore; never throw inside logSink\n }\n }\n\n /** Merge live service status into the snapshot (call after ensureServices/status). */\n ingestStatusSnapshot(snap: StatusSnapshot): void {\n for (const [id, svc] of Object.entries(snap.services)) {\n this.serviceMap[id] = {\n port: svc.port,\n pid: svc.pid,\n url: svc.url,\n state: svc.state,\n };\n }\n }\n\n buildSnapshot(): DiagSnapshot {\n return {\n schemaVersion: 1,\n capturedAt: new Date().toISOString(),\n pipeline: [...this.pipelineTraces],\n governance: [...this.governanceTraces],\n config: { ...this.configDiag },\n discovery: { ...this.discoveryDiag },\n services: { ...this.serviceMap },\n };\n }\n\n async writeSnapshot(path: string): Promise<void> {\n const snapshot = this.buildSnapshot();\n await writeFile(path, JSON.stringify(snapshot, null, 2), 'utf8');\n }\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Walk up from a starting directory until we find a KB Labs workspace root.\n * Recognises both `.kb/devservices.yaml` (runtime, generated by kb-create) and\n * `.kb/devservices.dev.yaml` (committed, present in CI checkouts).\n * Returns the absolute path of the project root, or `null` if not found.\n */\nexport function findWorkspaceRoot(startDir?: string): string | null {\n let dir = startDir ?? process.cwd();\n // Safety: bail after 20 levels so we never climb past `/`.\n for (let i = 0; i < 20; i++) {\n if (\n existsSync(resolve(dir, '.kb/devservices.yaml')) ||\n existsSync(resolve(dir, '.kb/devservices.dev.yaml'))\n ) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the workspace root for the current package, honoring env overrides.\n * Precedence:\n * 1. `KB_PROJECT_ROOT` env var (matches kb-dev itself).\n * 2. Walk up from `process.cwd()`.\n * 3. Walk up from this source file's directory (handles running tests\n * from deeply nested package dirs).\n *\n * Throws if no root can be located.\n */\nexport function resolveWorkspaceRoot(): string {\n const fromEnv = process.env.KB_PROJECT_ROOT;\n if (fromEnv && existsSync(resolve(fromEnv, '.kb/devservices.yaml'))) {\n return fromEnv;\n }\n const fromCwd = findWorkspaceRoot(process.cwd());\n if (fromCwd) {\n return fromCwd;\n }\n const here = dirname(fileURLToPath(import.meta.url));\n const fromHere = findWorkspaceRoot(here);\n if (fromHere) {\n return fromHere;\n }\n throw new Error(\n 'Could not locate KB Labs workspace root (.kb/devservices.yaml). ' +\n 'Set KB_PROJECT_ROOT or run from inside the workspace.',\n );\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { DiagCollector } from './diag-collector.js';\nimport type {\n EnsureOptions,\n KbDevControllerOptions,\n KbDevResult,\n ServiceId,\n ServiceStatus,\n StatusSnapshot,\n} from './types.js';\nimport { resolveWorkspaceRoot } from './workspace-root.js';\n\n/**\n * Ring buffer for the last N lines of subprocess output.\n * Used so that on failure the harness can dump recent kb-dev noise\n * into the test output without swamping it with tens of thousands of lines.\n */\nclass RingBuffer {\n private buf: string[] = [];\n constructor(private readonly capacity: number) {}\n push(line: string): void {\n this.buf.push(line);\n if (this.buf.length > this.capacity) {\n this.buf.splice(0, this.buf.length - this.capacity);\n }\n }\n snapshot(): string[] {\n return [...this.buf];\n }\n}\n\ninterface SubprocessResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/**\n * Controller that drives kb-dev as a subprocess and exposes its JSON\n * agent protocol as a typed TypeScript API for e2e tests.\n *\n * Lifecycle: one controller per test file (beforeAll/afterAll).\n * Services booted through this controller are shared across every\n * `describe`/`it` in that file.\n */\nexport class KbDevController {\n readonly projectRoot: string;\n readonly kbDevBin: string;\n private readonly env: Record<string, string>;\n private readonly logSink?: (line: string) => void;\n private readonly ring = new RingBuffer(400);\n /** Services this controller started (and therefore should clean up). */\n private readonly startedByUs = new Set<ServiceId>();\n /** Cached last status snapshot (invalidated on any mutating call). */\n private lastStatus?: StatusSnapshot;\n /** Collects KB_DEBUG diagnostic events from service stdout. Undefined when KB_DEBUG is not set. */\n private readonly diagCollector: DiagCollector | undefined;\n\n constructor(opts: KbDevControllerOptions = {}) {\n this.projectRoot = opts.projectRoot ?? resolveWorkspaceRoot();\n this.kbDevBin = opts.kbDevBin ?? resolve(this.projectRoot, 'tools/kb-dev/kb-dev');\n if (!existsSync(this.kbDevBin)) {\n throw new Error(\n `kb-dev binary not found at ${this.kbDevBin}. ` +\n 'Build it with: cd tools/kb-dev && make build',\n );\n }\n this.env = {\n ...process.env as Record<string, string>,\n ...(opts.env ?? {}),\n KB_PROJECT_ROOT: this.projectRoot,\n };\n this.logSink = opts.logSink;\n // env is fully resolved at this point — reads KB_DEBUG from process.env or opts.env\n this.diagCollector = this.env.KB_DEBUG === 'true' ? new DiagCollector() : undefined;\n }\n\n /** Returns the DiagCollector instance, or undefined when KB_DEBUG is not set. */\n getDiagCollector(): DiagCollector | undefined {\n return this.diagCollector;\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n /**\n * Ensure every listed service is `alive`. Idempotent — if a service is\n * already running, kb-dev reports `skipped` and we don't respawn.\n *\n * Throws with a formatted hint + recent log tail on failure.\n */\n async ensureServices(\n ids: ServiceId[],\n opts: EnsureOptions = {},\n ): Promise<StatusSnapshot> {\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const args = ['ensure', ...ids, '--json'];\n if (opts.force) {args.push('--force');}\n\n const result = await this.runJson<KbDevResult>(args, timeoutMs);\n if (!result.ok) {\n throw this.formatError(`kb-dev ensure ${ids.join(' ')}`, result);\n }\n for (const action of result.actions ?? []) {\n if (action.action === 'started') {\n this.startedByUs.add(action.service as ServiceId);\n }\n }\n // Poll status until every requested service is alive (ensure returns\n // when spawn completes, but health may still be warming up).\n const snapshot = await this.waitUntilAlive(ids, timeoutMs);\n this.lastStatus = snapshot;\n this.diagCollector?.ingestStatusSnapshot(snapshot);\n return snapshot;\n }\n\n /**\n * Block until a single service reports `alive` or the timeout expires.\n */\n async ready(id: ServiceId, timeoutMs = 60_000): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const snap = await this.status();\n const svc = snap.services[id];\n if (svc?.state === 'alive') {return;}\n if (svc?.state === 'failed') {\n throw new Error(\n `Service ${id} entered 'failed' state.\\n` +\n `Logs tail:\\n${(svc.logsTail ?? []).join('\\n')}`,\n );\n }\n await sleep(500);\n }\n throw new Error(`Timeout waiting for ${id} to become alive (${timeoutMs}ms)`);\n }\n\n /** Query current status for all services. */\n async status(): Promise<StatusSnapshot> {\n const result = await this.runJson<StatusSnapshot>(['status', '--json'], 10_000);\n this.lastStatus = result;\n this.diagCollector?.ingestStatusSnapshot(result);\n return result;\n }\n\n /**\n * Stop the given services (or everything this controller started, if none given).\n * Always best-effort — errors are logged but never thrown.\n */\n async stopServices(ids?: ServiceId[]): Promise<void> {\n const toStop = ids ?? Array.from(this.startedByUs);\n if (toStop.length === 0) {return;}\n try {\n await this.runJson<KbDevResult>(['stop', ...toStop, '--json'], 30_000);\n } catch (err) {\n // Stop failures should never mask the real test failure.\n this.logSink?.(`[kb-dev] stop failed (ignored): ${(err as Error).message}`);\n }\n for (const id of toStop) {this.startedByUs.delete(id);}\n this.lastStatus = undefined;\n }\n\n /** Disposes the controller — stops every service it started. */\n async dispose(): Promise<void> {\n await this.stopServices();\n }\n\n /**\n * Return the HTTP base URL for a service, e.g. `http://localhost:4000`.\n * Throws if the service is not in the last known status snapshot or has no URL.\n */\n getServiceUrl(id: ServiceId): string {\n const svc = this.requireService(id);\n if (!svc.url) {\n throw new Error(`Service ${id} has no URL in its status (state=${svc.state})`);\n }\n return svc.url;\n }\n\n /** Return the port for a service, or throw if unknown. */\n getServicePort(id: ServiceId): number {\n const svc = this.requireService(id);\n if (!svc.port) {\n throw new Error(`Service ${id} has no port in its status (state=${svc.state})`);\n }\n return svc.port;\n }\n\n /** Snapshot of recent subprocess log lines, newest last. */\n dumpRecentLogs(): string[] {\n return this.ring.snapshot();\n }\n\n // ── Internals ─────────────────────────────────────────────────────────────\n\n private requireService(id: ServiceId): ServiceStatus {\n if (!this.lastStatus) {\n throw new Error(\n `No status snapshot yet for ${id}. Call ensureServices() or status() first.`,\n );\n }\n const svc = this.lastStatus.services[id];\n if (!svc) {\n throw new Error(`Service ${id} not found in status snapshot`);\n }\n return svc;\n }\n\n private async waitUntilAlive(\n ids: ServiceId[],\n timeoutMs: number,\n ): Promise<StatusSnapshot> {\n const deadline = Date.now() + timeoutMs;\n let lastSnap: StatusSnapshot | undefined;\n while (Date.now() < deadline) {\n lastSnap = await this.status();\n const allAlive = ids.every((id) => lastSnap?.services[id]?.state === 'alive');\n if (allAlive) {return lastSnap;}\n // Fail fast on hard failures — no point waiting for a service already marked `failed`.\n const failed = ids.find((id) => lastSnap?.services[id]?.state === 'failed');\n if (failed) {\n const svc = lastSnap!.services[failed]!;\n throw new Error(\n `Service ${failed} failed during ensure.\\n` +\n `Logs tail:\\n${(svc.logsTail ?? []).join('\\n')}`,\n );\n }\n await sleep(500);\n }\n throw new Error(\n `Timeout waiting for services to become alive: ${ids.join(', ')}.\\n` +\n `Last known states: ${ids\n .map((id) => `${id}=${lastSnap?.services[id]?.state ?? 'unknown'}`)\n .join(', ')}`,\n );\n }\n\n private formatError(prefix: string, result: KbDevResult): Error {\n const lines: string[] = [`${prefix} failed`];\n if (result.hint) {lines.push(`Hint: ${result.hint}`);}\n for (const action of result.actions ?? []) {\n if (action.action === 'failed' || action.error) {\n lines.push(` - ${action.service}: ${action.error ?? 'failed'}`);\n for (const log of action.logsTail ?? []) {\n lines.push(` ${log}`);\n }\n }\n }\n const recent = this.ring.snapshot();\n if (recent.length > 0) {\n lines.push('Recent kb-dev output:');\n for (const l of recent.slice(-40)) {lines.push(` ${l}`);}\n }\n return new Error(lines.join('\\n'));\n }\n\n /**\n * Run a kb-dev subcommand and parse the stdout as JSON.\n * kb-dev prints only the JSON object on stdout when `--json` is set;\n * any logs go to stderr.\n */\n private async runJson<T>(args: string[], timeoutMs: number): Promise<T> {\n const result = await this.run(args, timeoutMs);\n if (result.code !== 0 && !result.stdout.trim()) {\n throw new Error(\n `kb-dev ${args.join(' ')} exited with code ${result.code}\\n` +\n `stderr:\\n${result.stderr}`,\n );\n }\n try {\n return JSON.parse(result.stdout) as T;\n } catch (err) {\n throw new Error(\n `Failed to parse JSON from \\`kb-dev ${args.join(' ')}\\`:\\n` +\n ` error: ${(err as Error).message}\\n` +\n ` stdout: ${result.stdout.slice(0, 2000)}\\n` +\n ` stderr: ${result.stderr.slice(0, 2000)}`,\n );\n }\n }\n\n private run(args: string[], timeoutMs: number): Promise<SubprocessResult> {\n return new Promise((resolvePromise) => {\n const child = spawn(this.kbDevBin, args, {\n cwd: this.projectRoot,\n env: this.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n const onLine = (chunk: Buffer, stream: 'stdout' | 'stderr') => {\n const text = chunk.toString();\n if (stream === 'stdout') {stdout += text;}\n else {stderr += text;}\n for (const line of text.split('\\n')) {\n if (line) {\n this.ring.push(`[${stream}] ${line}`);\n this.logSink?.(`[kb-dev ${args[0]}] [${stream}] ${line}`);\n if (stream === 'stdout') {\n this.diagCollector?.parseLine(line);\n }\n }\n }\n };\n\n child.stdout.on('data', (d: Buffer) => onLine(d, 'stdout'));\n child.stderr.on('data', (d: Buffer) => onLine(d, 'stderr'));\n\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n }, timeoutMs);\n\n child.on('close', (code) => {\n clearTimeout(timer);\n resolvePromise({ code: code ?? -1, stdout, stderr });\n });\n child.on('error', (err) => {\n clearTimeout(timer);\n resolvePromise({ code: -1, stdout, stderr: stderr + '\\n' + err.message });\n });\n });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => { setTimeout(r, ms); });\n}\n","import type { KbDevController } from './kb-dev-controller.js';\n\nconst SNAPSHOT_PATH = '/tmp/kb-e2e-diag.json';\n\n/**\n * Register a Vitest onTestFailed hook that writes a DiagSnapshot when a test fails.\n *\n * Safe to call in non-Vitest environments (Playwright, Node scripts) — the vitest\n * import is dynamic and failures are caught silently.\n *\n * Usage in beforeAll:\n * await registerDiagSnapshotHook(ctrl);\n */\nexport async function registerDiagSnapshotHook(ctrl: KbDevController): Promise<void> {\n // Dynamic import keeps this file free of static vitest dep (Playwright-safe)\n const vitest = await import('vitest').catch(() => null);\n if (!vitest?.onTestFailed) { return; }\n\n vitest.onTestFailed(async () => {\n const collector = ctrl.getDiagCollector();\n if (!collector) { return; }\n\n try {\n await collector.writeSnapshot(SNAPSHOT_PATH);\n\n // Vitest 3.x attachment API — degrade gracefully if unavailable\n try {\n const { inject } = await import('vitest');\n const attachments = (inject as (key: string) => unknown | undefined)('testAttachments') as\n | { attach(name: string, opts: { path: string; contentType: string }): Promise<void> }\n | undefined;\n await attachments?.attach('kb-e2e-diag.json', {\n path: SNAPSHOT_PATH,\n contentType: 'application/json',\n });\n } catch {\n process.stderr.write(`[KB_DEBUG] DiagSnapshot written to ${SNAPSHOT_PATH}\\n`);\n }\n } catch {\n // Never let a diagnostic failure propagate into the test result\n }\n });\n}\n","/**\n * Minimal HTTP client wrapper used by e2e tests.\n *\n * Intentionally thin — tests should be able to read one line and know\n * exactly what request went out. No retries, no interceptors, no magic.\n */\n\nexport interface HttpClientOptions {\n /** Extra headers included on every request. */\n headers?: Record<string, string>;\n /** Per-request timeout in ms. Default 15_000. */\n timeoutMs?: number;\n}\n\nexport interface HttpResponse<T = unknown> {\n status: number;\n ok: boolean;\n headers: Headers;\n /** Parsed JSON body, or `undefined` if the response had no body / non-JSON content. */\n body: T | undefined;\n /** Raw text body, always populated. */\n text: string;\n}\n\nexport class HttpClient {\n constructor(\n private readonly baseUrl: string,\n private readonly defaults: HttpClientOptions = {},\n ) {}\n\n async get<T = unknown>(path: string, opts: HttpClientOptions = {}): Promise<HttpResponse<T>> {\n return this.request<T>('GET', path, undefined, opts);\n }\n\n async post<T = unknown>(\n path: string,\n body: unknown,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('POST', path, body, opts);\n }\n\n async delete<T = unknown>(\n path: string,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('DELETE', path, undefined, opts);\n }\n\n async put<T = unknown>(\n path: string,\n body: unknown,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('PUT', path, body, opts);\n }\n\n async options<T = unknown>(\n path: string,\n opts: HttpClientOptions = {},\n ): Promise<HttpResponse<T>> {\n return this.request<T>('OPTIONS', path, undefined, opts);\n }\n\n /** Build an absolute URL for a path under this client's base. */\n url(path: string): string {\n if (path.startsWith('http://') || path.startsWith('https://')) {return path;}\n return `${this.baseUrl.replace(/\\/$/, '')}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n private async request<T>(\n method: string,\n path: string,\n body: unknown,\n opts: HttpClientOptions,\n ): Promise<HttpResponse<T>> {\n const timeoutMs = opts.timeoutMs ?? this.defaults.timeoutMs ?? 15_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n const headers: Record<string, string> = {\n ...this.defaults.headers,\n ...opts.headers,\n };\n if (body !== undefined && !headers['content-type'] && !headers['Content-Type']) {\n headers['content-type'] = 'application/json';\n }\n\n try {\n const res = await fetch(this.url(path), {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n const text = await res.text();\n let parsed: T | undefined;\n const contentType = res.headers.get('content-type') ?? '';\n if (text && contentType.includes('json')) {\n try {\n parsed = JSON.parse(text) as T;\n } catch {\n parsed = undefined;\n }\n }\n return {\n status: res.status,\n ok: res.ok,\n headers: res.headers,\n body: parsed,\n text,\n };\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nexport function httpClient(baseUrl: string, opts: HttpClientOptions = {}): HttpClient {\n return new HttpClient(baseUrl, opts);\n}\n","import { WebSocket, type RawData } from 'ws';\n\n/**\n * Test-friendly WebSocket wrapper.\n *\n * Adapted from `infra/kb-labs-gateway/apps/gateway-app/src/__tests__/live-gateway.e2e.test.ts`\n * — same tracking semantics so the harness can clean up leaked sockets\n * between tests even when an assertion fails mid-flight.\n */\n\nexport interface WsOptions {\n headers?: Record<string, string>;\n /** ms. Default 8000. */\n openTimeoutMs?: number;\n}\n\n/** Opaque handle returned from `connectWs`. */\nexport interface WsHandle {\n readonly socket: WebSocket;\n /** Send a JSON-stringified message. */\n send(data: unknown): void;\n /** Wait for the next message, optionally satisfying a predicate. */\n waitForMessage<T = unknown>(\n opts?: { timeoutMs?: number; predicate?: (msg: T) => boolean },\n ): Promise<T>;\n /** Collect the next N messages (parsed as JSON). */\n collect<T = unknown>(count: number, timeoutMs?: number): Promise<T[]>;\n close(code?: number): void;\n}\n\n/**\n * Shared registry of open sockets. Call `closeAllTrackedSockets()` from an\n * `afterEach` to guarantee cleanup.\n */\nconst openSockets = new Set<WebSocket>();\n\nexport async function closeAllTrackedSockets(graceMs = 150): Promise<void> {\n const toClose = [...openSockets];\n for (const ws of toClose) {\n if (ws.readyState === ws.OPEN || ws.readyState === ws.CONNECTING) {\n try {\n ws.close(1000);\n } catch {\n // intentionally empty: best-effort cleanup, socket may already be dead\n }\n }\n }\n openSockets.clear();\n if (toClose.length > 0) {\n await new Promise((r) => { setTimeout(r, graceMs); });\n }\n}\n\nexport function connectWs(url: string, opts: WsOptions = {}): Promise<WsHandle> {\n const openTimeoutMs = opts.openTimeoutMs ?? 8000;\n return new Promise((resolvePromise, reject) => {\n const ws = new WebSocket(url, {\n headers: opts.headers,\n });\n openSockets.add(ws);\n ws.on('close', () => openSockets.delete(ws));\n\n const timer = setTimeout(() => {\n reject(new Error(`WebSocket open timeout after ${openTimeoutMs}ms: ${url}`));\n try { ws.close(); } catch {\n // intentionally empty: best-effort cleanup on timeout\n }\n }, openTimeoutMs);\n\n ws.once('open', () => {\n clearTimeout(timer);\n resolvePromise(wrapHandle(ws));\n });\n ws.once('error', (err) => {\n clearTimeout(timer);\n reject(err);\n });\n });\n}\n\nfunction wrapHandle(ws: WebSocket): WsHandle {\n return {\n socket: ws,\n send(data: unknown) {\n ws.send(typeof data === 'string' ? data : JSON.stringify(data));\n },\n waitForMessage<T = unknown>(\n opts: { timeoutMs?: number; predicate?: (msg: T) => boolean } = {},\n ): Promise<T> {\n const timeoutMs = opts.timeoutMs ?? 5000;\n return new Promise((resolvePromise, reject) => {\n const cleanup = () => {\n ws.off('message', onMessage);\n ws.off('close', onClose);\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`WebSocket message timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n const onClose = (code: number, reason: Buffer) => {\n clearTimeout(timer);\n cleanup();\n reject(new Error(`WebSocket closed (code=${code}) before message: ${reason.toString() || '(no reason)'}`));\n };\n const onMessage = (raw: RawData) => {\n let msg: T;\n try {\n msg = JSON.parse(raw.toString()) as T;\n } catch (err) {\n clearTimeout(timer);\n cleanup();\n reject(new Error(`Non-JSON WebSocket message: ${(err as Error).message}`));\n return;\n }\n if (!opts.predicate || opts.predicate(msg)) {\n clearTimeout(timer);\n cleanup();\n resolvePromise(msg);\n }\n };\n ws.on('message', onMessage);\n ws.on('close', onClose);\n });\n },\n collect<T = unknown>(count: number, timeoutMs = 5000): Promise<T[]> {\n return new Promise((resolvePromise, reject) => {\n const msgs: T[] = [];\n const cleanup = () => { ws.off('message', onMessage); ws.off('close', onClose); };\n const timer = setTimeout(() => {\n cleanup();\n reject(\n new Error(\n `Timeout: expected ${count} WS messages, got ${msgs.length}: ${JSON.stringify(msgs)}`,\n ),\n );\n }, timeoutMs);\n const onClose = (code: number, reason: Buffer) => {\n clearTimeout(timer);\n cleanup();\n reject(new Error(`WebSocket closed (code=${code}) before collecting ${count} messages: ${reason.toString() || '(no reason)'}`));\n };\n const onMessage = (raw: RawData) => {\n msgs.push(JSON.parse(raw.toString()) as T);\n if (msgs.length >= count) {\n clearTimeout(timer);\n cleanup();\n resolvePromise(msgs);\n }\n };\n ws.on('message', onMessage);\n ws.on('close', onClose);\n });\n },\n close(code = 1000) {\n try {\n ws.close(code);\n } catch {\n // intentionally empty: best-effort cleanup\n }\n },\n };\n}\n","/**\n * Minimal Server-Sent Events reader.\n *\n * Consumes `text/event-stream` responses and yields one `SseEvent` per\n * `event:`/`data:` pair. Terminates on close, explicit `untilEvent`, or timeout.\n */\n\nexport interface SseEvent {\n /** SSE `event:` field. Empty string if absent. */\n event: string;\n /** SSE `data:` field, concatenated with newlines if multi-line. */\n data: string;\n /** Optional `id:` field. */\n id?: string;\n /** Parsed JSON body if `data` is valid JSON, else undefined. */\n json?: unknown;\n}\n\nexport interface SseOptions {\n headers?: Record<string, string>;\n /** If set, the iterator terminates after the first event with this name. */\n untilEvent?: string;\n /** Wall-clock timeout in ms. Default 30_000. */\n timeoutMs?: number;\n}\n\n/**\n * Async iterator over an SSE stream. Caller is responsible for iterating\n * (e.g. `for await (const event of readSse(url)) { ... }`).\n */\nexport async function* readSse(url: string, opts: SseOptions = {}): AsyncGenerator<SseEvent> {\n const timeoutMs = opts.timeoutMs ?? 30_000;\n // Use a race-based timeout instead of AbortController on the fetch /\n // reader: AbortController surfaces AbortError to callers that we cannot\n // suppress reliably (the response stream pipes through Playwright's\n // fixture cleanup, where re-throws happen outside this generator's\n // try/catch). Race the read against a sleep and treat timeout as a\n // clean end-of-stream — that is what every collectSseEvents-style\n // caller expects.\n const deadline = Date.now() + timeoutMs;\n\n let res: Response;\n try {\n res = await fetch(url, {\n headers: { accept: 'text/event-stream', ...opts.headers },\n });\n } catch (err) {\n throw new Error(`SSE fetch failed: ${(err as Error).message}`);\n }\n\n if (!res.ok || !res.body) {\n throw new Error(`SSE response not ok: ${res.status} ${res.statusText}`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n type ReadResult = { value?: Uint8Array; done: boolean };\n const TIMEOUT_MARKER: ReadResult = { done: true };\n\n try {\n while (true) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) { return; }\n\n // Race the next chunk against the deadline. A timeout returns a\n // synthetic \"done\" marker — no AbortError ever surfaces.\n const chunk: ReadResult = await Promise.race([\n reader.read() as Promise<ReadResult>,\n new Promise<ReadResult>((resolve) => setTimeout(() => resolve(TIMEOUT_MARKER), remaining)),\n ]);\n\n const { value, done } = chunk;\n if (done) { return; }\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by a blank line (\\n\\n).\n let sepIdx: number;\n while ((sepIdx = buffer.indexOf('\\n\\n')) !== -1) {\n const rawEvent = buffer.slice(0, sepIdx);\n buffer = buffer.slice(sepIdx + 2);\n const parsed = parseEvent(rawEvent);\n if (!parsed) { continue; }\n yield parsed;\n if (opts.untilEvent && parsed.event === opts.untilEvent) {\n return;\n }\n }\n }\n } finally {\n try { await reader.cancel(); } catch {\n // intentionally empty: reader may already be closed\n }\n }\n}\n\nfunction parseEvent(raw: string): SseEvent | null {\n if (!raw.trim()) {return null;}\n let eventName = '';\n const dataLines: string[] = [];\n let id: string | undefined;\n\n for (const line of raw.split('\\n')) {\n if (!line || line.startsWith(':')) {continue;} // comment / keep-alive\n const colonIdx = line.indexOf(':');\n if (colonIdx === -1) {continue;}\n const field = line.slice(0, colonIdx);\n // Per spec: strip a single leading space from value.\n const value = line.slice(colonIdx + 1).replace(/^ /, '');\n if (field === 'event') {eventName = value;}\n else if (field === 'data') {dataLines.push(value);}\n else if (field === 'id') {id = value;}\n }\n\n if (eventName === '' && dataLines.length === 0) {return null;}\n const data = dataLines.join('\\n');\n let json: unknown;\n if (data) {\n try { json = JSON.parse(data); } catch { /* not JSON, leave undefined */ }\n }\n return { event: eventName, data, id, json };\n}\n","/**\n * Gateway auth helpers.\n *\n * Extracted from `infra/kb-labs-gateway/apps/gateway-app/src/__tests__/live-gateway.e2e.test.ts`\n * (`getJwtToken`, `registerHost`) so every e2e test can reuse the same flow.\n *\n * Flow:\n * 1. POST /auth/register { name, namespaceId } -> { clientId, clientSecret, hostId }\n * 2. POST /auth/token { clientId, clientSecret } -> { accessToken }\n */\n\nimport type { HttpClient } from './http-client.js';\n\nexport interface AgentCredentials {\n accessToken: string;\n clientId: string;\n hostId: string;\n}\n\nexport interface HostCredentials {\n hostId: string;\n machineToken: string;\n}\n\nexport async function registerAgent(\n client: HttpClient,\n opts: { name?: string; namespaceId: string } = { namespaceId: 'e2e-default' },\n): Promise<AgentCredentials> {\n const name = opts.name ?? 'e2e-agent';\n const regRes = await client.post<{ clientId: string; clientSecret: string; hostId: string }>(\n '/auth/register',\n { name, namespaceId: opts.namespaceId },\n );\n if (!regRes.ok || !regRes.body) {\n throw new Error(`/auth/register failed: ${regRes.status} ${regRes.text}`);\n }\n const { clientId, clientSecret, hostId } = regRes.body;\n\n const tokenRes = await client.post<{ accessToken: string }>(\n '/auth/token',\n { clientId, clientSecret },\n );\n if (!tokenRes.ok || !tokenRes.body) {\n throw new Error(`/auth/token failed: ${tokenRes.status} ${tokenRes.text}`);\n }\n\n return { accessToken: tokenRes.body.accessToken, clientId, hostId };\n}\n\nexport async function registerHost(\n client: HttpClient,\n opts: {\n name?: string;\n namespaceId: string;\n capabilities?: string[];\n workspacePaths?: string[];\n },\n): Promise<HostCredentials> {\n const res = await client.post<HostCredentials>('/hosts/register', {\n name: opts.name ?? 'e2e-host',\n namespaceId: opts.namespaceId,\n capabilities: opts.capabilities ?? ['filesystem'],\n workspacePaths: opts.workspacePaths ?? [],\n });\n if (!res.ok || !res.body) {\n throw new Error(`/hosts/register failed: ${res.status} ${res.text}`);\n }\n return res.body;\n}\n","import { mkdir, mkdtemp, rm, writeFile, copyFile, readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/**\n * An isolated temporary project root with its own `.kb/` directory.\n *\n * Used by marketplace/plugin e2e tests so real workspace `.kb/marketplace.lock`\n * and `.kb/plugins.json` are never mutated.\n *\n * Pass the returned `root` via `KB_PROJECT_ROOT` env when starting kb-dev.\n */\nexport interface IsolatedProjectRoot {\n /** Absolute path to the temp project root. */\n root: string;\n /** Absolute path to `<root>/.kb/devservices.yaml`. */\n devConfigPath: string;\n /** Delete the temp dir. Safe to call multiple times. */\n cleanup(): Promise<void>;\n}\n\nexport interface IsolatedProjectRootOptions {\n /**\n * If given, copies the devservices.yaml from this existing workspace root.\n * If omitted, a minimal config with only `state-daemon` is written.\n */\n copyDevConfigFrom?: string;\n /** Prefix for the temp dir name (for human diagnosis). */\n prefix?: string;\n}\n\nconst MINIMAL_DEV_CONFIG = `name: KB Labs E2E Isolated Root\n\ngroups:\n infra: [state-daemon]\n\nservices:\n state-daemon:\n name: State Daemon\n description: Distributed state management\n group: infra\n type: node\n command: node ./plugins/state/daemon/core-state-daemon/dist/bin.cjs\n healthCheck: http://localhost:7777/health\n port: 7777\n url: http://localhost:7777\n env:\n KB_STATE_DAEMON_PORT: \"7777\"\n KB_STATE_DAEMON_HOST: localhost\n\nsettings:\n logsDir: .kb/logs/tmp\n pidDir: .kb/tmp\n startTimeout: 30000\n healthCheckInterval: 1000\n`;\n\nexport async function createIsolatedProjectRoot(\n opts: IsolatedProjectRootOptions = {},\n): Promise<IsolatedProjectRoot> {\n const prefix = opts.prefix ?? 'kb-e2e-';\n const root = await mkdtemp(join(tmpdir(), prefix));\n const kbDir = join(root, '.kb');\n await mkdir(kbDir, { recursive: true });\n await mkdir(join(kbDir, 'tmp'), { recursive: true });\n await mkdir(join(kbDir, 'logs', 'tmp'), { recursive: true });\n\n const devConfigPath = join(kbDir, 'devservices.yaml');\n\n if (opts.copyDevConfigFrom) {\n const source = resolve(opts.copyDevConfigFrom, '.kb/devservices.yaml');\n if (!existsSync(source)) {\n throw new Error(`copyDevConfigFrom: no devservices.yaml at ${source}`);\n }\n // Read to validate it exists and is readable.\n await readFile(source, 'utf8');\n await copyFile(source, devConfigPath);\n } else {\n await writeFile(devConfigPath, MINIMAL_DEV_CONFIG, 'utf8');\n }\n\n let disposed = false;\n const cleanup = async () => {\n if (disposed) {return;}\n disposed = true;\n try {\n await rm(root, { recursive: true, force: true });\n } catch {\n // intentionally empty: best-effort cleanup, tmpdir will be reaped eventually\n }\n };\n\n return { root, devConfigPath, cleanup };\n}\n","import { createHash } from 'node:crypto';\nimport { nanoid } from 'nanoid';\n\n/**\n * Build a deterministic-yet-unique namespace prefix for e2e test resources.\n *\n * Shape: `e2e-<fileHash>-<nanoid>`\n *\n * - `fileHash` is 6 hex chars of sha1(filePath) — lets you grep leaked resources\n * back to the test file that created them.\n * - `nanoid` is a 10-char random suffix — lets parallel runs never collide.\n *\n * Pass `import.meta.url` from the test file.\n */\nexport function makeTestNamespace(fileUrlOrPath: string, prefix = 'e2e'): string {\n const hash = createHash('sha1').update(fileUrlOrPath).digest('hex').slice(0, 6);\n return `${prefix}-${hash}-${nanoid(10)}`;\n}\n","import { readSse } from '../sse-reader.js';\nimport type { SseEvent } from '../sse-reader.js';\n\nexport type { SseEvent };\n\nexport interface CollectSseOptions {\n /** Stop after collecting this many events. */\n count?: number;\n /** Stop after receiving an event with this type (inclusive). */\n untilEvent?: string;\n /** Wall-clock timeout in ms. Default 30_000. */\n timeoutMs?: number;\n /** Extra HTTP headers forwarded to the SSE request. */\n headers?: Record<string, string>;\n}\n\n/**\n * Collects SSE events from `url` into an array.\n * Stops on `count`, `untilEvent`, stream close, or timeout.\n */\nexport async function collectSseEvents(url: string, opts: CollectSseOptions = {}): Promise<SseEvent[]> {\n const events: SseEvent[] = [];\n\n for await (const event of readSse(url, {\n untilEvent: opts.untilEvent,\n timeoutMs: opts.timeoutMs,\n headers: opts.headers,\n })) {\n events.push(event);\n if (opts.count !== undefined && events.length >= opts.count) {\n break;\n }\n }\n\n return events;\n}\n\n/**\n * Returns the first event matching `eventType`, or rejects on timeout.\n */\nexport async function waitForSseEvent(\n url: string,\n eventType: string,\n opts: { timeoutMs?: number; headers?: Record<string, string> } = {},\n): Promise<SseEvent> {\n for await (const event of readSse(url, { timeoutMs: opts.timeoutMs ?? 30_000, headers: opts.headers })) {\n if (event.event === eventType) {\n return event;\n }\n }\n throw new Error(`SSE stream ended before receiving event type \"${eventType}\"`);\n}\n\n/**\n * Asserts the SSE connection at `url` closes on its own without hanging.\n * Rejects if the stream is still open after `timeoutMs`.\n */\nexport async function expectSseTerminates(\n url: string,\n opts: { timeoutMs?: number; headers?: Record<string, string> } = {},\n): Promise<void> {\n const timeoutMs = opts.timeoutMs ?? 5_000;\n\n await Promise.race([\n (async () => {\n // Drain all events — the stream must close naturally.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const _event of readSse(url, { timeoutMs, headers: opts.headers })) {\n // just consume\n }\n })(),\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error(`SSE stream did not terminate within ${timeoutMs}ms`)), timeoutMs),\n ),\n ]);\n}\n","import type { SseEvent } from '../sse-reader.js';\n\n/**\n * Asserts SSE events arrive in the exact order of `expectedTypes`.\n * Extra events between expected ones are allowed; missing events throw.\n */\nexport function assertSseOrder(events: SseEvent[], expectedTypes: string[]): void {\n let cursor = 0;\n for (const event of events) {\n if (cursor >= expectedTypes.length) { break; }\n if (event.event === expectedTypes[cursor]) {\n cursor++;\n }\n }\n if (cursor < expectedTypes.length) {\n const received = events.map((e) => e.event);\n throw new Error(\n `SSE order assertion failed.\\n` +\n `Expected (in order): ${expectedTypes.join(', ')}\\n` +\n `Received: ${received.join(', ')}\\n` +\n `Missing: ${expectedTypes[cursor]}`,\n );\n }\n}\n\n/**\n * Asserts no two events share the same event type AND id combination.\n * Events without an id field are compared by type + data.\n */\nexport function assertNoSseDuplicates(events: SseEvent[]): void {\n const seen = new Set<string>();\n for (const event of events) {\n const key = event.id ? `${event.event}::${event.id}` : `${event.event}::${event.data}`;\n if (seen.has(key)) {\n throw new Error(`Duplicate SSE event detected: type=\"${event.event}\" id=\"${event.id ?? '(none)'}\"`);\n }\n seen.add(key);\n }\n}\n","import { connectWs } from '../ws-client.js';\nimport type { WsHandle, WsOptions } from '../ws-client.js';\n\nexport type { WsHandle, WsOptions };\n\n/**\n * Opens a WebSocket, runs `fn`, then closes the socket.\n * The socket is always closed in a finally block — even if `fn` throws.\n */\nexport async function withWs<T>(\n url: string,\n fn: (ws: WsHandle) => Promise<T>,\n opts?: WsOptions,\n): Promise<T> {\n const ws = await connectWs(url, opts);\n try {\n return await fn(ws);\n } finally {\n try {\n ws.close(1000);\n } catch {\n // intentionally empty: best-effort cleanup\n }\n }\n}\n","import type { WsHandle } from '../ws-client.js';\n\n/**\n * Waits for the next WebSocket message that satisfies `predicate`.\n * Times out after `timeoutMs` (default 8000).\n */\nexport async function expectWsMessage<T = unknown>(\n ws: WsHandle,\n predicate: (msg: T) => boolean,\n opts: { timeoutMs?: number; label?: string } = {},\n): Promise<T> {\n const timeoutMs = opts.timeoutMs ?? 8_000;\n const label = opts.label ?? 'expected WS message';\n\n return ws.waitForMessage<T>({\n timeoutMs,\n predicate,\n }).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n const isTimeout = msg.includes('timeout');\n throw new Error(isTimeout ? `Timed out waiting for ${label} after ${timeoutMs}ms` : `${label}: ${msg}`);\n });\n}\n\n/**\n * Asserts the WebSocket closes with the given code (default 1000).\n * Times out after `timeoutMs` (default 5000).\n */\nexport function expectWsClose(\n ws: WsHandle,\n code = 1000,\n opts: { timeoutMs?: number } = {},\n): Promise<void> {\n const timeoutMs = opts.timeoutMs ?? 5_000;\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(`WebSocket did not close with code ${code} within ${timeoutMs}ms`)),\n timeoutMs,\n );\n\n ws.socket.once('close', (closeCode: number) => {\n clearTimeout(timer);\n if (code !== undefined && closeCode !== code) {\n reject(new Error(`WebSocket closed with code ${closeCode}, expected ${code}`));\n } else {\n resolve();\n }\n });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/shared-testing-e2e",
3
3
  "description": "E2E test harness for KB Labs platform — kb-dev controller, HTTP/WS/SSE helpers, isolated project roots",
4
- "version": "2.118.2",
4
+ "version": "2.119.0-canary.0b4b21a55",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -25,8 +25,8 @@
25
25
  "nanoid": "^5.1.16",
26
26
  "vitest": "^3.2.6",
27
27
  "ws": "^8.20.1",
28
- "@kb-labs/plugin-contracts": "2.118.2",
29
- "@kb-labs/shared-command-kit": "2.118.2"
28
+ "@kb-labs/plugin-contracts": "2.119.0-canary.0b4b21a55",
29
+ "@kb-labs/shared-command-kit": "2.119.0-canary.0b4b21a55"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^24.3.3",
@@ -34,7 +34,7 @@
34
34
  "rimraf": "^6.0.1",
35
35
  "tsup": "^8.5.0",
36
36
  "typescript": "^5.6.3",
37
- "@kb-labs/devkit": "2.118.2"
37
+ "@kb-labs/devkit": "2.119.0-canary.0b4b21a55"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=22.0.0",