kimi-code/packages/daemon-e2e
haozhe.yang d4eacc7e7d feat(prompt): add prompt queue and steer support
- add per-session prompt queue: concurrent submits return queued status\n- add list/steer REST endpoints and protocol schemas\n- synthesize prompt.steered lifecycle event\n- add debug endpoint to inject active prompts for e2e testing\n- add daemon-e2e queue + steer invariant test\n- fix WS ping frame handling in daemon-e2e client
2026-06-11 10:14:45 +08:00
..
scenarios test(daemon-e2e): split monolithic recent-daemon-apis scenario into focused scenarios 2026-06-11 10:14:45 +08:00
scripts feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
src feat(prompt): add prompt queue and steer support 2026-06-11 10:14:45 +08:00
test feat(prompt): add prompt queue and steer support 2026-06-11 10:14:45 +08:00
.gitignore feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
AGENTS.md feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
package.json feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
README.md feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
tsconfig.json feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
tsdown.config.ts feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00
vitest.config.ts feat(daemon,web): expand daemon APIs and web client 2026-06-11 10:14:45 +08:00

@moonshot-ai/daemon-e2e

Wire-level test client for the kimi-code daemon (HTTP + WS). This package is private — it ships scenario scripts that double as smoke tests and a small typed DaemonClient you can reuse in vitest e2e files.

When to use this

  • You want to drive a real, running daemon process from a Node script and observe HTTP + WS behavior end to end.
  • You're writing a vitest e2e that covers daemon REST + WS lifecycle as a whole — not a single in-process unit (those belong in packages/daemon/test/).
  • You need a reference for the wire shape of approval / question / events.

When NOT to use this

  • You're testing the WS gateway in isolation — keep using packages/daemon/test/ws-*.e2e.test.ts (in-process startDaemon boots are faster and assert on the daemon's internal services directly).
  • You want a typed in-process facade over the daemon for user-facing code — use @moonshot-ai/node-sdk instead (KimiHarness, Session).

Quick start

import { DaemonClient } from '@moonshot-ai/daemon-e2e';

const client = new DaemonClient(); // http://127.0.0.1:7878 by default

const session = await client.createSession({ metadata: { cwd: process.cwd() } });
await client.connect();              // server_hello + client_hello ack
await client.subscribe(session.id);

client.onApprovalRequested(() => ({ decision: 'approved' }));

const { prompt_id, finalFrame } = await client.submitAndWait(session.id, {
  content: [{ type: 'text', text: 'Echo hello' }],
});

await client.close();
await client.deleteSession(session.id);

Scripts

pnpm --filter @moonshot-ai/daemon-e2e typecheck
pnpm --filter @moonshot-ai/daemon-e2e test            # vitest self-tests
pnpm --filter @moonshot-ai/daemon-e2e test:scenarios  # run every scenarios/*.ts

Both test and test:scenarios require a running daemon (set DAEMON_URL to override the default http://127.0.0.1:7878). The vitest suite skips its live-dependent cases when no daemon is reachable so CI stays green. Scenarios are run via tsx because they execute TypeScript directly.

Both commands write a browser-readable report to packages/daemon-e2e/reports/latest/index.html (override with DAEMON_E2E_REPORT_DIR). The report groups events by case and shows a compact timeline of case logs, HTTP request / response envelopes, WebSocket frames, and test results. JSON payloads are kept in collapsed detail blocks so the terminal can stay concise while the full wire trace remains available.

Public API summary

Symbol Purpose
DaemonClient Main facade — HTTP + WS, handshake plumbing, reverse-RPC handlers.
HttpClient REST helpers only (no WS). Useful when you don't need event observation.
WsClient Raw WS wrapper — queue, waiters, ack correlation.
EnvelopeError Thrown by unwrap() / HTTP helpers when envelope.code !== 0.
fetchWithReport / writeHtmlReport Capture direct fetch calls and render the JSONL trace as a single HTML report.
installReverseRpcHandler Uniform helper powering onApprovalRequested / onQuestionAsked.
waitForFrame / waitForSessionStatus Standalone wait helpers reused by scenarios.

See scenarios/README.md for the executable script catalog and conventions.

Scope notes

  • No in-process daemon bootstrap — point at an already-running daemon. An in-process startDaemon(port:0) helper is intentionally out of scope.
  • No auto-discovery — the WS endpoint is hard-coded to ${apiPrefix}/ws. Override via apiPrefix only.
  • Not publishedprivate: true. Internal tooling only.