文件最后提交记录最后更新时间
sync: OpenCode v1.14.50 -> v1.14.51 Upstream commits: - feat: add experimental background subagents (#27084) - feat(desktop): add mcp client registration status and authentication handling (#27525) - feat(provider): add NVIDIA endpoints origin header (#27394) - fix(session): prevent double auto-compaction from filterCompacted reorder (#27545) - fix(session): finalize interrupted assistant messages (#27254) - fix: image resizer wasm loading, reenable image resizing (#26805) - fix(provider): remove LiteLLM workarounds ported upstream (#26819) - fix(tui): preserve text selection on question prompt options (#24988) - fix(tool): close shell truncation stream (#27517) - fix(worktree): accept missing create payload (#27582) - fix: bug with azure gpt-5.5 w/ completions api (#26222) - refactor(server): simplify listener lifecycle (#27413) - refactor(server): centralize session busy mapping (#27473) - Refactor event HTTP API route modules (#27441) - refactor(flags): migrate multiple flags to runtime flags (#27605-#27615) - refactor(http-recorder): tighten cassette safety, fix WS leaks (#26730) Conflicts resolved: 46 files - package.json (18): accepted upstream versions, preserved name: "deveco" and workspace dep - bun.lock: accepted upstream - extension.toml: accepted upstream version + download URL - flag.ts, runtime-flags.ts: accepted upstream, replaced OPENCODE_ -> DEVECO_ env var prefixes - provider.ts, registry.ts, shell.ts, storage/db.ts: accepted upstream architecture, preserved DEVECO_ branding - lsp.ts, server.ts, formatter.ts, project.ts: accepted upstream, replaced OPENCODE_ -> DEVECO_ - image.ts: accepted upstream wasm fix, replaced __OPENCODE_PHOTON_WASM_PATH -> __DEVECO_PHOTON_WASM_PATH - skill/index.ts: accepted upstream, replaced OPENCODE_SKILL_PATTERN/OPENCODE_DISABLE_EXTERNAL_SKILLS -> DEVECO_ - server/shared/ui.ts, share/session.ts: accepted upstream - Test files (9): accepted upstream, replaced OPENCODE_ -> DEVECO_ env var prefixes Brand identifiers preserved throughout, HarmonyOS tools and plugins retained Baseline updated in BASELINE.md Signed-off-by: OwenO <ouwen7@huawei.com> 15 天前
sync: OpenCode v1.14.50 -> v1.14.51 Upstream commits: - feat: add experimental background subagents (#27084) - feat(desktop): add mcp client registration status and authentication handling (#27525) - feat(provider): add NVIDIA endpoints origin header (#27394) - fix(session): prevent double auto-compaction from filterCompacted reorder (#27545) - fix(session): finalize interrupted assistant messages (#27254) - fix: image resizer wasm loading, reenable image resizing (#26805) - fix(provider): remove LiteLLM workarounds ported upstream (#26819) - fix(tui): preserve text selection on question prompt options (#24988) - fix(tool): close shell truncation stream (#27517) - fix(worktree): accept missing create payload (#27582) - fix: bug with azure gpt-5.5 w/ completions api (#26222) - refactor(server): simplify listener lifecycle (#27413) - refactor(server): centralize session busy mapping (#27473) - Refactor event HTTP API route modules (#27441) - refactor(flags): migrate multiple flags to runtime flags (#27605-#27615) - refactor(http-recorder): tighten cassette safety, fix WS leaks (#26730) Conflicts resolved: 46 files - package.json (18): accepted upstream versions, preserved name: "deveco" and workspace dep - bun.lock: accepted upstream - extension.toml: accepted upstream version + download URL - flag.ts, runtime-flags.ts: accepted upstream, replaced OPENCODE_ -> DEVECO_ env var prefixes - provider.ts, registry.ts, shell.ts, storage/db.ts: accepted upstream architecture, preserved DEVECO_ branding - lsp.ts, server.ts, formatter.ts, project.ts: accepted upstream, replaced OPENCODE_ -> DEVECO_ - image.ts: accepted upstream wasm fix, replaced __OPENCODE_PHOTON_WASM_PATH -> __DEVECO_PHOTON_WASM_PATH - skill/index.ts: accepted upstream, replaced OPENCODE_SKILL_PATTERN/OPENCODE_DISABLE_EXTERNAL_SKILLS -> DEVECO_ - server/shared/ui.ts, share/session.ts: accepted upstream - Test files (9): accepted upstream, replaced OPENCODE_ -> DEVECO_ env var prefixes Brand identifiers preserved throughout, HarmonyOS tools and plugins retained Baseline updated in BASELINE.md Signed-off-by: OwenO <ouwen7@huawei.com> 15 天前
sync: OpenCode v1.14.50 -> v1.14.51 Upstream commits: - feat: add experimental background subagents (#27084) - feat(desktop): add mcp client registration status and authentication handling (#27525) - feat(provider): add NVIDIA endpoints origin header (#27394) - fix(session): prevent double auto-compaction from filterCompacted reorder (#27545) - fix(session): finalize interrupted assistant messages (#27254) - fix: image resizer wasm loading, reenable image resizing (#26805) - fix(provider): remove LiteLLM workarounds ported upstream (#26819) - fix(tui): preserve text selection on question prompt options (#24988) - fix(tool): close shell truncation stream (#27517) - fix(worktree): accept missing create payload (#27582) - fix: bug with azure gpt-5.5 w/ completions api (#26222) - refactor(server): simplify listener lifecycle (#27413) - refactor(server): centralize session busy mapping (#27473) - Refactor event HTTP API route modules (#27441) - refactor(flags): migrate multiple flags to runtime flags (#27605-#27615) - refactor(http-recorder): tighten cassette safety, fix WS leaks (#26730) Conflicts resolved: 46 files - package.json (18): accepted upstream versions, preserved name: "deveco" and workspace dep - bun.lock: accepted upstream - extension.toml: accepted upstream version + download URL - flag.ts, runtime-flags.ts: accepted upstream, replaced OPENCODE_ -> DEVECO_ env var prefixes - provider.ts, registry.ts, shell.ts, storage/db.ts: accepted upstream architecture, preserved DEVECO_ branding - lsp.ts, server.ts, formatter.ts, project.ts: accepted upstream, replaced OPENCODE_ -> DEVECO_ - image.ts: accepted upstream wasm fix, replaced __OPENCODE_PHOTON_WASM_PATH -> __DEVECO_PHOTON_WASM_PATH - skill/index.ts: accepted upstream, replaced OPENCODE_SKILL_PATTERN/OPENCODE_DISABLE_EXTERNAL_SKILLS -> DEVECO_ - server/shared/ui.ts, share/session.ts: accepted upstream - Test files (9): accepted upstream, replaced OPENCODE_ -> DEVECO_ env var prefixes Brand identifiers preserved throughout, HarmonyOS tools and plugins retained Baseline updated in BASELINE.md Signed-off-by: OwenO <ouwen7@huawei.com> 15 天前
sync: OpenCode v1.15.4 -> v1.15.5 Upstream commits: - Preview native LLM runtime stack (#27114) - feat(tui): add syntax highlighting for elixir, fsharp, r, make, vim, xml, agda - perf(app): virtualize session timeline rows (#26949) - fix(plugin): ask in tools from plugins returns promise instead of effect - fix(bus): acquire PubSub subscription eagerly to close /event race - refactor(session): move prompt reminders out of core loop - refactor(session): extract prompt tool resolution - refactor(session): extract reference prompt helpers - refactor(reference): split materialization state - refactor(repository): add cache service + type cache failures - fix(core): fix file references in workspaces - fix(ui): guard reasoning renderer, fix question dock overflow - fix(tui): copy pasted prompt content, collapse long tool output lines - Load models.dev snapshot from build global (models-snapshot.js deleted) - Upgrade Bun to final non-rust version - Multiple test migrations to instance fixtures Conflicts resolved: 28 files - package.json (17): version bump, accept upstream - packages/opencode/package.json: accept upstream + keep name/bin/deveco-codegenie deps - packages/web/package.json: accept upstream + fix deveco workspace dep - bun.lock/extension.toml/sdks/vscode/package.json: accept upstream - build scripts (3): DEVECO_MODELS_DEV define, generate.ts export - runtime-flags.ts: new experimentalNativeLlm flag with DEVECO_ prefix - session/llm.ts: accept upstream native LLM runtime architecture, keep DEVECO_ headers + debug logging - test files (3): DEVECO_TEST_HOME branding Brand identifiers preserved throughout, HarmonyOS tools and plugins retained Baseline updated in BASELINE.md Signed-off-by: OwenO <ouwen7@huawei.com> 13 天前
sync: OpenCode v1.14.46 -> v1.14.47 Upstream commits (50): - feat(scout): materialize configured reference repos (#26692) - feat: better image handling (auto resize & max size constraints) (#26401) - feat(http-recorder): default mode to "auto" (#26719) - Source HTTP API ID path patterns (#26623) - Source workspace path pattern (#26632) - Source diff message query pattern (#26638) - Persist session model switches outside event flag (#26765) - restore managed textarea keymap handling (#26771) - fix(server): return diagnosable body for schema rejections (#26631) - Add explicit LLM stream lifecycle events (#26722) - refactor(http-recorder): use Schema.TaggedErrorClass for cassette errors (#26729) - refactor(http-recorder): hide cassette format behind Cassette seam (#26725) - refactor(http-recorder): Redactor + Recorder seams, README (#26636) - Scope boolean query overrides - Drop unused ID Zod statics (#26740) - Drop compaction create facade (#26739) - Replace compaction create test fixtures (#26738) - Migrate compaction tool-call/plugin/LLM/overflow tests - Use Effect timeout in compaction test (#26728) - Format TUI paths relative to session directory (#26648) - Remove redundant ID Zod overrides (#26633) - Zen: Ring 2.6 1T, fix usage css, fix reasoning token - Go: hy3 preview, tencent icon - Various chore: generate commits - release: v1.14.47 Conflicts resolved: - 17 package.json: version bump, kept codegenie name - packages/opencode/package.json: version bump, kept name=codegenie - packages/web/package.json: version bump, fixed workspace dep - bun.lock: accepted upstream - extension.toml: version/URL upgrade - AGENTS.md: kept local CodeGenie docs index - agent.ts: accepted Reference.resolveAll refactor, kept CODEGENIE_ brand - read.ts: merged imports (isImageAttachment + Reference) - event.ts: accepted bypassExperimentalEventSystem option, kept CODEGENIE_ brand - prompt-traits.test.ts: accepted upstream new test file Brand cleanup: - reference.ts, reference.test.ts, read.test.ts: OPENCODE_ -> CODEGENIE_ Signed-off-by: zhangyuchen <zhangyuchen45@huawei.com> 20 天前
sync: OpenCode v1.14.41 -> v1.14.42 Upstream commits: - feat(core): add scout agent for repo research (#24149) - Add native LLM core foundation (#24712) - feat(opencode): add interactive split-footer mode to run (#23557) - feat(server): add HTTP API response compression (#26440) - feat(core): be smarter about generating a worktree name (#26368) - feat(core): allow external workspace creation (#26212) - feat(desktop): working indicator on project sidebar (#26223) - feat(desktop): allow silent install and only user-wide scope (#26253) - feat(websearch): add parallel provider rollout (#26227) - fix(server): clean up post-Hono-deletion scar tissue (#26542) - fix(server): validate permission and question ids (#26456) - fix(server): include auth challenge on typed 401 (#26455) - fix(server): return structured validation errors (#26457) - fix(server): match Hono wire format for authorize errors (#26474) - fix(tui): sort session picker by full updated timestamp (#24725) - fix(cli): forward signals from npm shim (#26259) - fix(workspace): claim detached sessions to source project (#26413) - fix(tui): retain cleared prompt drafts (#26258) - fix(provider): align Gemini thinking controls (#26279) - fix(provider): align Anthropic Opus 4.5 efforts (#26275) - fix(provider): constrain OpenAI deep research efforts (#26273) - fix(provider): align GPT-5 reasoning variants (#26268) - fix(skill): allow missing descriptions (#26391) - fix: ensure tools are always in same order (#26370) - fix: adjust tui retry dialog logic (#26366) - fix(web): normalize shell output carriage returns (#26426) - fix: tweaks to transform logic for anthropic and bedrock (#26276) - flatten to keybind compatible config (#26421) - introduce opentui keymap as sole key/cmd engine (#26053) - internal which-key plugin, inactive by default (#26337) - refactor(desktop): convert main process to Effect-TS (#26148) - research: delete Hono backend (#25667) - release: v1.14.42 Conflicts resolved: 77 files - package.json (17): accepted upstream versions, preserved name: "codegenie" - bun.lock, nix/hashes.json: accepted upstream - extension.toml: accepted upstream version and download URL - server source (12): accepted upstream architecture, preserved CODEGENIE_ brand - server tests (27): accepted upstream test structure, preserved CODEGENIE_ brand - tui/plugin (6): accepted upstream TUI changes, preserved CodeGenie customizations - desktop (2): accepted upstream Effect-TS refactor, preserved brand - bin/codegenie: preserved CODEGENIE_BIN_PATH and .codegenie cache - modify/delete (6): accepted upstream deletions (Hono cleanup) - sdk/build (1): accepted upstream - flag.ts: accepted upstream flags, converted OPENCODE_ to CODEGENIE_ Brand identifiers preserved throughout, HarmonyOS tools and plugins retained Signed-off-by: zhangyuchen <zhangyuchen45@huawei.com> 20 天前
README.md

@opencode-ai/http-recorder

Record and replay HTTP and WebSocket traffic for Effect's HttpClient. Tests exercise real request shapes against deterministic, version-controlled cassettes — no manual mocks, no flakes from upstream drift.

Install

Internal package; depended on as @opencode-ai/http-recorder from another workspace package.

import { HttpRecorder } from "@opencode-ai/http-recorder"

Quickstart

Provide cassetteLayer(name) in place of (or layered over) your HttpClient. By default the layer records on first run and replays on subsequent runs — no env-var ternary at the call site, and CI=true forces strict replay so missing cassettes fail loudly in CI rather than silently re-recording.

import { Effect } from "effect"
import { HttpClient, HttpClientRequest } from "effect/unstable/http"
import { HttpRecorder } from "@opencode-ai/http-recorder"

const program = Effect.gen(function* () {
  const http = yield* HttpClient.HttpClient
  const response = yield* http.execute(HttpClientRequest.get("https://api.example.com/users/1"))
  return yield* response.json
})

// Records if the cassette is missing, replays if it exists.
// In CI (CI=true) always replays — fails loudly on missing fixtures.
Effect.runPromise(program.pipe(Effect.provide(HttpRecorder.cassetteLayer("users/get-one"))))

// Force a refresh — always hits upstream and overwrites.
Effect.runPromise(program.pipe(Effect.provide(HttpRecorder.cassetteLayer("users/get-one", { mode: "record" }))))

Modes

Mode Behavior
auto Default. Replay if the cassette exists; record if missing. CI=true forces replay.
replay Strict — match the request to a recorded interaction; error if none.
record Execute upstream, append the interaction, write the cassette.
passthrough Bypass the recorder entirely — just call upstream.

Cassette format

A cassette is JSON at test/fixtures/recordings/<name>.json:

{
  "version": 1,
  "metadata": { "name": "users/get-one", "recordedAt": "2026-05-09T..." },
  "interactions": [
    {
      "transport": "http",
      "request":  { "method": "GET", "url": "...", "headers": {...}, "body": "" },
      "response": { "status": 200, "headers": {...}, "body": "..." }
    }
  ]
}

Cassettes are normal source files — review them, diff them, commit them.

Request matching

Replay walks the cassette in record order via an internal cursor: the Nth request executed at runtime is served by the Nth recorded interaction, and each one is validated as the cursor advances. Request equality is computed on canonicalized method, URL, headers, and JSON body (object keys sorted).

This is deliberately strict — content-based dispatch was removed because it silently returns the first recorded response for repeated identical requests, masking state changes that retry/polling/cache-hit tests need to observe. If you reorder requests in a test, re-record the cassette.

Supply your own matcher via match: (incoming, recorded) => boolean for custom equivalence (e.g. ignoring a timestamp field in the body).

Redaction & secret safety

Cassettes get checked in, so the recorder is aggressive about not letting secrets escape. Redaction is configured by composing a Redactor:

import { HttpRecorder, Redactor } from "@opencode-ai/http-recorder"

HttpRecorder.cassetteLayer("anthropic/messages", {
  redactor: Redactor.defaults({
    requestHeaders: { allow: ["content-type", "anthropic-version"] },
    url: { transform: (url) => url.replace(/\/accounts\/[^/]+/, "/accounts/{account}") },
    body: (parsed) => ({ ...(parsed as object), user_id: "{user}" }),
  }),
})

Redactor.defaults({ … }) composes the four built-in redactors with your overrides. For full control, build the stack yourself:

const redactor = Redactor.compose(
  Redactor.requestHeaders({ allow: ["content-type", "x-custom"] }),
  Redactor.responseHeaders(),
  Redactor.url({ query: ["session-id"] }),
  Redactor.body((parsed) => /* … */),
)

What each layer does:

  • requestHeaders / responseHeaders — strip headers to a small allow-list (request default: content-type, accept, openai-beta; response default: content-type). Sensitive headers within the allow-list (authorization, cookie, API-key headers, AWS/GCP tokens, …) are replaced with [REDACTED].
  • url — query parameters matching common secret names (api_key, token, signature, AWS signing params, …) are replaced with [REDACTED]. URL user/password are replaced. transform runs after built-in redaction for path-level scrubbing.
  • body — receives the parsed JSON request body and returns a redacted version. No-op for non-JSON bodies.

After assembling the cassette, the recorder scans every string for known secret patterns (Bearer tokens, sk-…, sk-ant-…, Google AIza… keys, AWS access keys, GitHub tokens, PEM blocks) and for values matching any environment variable named like a credential. If anything is found, the cassette is not written and the request fails with UnsafeCassetteError listing what was detected.

WebSocket recording

WebSocket support records the open frame plus client/server message streams. It uses the shared Cassette.Service, so HTTP and WS interactions can live in the same cassette.

import { HttpRecorder } from "@opencode-ai/http-recorder"
import { Effect } from "effect"

const program = Effect.gen(function* () {
  const cassette = yield* HttpRecorder.Cassette.Service
  const executor = yield* HttpRecorder.makeWebSocketExecutor({
    name: "ws/subscribe",
    cassette,
    live: liveExecutor,
  })
  // use executor.open(...)
})

Inspecting cassettes programmatically

Cassette.Service exposes read, append, exists, and list. read returns the recorded interactions for a name; the file format is hidden behind the seam. Useful for CI checks:

import { HttpRecorder } from "@opencode-ai/http-recorder"
import { Effect } from "effect"

const audit = Effect.gen(function* () {
  const cassettes = yield* HttpRecorder.Cassette.Service
  const names = yield* cassettes.list()
  const issues = yield* Effect.forEach(names, (name) =>
    cassettes
      .read(name)
      .pipe(Effect.map((interactions) => ({ name, findings: HttpRecorder.secretFindings(interactions) }))),
  )
  return issues.filter((i) => i.findings.length > 0)
})

cassetteLayer is the batteries-included entry point — it provides Cassette.fileSystem({ directory }) automatically. If you want to provide your own Cassette.Service (e.g. an in-memory adapter for the recorder's own unit tests), use recordingLayer and supply Cassette.fileSystem / Cassette.memory yourself.

Options reference

type RecordReplayOptions = {
  mode?: "auto" | "replay" | "record" | "passthrough" // default: "auto" (CI=true forces "replay")
  directory?: string // default: <cwd>/test/fixtures/recordings
  metadata?: Record<string, unknown> // merged into cassette.metadata
  redactor?: Redactor // default: Redactor.defaults()
  match?: (incoming, recorded) => boolean // custom matcher
}

Layout

File Purpose
effect.ts cassetteLayer / recordingLayer — the HttpClient adapter.
websocket.ts makeWebSocketExecutor — WebSocket record/replay.
cassette.ts Cassette.ServicefileSystem / memory adapters, error types.
recorder.ts Shared transport plumbing: resolveAutoMode, ReplayState.
redactor.ts Composable Redactor — headers, url, body redaction.
redaction.ts Lower-level header/URL primitives + secret pattern detection.
schema.ts Effect Schema definitions for the cassette JSON format.
matching.ts Request matcher, canonicalization, sequential cursor, mismatch diagnostics.