Skip to content

Fixture/langfuse record auto mode data error#308

Merged
claude-code-best merged 8 commits intomainfrom
fixture/langfuse-record-auto-mode-data-error
Apr 20, 2026
Merged

Fixture/langfuse record auto mode data error#308
claude-code-best merged 8 commits intomainfrom
fixture/langfuse-record-auto-mode-data-error

Conversation

@claude-code-best
Copy link
Copy Markdown
Owner

@claude-code-best claude-code-best commented Apr 20, 2026

Summary by CodeRabbit

  • New Features

    • Added support for nested tracing with parent span context for improved observability
    • Added user-configured model fallback to model selection logic
  • Bug Fixes

    • Fixed token counting to include cache tokens and detect placeholder entries
    • Fixed context percentage calculations when total tokens equal zero
  • Chores

    • Added comprehensive test command
    • Consolidated feature flag definitions into single source
    • Updated native module compatibility for ESM environments

claude-code-best and others added 8 commits April 20, 2026 10:43
第三方 API(如智谱)在 message_start 中可能不返回完整 usage 数据,
导致 getCurrentUsage 返回全零 usage 对象,使 ctx 显示为 0%。

双重保护:
- getCurrentUsage: 跳过全零 usage,继续往前找有真实数据的 message
- calculateContextPercentages: totalInputTokens 为 0 时返回 null

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
color-diff-napi、image-processor-napi、audio-capture-napi 声明
"type": "module" 但使用裸 require(),Node.js ESM 中 require
不可用。改用 createRequire(import.meta.url) 或顶层 import。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
当用户通过 ANTHROPIC_MODEL 或 settings 配置了自定义 provider 支持的模型时,
getDefaultSonnetModel/Haiku/Opus 现在会优先使用该配置,而非硬编码 Anthropic 官方模型 ID。
同时改进 Langfuse 可观测性:sideQuery 失败时记录错误信息到 span,
optional 模式下标记 WARNING 而非 ERROR。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
classifyYoloAction 及 classifyYoloActionXml 接收 parentSpan 参数,
透传给 sideQuery 调用,使 auto_mode 的 side-query span 嵌套在主 agent trace 下。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Poor mode 启用时不执行 findRelevantMemories 的预取调用,
避免额外的 API token 消耗。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vite 构建插件的 DEFAULT_BUILD_FEATURES 缺少 BUDDY、TRANSCRIPT_CLASSIFIER、
BRIDGE_MODE、ACP、BG_SESSIONS、TEMPLATES,导致 feature('TRANSCRIPT_CLASSIFIER')
被替换为 false,auto mode 从 Shift+Tab 循环中消失。与 build.ts 对齐。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
将 DEFAULT_BUILD_FEATURES 列表从 build.ts、dev.ts、vite-plugin-feature-flags.ts
三处内联定义统一到 scripts/defines.ts 单一导出。之前的 Vite 插件缺少
TRANSCRIPT_CLASSIFIER 等 feature flag,导致 auto mode 在 Vite 构建中不可见。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mintlify
Copy link
Copy Markdown

mintlify bot commented Apr 20, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ccb-863780bf 🟢 Ready View Preview Apr 20, 2026, 5:24 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

This PR centralizes default build feature configurations into scripts/defines.ts, converts native modules from CommonJS to ESM-compatible require patterns, adds a test:all npm script combining typecheck and test operations, introduces Langfuse span creation with parent-span context threading through memory queries and side queries, and updates utility functions for improved token accounting and permissions classification integration.

Changes

Cohort / File(s) Summary
Build Features Centralization
scripts/defines.ts, build.ts, scripts/dev.ts, scripts/vite-plugin-feature-flags.ts
Extracted hardcoded DEFAULT_BUILD_FEATURES array into scripts/defines.ts as a typed constant exported for reuse, then imported this constant in build.ts, dev.ts, and vite-plugin-feature-flags.ts to eliminate duplication.
Development Workflow
CLAUDE.md, package.json
Added test:all npm script (bun run typecheck && bun test) to package.json and integrated it into CLAUDE.md command sequence for consolidated type checking and testing.
Native Module ESM Migration
packages/audio-capture-napi/src/index.ts, packages/color-diff-napi/src/index.ts, packages/image-processor-napi/src/index.ts
Migrated from CommonJS require() to ESM-compatible createRequire(import.meta.url) pattern across three native addon modules; image-processor additionally switched to direct named imports for readFileSync and unlinkSync.
Langfuse Span Creation & Re-export
src/services/langfuse/tracing.ts, src/services/langfuse/index.ts
Introduced new createChildSpan(parentSpan, params) function supporting nested Langfuse trace observations under parent spans with context propagation (session/user IDs), error handling, and debug logging; re-exported from index.ts.
Memory Query Tracing Integration
src/memdir/findRelevantMemories.ts, src/utils/attachments.ts, src/utils/permissions/yoloClassifier.ts, src/utils/permissions/permissions.ts
Extended function signatures to accept optional parentSpan parameter and thread it through memory discovery and classifier invocation paths; added poor-mode detection to skip memory prefetch when active.
Side Query Tracing & Token Handling
src/utils/sideQuery.ts, src/utils/tokens.ts, src/utils/context.ts
Enhanced SideQueryOptions with optional parentSpan and optional flag for flexible Langfuse trace nesting and error status handling; improved token accounting to aggregate cache-related inputs and filter placeholder zero-token messages; fixed context percentage calculation for zero total tokens.
Model Default Selection
src/utils/model/model.ts
Extended default Opus/Sonnet/Haiku model functions to check user-specified model settings as an additional fallback before returning provider defaults.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Memory as Memory Finder
    participant Classifier as Classifier
    participant SideQuery as Side Query
    participant Langfuse

    Client->>Memory: findRelevantMemories(query, ..., parentSpan)
    Memory->>SideQuery: sideQuery({parentSpan, optional: true})
    SideQuery->>Langfuse: createChildSpan(parentSpan)
    Langfuse-->>SideQuery: child span instance
    SideQuery->>Langfuse: record LLM observation
    SideQuery-->>Memory: results
    Memory-->>Client: relevant memories

    Client->>Classifier: classifyYoloAction(..., parentSpan)
    Classifier->>SideQuery: sideQuery({parentSpan})
    SideQuery->>Langfuse: createChildSpan(parentSpan)
    Langfuse-->>SideQuery: child span instance
    SideQuery->>Langfuse: record classification
    SideQuery-->>Classifier: classification result
    Classifier-->>Client: action classification
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 Hop hop, the features now unite!
From scattered scripts to one true light,
ESM's call rings clear and bright,
While traces dance through Langfuse's sight—
A rabbit's joy, precision's might!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fixture/langfuse record auto mode data error' is vague and unclear. It uses non-descriptive terms like 'Fixture' and 'data error' without conveying what the changeset actually accomplishes. Revise the title to clearly describe the main change, e.g., 'Add Langfuse tracing support for auto mode classifier and memory queries' or 'Centralize default build features and extend Langfuse span context'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fixture/langfuse-record-auto-mode-data-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/permissions/yoloClassifier.ts (1)

781-807: ⚠️ Potential issue | 🟠 Major

Strip parentSpan before dumping or storing classifier requests.

stage1Opts, stage2Opts, and sideQueryOpts now contain the live LangfuseSpan, but the same objects are passed to maybeDumpAutoMode() and setLastClassifierRequests(). That risks serializing trace internals or circular SDK state into auto-mode dumps and /share transcript data. Keep the span only on the object passed to sideQuery, and store/dump a redacted copy.

🛡️ Proposed fix
+function stripTraceContext<T extends { parentSpan?: LangfuseSpan | null }>(
+  opts: T,
+): Omit<T, 'parentSpan'> {
+  const { parentSpan: _parentSpan, ...rest } = opts
+  return rest
+}
+
       stage1Opts = {
         model,
         max_tokens: (mode === 'fast' ? 256 : 64) + thinkingPadding,
@@
         querySource: 'auto_mode',
         parentSpan,
       }
       const stage1Raw = await sideQuery(stage1Opts)
@@
-      void maybeDumpAutoMode(stage1Opts, stage1Raw, stage1Start, 'stage1')
-      setLastClassifierRequests([stage1Opts])
+      const stage1DumpOpts = stripTraceContext(stage1Opts)
+      void maybeDumpAutoMode(stage1DumpOpts, stage1Raw, stage1Start, 'stage1')
+      setLastClassifierRequests([stage1DumpOpts])
@@
     const stage2Opts = {
@@
       querySource: 'auto_mode' as const,
       parentSpan,
     }
     const stage2Raw = await sideQuery(stage2Opts)
@@
-    void maybeDumpAutoMode(stage2Opts, stage2Raw, stage2Start, 'stage2')
+    const stage2DumpOpts = stripTraceContext(stage2Opts)
+    void maybeDumpAutoMode(stage2DumpOpts, stage2Raw, stage2Start, 'stage2')
     setLastClassifierRequests(
-      stage1Opts ? [stage1Opts, stage2Opts] : [stage2Opts],
+      stage1Opts ? [stripTraceContext(stage1Opts), stage2DumpOpts] : [stage2DumpOpts],
     )
@@
     const sideQueryOpts = {
@@
       querySource: 'auto_mode' as const,
       parentSpan,
     }
     const result = await sideQuery(sideQueryOpts)
-    void maybeDumpAutoMode(sideQueryOpts, result, start)
-    setLastClassifierRequests([sideQueryOpts])
+    const dumpOpts = stripTraceContext(sideQueryOpts)
+    void maybeDumpAutoMode(dumpOpts, result, start)
+    setLastClassifierRequests([dumpOpts])

Also applies to: 869-900, 1140-1169

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/permissions/yoloClassifier.ts` around lines 781 - 807, The objects
stage1Opts, stage2Opts, and sideQueryOpts currently include a live LangfuseSpan
(parentSpan) and that same object is passed to maybeDumpAutoMode() and
setLastClassifierRequests(), risking serialization of trace internals; keep
parentSpan only on the object passed to sideQuery (e.g., call
sideQuery(stage1Opts) with parentSpan present) but pass a redacted copy (shallow
clone with parentSpan removed) to maybeDumpAutoMode() and
setLastClassifierRequests(); update the three spots (where
stage1Opts/stage2Opts/sideQueryOpts are created and used) to build or clone a
copy like { ...opts } then delete or omit parentSpan before calling
maybeDumpAutoMode and setLastClassifierRequests so the real span remains for
sideQuery but is not stored/dumped.
🧹 Nitpick comments (1)
src/utils/attachments.ts (1)

2197-2226: Type the parent span instead of casting it through unknown.

parentSpan?: unknown plus parentSpan as Parameters<typeof findRelevantMemories>[5] hides type regressions in the tracing path. Import the span type and keep the signature explicit.

♻️ Proposed type tightening
+import type { LangfuseSpan } from '../services/langfuse/index.js'
+
 async function getRelevantMemoryAttachments(
   input: string,
   agents: AgentDefinition[],
@@
   signal: AbortSignal,
   alreadySurfaced: ReadonlySet<string>,
-  parentSpan?: unknown,
+  parentSpan?: LangfuseSpan | null,
 ): Promise<Attachment[]> {
@@
         recentTools,
         alreadySurfaced,
-        parentSpan as Parameters<typeof findRelevantMemories>[5],
+        parentSpan,
       ).catch(() => []),

As per coding guidelines, "Use type guards to narrow union types instead of forced type casting."

Also applies to: 2401-2409

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/attachments.ts` around lines 2197 - 2226, The function
getRelevantMemoryAttachments uses a loosely typed parentSpan (parentSpan?:
unknown) and then casts it when calling findRelevantMemories, which hides type
errors; import the proper tracing/span type (e.g., Span or TracingSpan) and
change the signature to parentSpan?: Span, remove the cast parentSpan as
Parameters<typeof findRelevantMemories>[5] and pass parentSpan directly into
findRelevantMemories, and update the other occurrence around lines ~2401-2409
the same way so both call sites use the explicit Span type instead of
unknown/casts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLAUDE.md`:
- Around line 61-63: The README line for the "test:all" command is inaccurate:
it claims "typecheck + lint + test" but the actual "test:all" script only runs
typecheck + test; either update the CLAUDE.md description to match the current
behavior or change the "test:all" npm/bun script to include the lint step.
Locate the "test:all" script in package.json (script name "test:all") and either
add the lint invocation into that script (e.g., run the lint script between
typecheck and test) or edit the sentence in CLAUDE.md to state precisely what
"test:all" runs (typecheck + test).

In `@package.json`:
- Line 61: The "test:all" npm script currently only runs typecheck and tests and
should include linting; update the "test:all" entry in package.json (the
"test:all" script) to run lint before typecheck and tests (e.g., run the
existing lint script then typecheck then test) so lint regressions are caught
when developers run test:all; ensure the order is lint -> typecheck -> test and
keep the same execution environment (bun) as other scripts.

In `@packages/audio-capture-napi/src/index.ts`:
- Around line 1-6: The code uses createRequire and a nodeRequire alias to load
the native addon which prevents Bun's static analysis from seeing the require;
remove the import of createRequire and the nodeRequire variable, and replace
uses of nodeRequire(process.env.AUDIO_CAPTURE_NODE_PATH) with a direct
import.meta.require(process.env.AUDIO_CAPTURE_NODE_PATH) call so
AUDIO_CAPTURE_NODE_PATH remains a direct native-addon require; update any
references to createRequire/nodeRequire in this module (and keep the environment
var name AUDIO_CAPTURE_NODE_PATH) and do not introduce node:module imports.

In `@packages/image-processor-napi/src/index.ts`:
- Around line 65-66: The code contains an unused Bun.file(tmpPath) allocation
(const file = Bun.file(tmpPath)) that is dead code because the buffer is read
with readFileSync(tmpPath) instead; remove the unused declaration
(Bun.file(tmpPath)) or, if you intend to use Bun APIs, replace the readFileSync
usage by the corresponding Bun sync read and assign to buffer consistently
(update references to file, tmpPath, and buffer accordingly) so there are no
unused variables.
- Line 1: Remove the unused Bun.file call by deleting the variable assignment
"const file = Bun.file(tmpPath)" (the unused symbol file) and keep the existing
readFileSync(tmpPath) usage; ensure no other code references "file" or
Bun.file(tmpPath) in the surrounding logic (e.g., where tmpPath and buffer are
used) so the code compiles without the unused variable.

In `@scripts/defines.ts`:
- Around line 29-67: DEFAULT_BUILD_FEATURES is reused by scripts/dev.ts but has
UDS_INBOX commented out, which changes bun run dev behavior; restore dev parity
by creating a separate constant DEFAULT_DEV_FEATURES (including UDS_INBOX and
any other dev-only flags) and update scripts/dev.ts to consume
DEFAULT_DEV_FEATURES instead of DEFAULT_BUILD_FEATURES, leaving
DEFAULT_BUILD_FEATURES unchanged for production builds.

In `@src/utils/attachments.ts`:
- Around line 2375-2379: Replace the inline CommonJS require with a static ESM
import: add "import { isPoorModeActive } from '../commands/poor/poorMode.js'" at
the module top, remove the inline require line and its type assertion, and keep
the synchronous call to isPoorModeActive() as-is; ensure no other code relies on
the removed require.

In `@src/utils/model/model.ts`:
- Around line 129-134: The user-specified model parsing can recurse because
getUserSpecifiedModelSetting() may return alias tokens (e.g., "sonnet", "haiku",
"opus", "best", "opusplan") that parseUserSpecifiedModel() itself resolves by
calling the same default-model helpers; to fix, add a guard before calling
parseUserSpecifiedModel(): detect alias tokens (implement or reuse an
isModelAlias(value) check) and if the value is an alias return it or resolve to
a concrete model without invoking the default-model helpers again; update every
call site that directly calls parseUserSpecifiedModel() on
getUserSpecifiedModelSetting() (including the occurrences around
parseUserSpecifiedModel at the other noted call sites) to use the alias guard so
recursion/stacks are prevented.

---

Outside diff comments:
In `@src/utils/permissions/yoloClassifier.ts`:
- Around line 781-807: The objects stage1Opts, stage2Opts, and sideQueryOpts
currently include a live LangfuseSpan (parentSpan) and that same object is
passed to maybeDumpAutoMode() and setLastClassifierRequests(), risking
serialization of trace internals; keep parentSpan only on the object passed to
sideQuery (e.g., call sideQuery(stage1Opts) with parentSpan present) but pass a
redacted copy (shallow clone with parentSpan removed) to maybeDumpAutoMode() and
setLastClassifierRequests(); update the three spots (where
stage1Opts/stage2Opts/sideQueryOpts are created and used) to build or clone a
copy like { ...opts } then delete or omit parentSpan before calling
maybeDumpAutoMode and setLastClassifierRequests so the real span remains for
sideQuery but is not stored/dumped.

---

Nitpick comments:
In `@src/utils/attachments.ts`:
- Around line 2197-2226: The function getRelevantMemoryAttachments uses a
loosely typed parentSpan (parentSpan?: unknown) and then casts it when calling
findRelevantMemories, which hides type errors; import the proper tracing/span
type (e.g., Span or TracingSpan) and change the signature to parentSpan?: Span,
remove the cast parentSpan as Parameters<typeof findRelevantMemories>[5] and
pass parentSpan directly into findRelevantMemories, and update the other
occurrence around lines ~2401-2409 the same way so both call sites use the
explicit Span type instead of unknown/casts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7fd62a02-d906-4ccf-ada6-314dfd976e09

📥 Commits

Reviewing files that changed from the base of the PR and between 92f8a92 and 99e24fe.

📒 Files selected for processing (19)
  • CLAUDE.md
  • build.ts
  • package.json
  • packages/audio-capture-napi/src/index.ts
  • packages/color-diff-napi/src/index.ts
  • packages/image-processor-napi/src/index.ts
  • scripts/defines.ts
  • scripts/dev.ts
  • scripts/vite-plugin-feature-flags.ts
  • src/memdir/findRelevantMemories.ts
  • src/services/langfuse/index.ts
  • src/services/langfuse/tracing.ts
  • src/utils/attachments.ts
  • src/utils/context.ts
  • src/utils/model/model.ts
  • src/utils/permissions/permissions.ts
  • src/utils/permissions/yoloClassifier.ts
  • src/utils/sideQuery.ts
  • src/utils/tokens.ts

Comment thread CLAUDE.md
Comment on lines +61 to +63
# Full check (typecheck + lint + test) — run after completing any task
bun run test:all

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix command description mismatch with actual script behavior.

Line 61 says test:all includes lint, but bun run test:all currently runs only typecheck + test. Please either update the description or include lint in the script to avoid misleading contributors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` around lines 61 - 63, The README line for the "test:all" command
is inaccurate: it claims "typecheck + lint + test" but the actual "test:all"
script only runs typecheck + test; either update the CLAUDE.md description to
match the current behavior or change the "test:all" npm/bun script to include
the lint step. Locate the "test:all" script in package.json (script name
"test:all") and either add the lint invocation into that script (e.g., run the
lint script between typecheck and test) or edit the sentence in CLAUDE.md to
state precisely what "test:all" runs (typecheck + test).

Comment thread package.json
"postinstall": "node scripts/run-parallel.mjs scripts/postinstall.cjs scripts/setup-chrome-mcp.mjs",
"docs:dev": "npx mintlify dev",
"typecheck": "tsc --noEmit",
"test:all": "bun run typecheck && bun test",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

test:all is not actually “all” checks right now.

The script omits lint, while docs/CI messaging treat it as full validation. This can let lint regressions pass when developers run only test:all.

Suggested fix
-    "test:all": "bun run typecheck && bun test",
+    "test:all": "bun run typecheck && bun run lint && bun test",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 61, The "test:all" npm script currently only runs
typecheck and tests and should include linting; update the "test:all" entry in
package.json (the "test:all" script) to run lint before typecheck and tests
(e.g., run the existing lint script then typecheck then test) so lint
regressions are caught when developers run test:all; ensure the order is lint ->
typecheck -> test and keep the same execution environment (bun) as other
scripts.

Comment on lines +1 to +6
import { createRequire } from 'node:module'

// createRequire works in both Bun and Node.js ESM contexts.
// Needed because this package is "type": "module" but uses require() for
// loading native .node addons — bare require is not available in Node.js ESM.
const nodeRequire = createRequire(import.meta.url)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect native addon require handling and build-time defines.
# Expectation: build scripts/comments indicate import.meta.require/direct require
# is the supported analyzable form; createRequire/nodeRequire aliases should be
# explicitly handled before keeping this change.

rg -n -C4 'AUDIO_CAPTURE_NODE_PATH|audio-capture\.node|import\.meta\.require|createRequire|nodeRequire|require\(process\.env' \
  --glob '*.ts' \
  --glob '*.js'

Repository: claude-code-best/claude-code

Length of output: 13385


Bun static analysis requires a direct native addon require call, not one hidden behind a createRequire alias.

The native addon path at line 42-46 documents that AUDIO_CAPTURE_NODE_PATH must remain a direct require() call for Bun to analyze it statically. Using nodeRequire(process.env.AUDIO_CAPTURE_NODE_PATH) breaks this because Bun cannot trace the call through an alias. Additionally, importing createRequire from node:module violates the guideline to use only Bun runtime APIs.

Use import.meta.require instead, which the build system automatically post-processes to Node.js-compatible versions:

-import { createRequire } from 'node:module'
-
-// createRequire works in both Bun and Node.js ESM contexts.
-// Needed because this package is "type": "module" but uses require() for
-// loading native .node addons — bare require is not available in Node.js ESM.
-const nodeRequire = createRequire(import.meta.url)
+// Bun API; build.ts post-processes import.meta.require to Node.js compatibility.
+const nodeRequire = import.meta.require
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/audio-capture-napi/src/index.ts` around lines 1 - 6, The code uses
createRequire and a nodeRequire alias to load the native addon which prevents
Bun's static analysis from seeing the require; remove the import of
createRequire and the nodeRequire variable, and replace uses of
nodeRequire(process.env.AUDIO_CAPTURE_NODE_PATH) with a direct
import.meta.require(process.env.AUDIO_CAPTURE_NODE_PATH) call so
AUDIO_CAPTURE_NODE_PATH remains a direct native-addon require; update any
references to createRequire/nodeRequire in this module (and keep the environment
var name AUDIO_CAPTURE_NODE_PATH) and do not introduce node:module imports.

@@ -1,3 +1,4 @@
import { readFileSync, unlinkSync } from 'node:fs'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for node:fs usage patterns and verify if Bun APIs are available

# Search for other node:fs imports in the codebase
echo "=== Checking for node:fs imports ==="
rg -n "from ['\"]node:fs['\"]" --type=ts

# Search for Bun.file usage patterns
echo -e "\n=== Checking Bun.file usage patterns ==="
rg -n "Bun\.file\(" --type=ts -A 2

# Check for readFileSync usage
echo -e "\n=== Checking readFileSync usage ==="
rg -n "readFileSync" --type=ts

Repository: claude-code-best/claude-code

Length of output: 17530


Remove the unused Bun.file() call on line 65.

Line 65 creates a Bun.file(tmpPath) variable that is never used. The immediately following line uses readFileSync(tmpPath) instead. Remove the unused variable assignment.

Relevant code context
const file = Bun.file(tmpPath)
const buffer: Buffer = readFileSync(tmpPath)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/image-processor-napi/src/index.ts` at line 1, Remove the unused
Bun.file call by deleting the variable assignment "const file =
Bun.file(tmpPath)" (the unused symbol file) and keep the existing
readFileSync(tmpPath) usage; ensure no other code references "file" or
Bun.file(tmpPath) in the surrounding logic (e.g., where tmpPath and buffer are
used) so the code compiles without the unused variable.

Comment on lines 65 to +66
const file = Bun.file(tmpPath)
// Use synchronous read via Node compat
const fs = require('fs')
const buffer: Buffer = fs.readFileSync(tmpPath)
const buffer: Buffer = readFileSync(tmpPath)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove unused Bun.file() call - dead code detected.

Line 65 declares const file = Bun.file(tmpPath) but this variable is never used. Line 66 immediately uses readFileSync(tmpPath) instead. This suggests an incomplete refactor.

🧹 Proposed fix to remove dead code

Option 1: Remove the unused line (recommended for this synchronous context)

-        const file = Bun.file(tmpPath)
         const buffer: Buffer = readFileSync(tmpPath)

Option 2: Use Bun APIs consistently (if Bun has sync file reading)

If Bun provides synchronous file reading APIs, consider using them instead to align with coding guidelines:

const file = Bun.file(tmpPath)
const buffer = Buffer.from(/* appropriate Bun sync API */)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const file = Bun.file(tmpPath)
// Use synchronous read via Node compat
const fs = require('fs')
const buffer: Buffer = fs.readFileSync(tmpPath)
const buffer: Buffer = readFileSync(tmpPath)
const buffer: Buffer = readFileSync(tmpPath)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/image-processor-napi/src/index.ts` around lines 65 - 66, The code
contains an unused Bun.file(tmpPath) allocation (const file = Bun.file(tmpPath))
that is dead code because the buffer is read with readFileSync(tmpPath) instead;
remove the unused declaration (Bun.file(tmpPath)) or, if you intend to use Bun
APIs, replace the readFileSync usage by the corresponding Bun sync read and
assign to buffer consistently (update references to file, tmpPath, and buffer
accordingly) so there are no unused variables.

Comment thread scripts/defines.ts
Comment on lines +29 to +67
export const DEFAULT_BUILD_FEATURES = [
'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
'AGENT_TRIGGERS_REMOTE',
'CHICAGO_MCP',
'VOICE_MODE',
'SHOT_STATS',
'PROMPT_CACHE_BREAK_DETECTION',
'TOKEN_BUDGET',
// P0: local features
'AGENT_TRIGGERS',
'ULTRATHINK',
'BUILTIN_EXPLORE_PLAN_AGENTS',
'LODESTONE',
// P1: API-dependent features
'EXTRACT_MEMORIES',
'VERIFICATION_AGENT',
'KAIROS_BRIEF',
'AWAY_SUMMARY',
'ULTRAPLAN',
// P2: daemon + remote control server
'DAEMON',
// ACP (Agent Client Protocol) agent mode
'ACP',
// PR-package restored features
'WORKFLOW_SCRIPTS',
'HISTORY_SNIP',
'CONTEXT_COLLAPSE',
'MONITOR_TOOL',
'FORK_SUBAGENT',
// 'UDS_INBOX',
'KAIROS',
'COORDINATOR_MODE',
'LAN_PIPES',
'BG_SESSIONS',
'TEMPLATES',
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
// P3: poor mode (disable extract_memories + prompt_suggestion)
'POOR',
] as const;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve the previous dev-only feature defaults.

DEFAULT_BUILD_FEATURES is now reused by scripts/dev.ts, but Line 58 comments out UDS_INBOX, which the previous dev default list enabled. This silently changes bun run dev behavior. Consider adding a separate dev default list, or re-enable UDS_INBOX if this shared list is intended to preserve dev parity.

Suggested direction
 export const DEFAULT_BUILD_FEATURES = [
     'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
@@
     'POOR',
 ] as const;
+
+export const DEFAULT_DEV_FEATURES = [
+    ...DEFAULT_BUILD_FEATURES,
+    'UDS_INBOX',
+] as const;

Then have scripts/dev.ts consume DEFAULT_DEV_FEATURES instead of DEFAULT_BUILD_FEATURES.

Based on learnings: Dev mode enables all feature flags by default via -d flag injection through scripts/dev.ts.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const DEFAULT_BUILD_FEATURES = [
'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
'AGENT_TRIGGERS_REMOTE',
'CHICAGO_MCP',
'VOICE_MODE',
'SHOT_STATS',
'PROMPT_CACHE_BREAK_DETECTION',
'TOKEN_BUDGET',
// P0: local features
'AGENT_TRIGGERS',
'ULTRATHINK',
'BUILTIN_EXPLORE_PLAN_AGENTS',
'LODESTONE',
// P1: API-dependent features
'EXTRACT_MEMORIES',
'VERIFICATION_AGENT',
'KAIROS_BRIEF',
'AWAY_SUMMARY',
'ULTRAPLAN',
// P2: daemon + remote control server
'DAEMON',
// ACP (Agent Client Protocol) agent mode
'ACP',
// PR-package restored features
'WORKFLOW_SCRIPTS',
'HISTORY_SNIP',
'CONTEXT_COLLAPSE',
'MONITOR_TOOL',
'FORK_SUBAGENT',
// 'UDS_INBOX',
'KAIROS',
'COORDINATOR_MODE',
'LAN_PIPES',
'BG_SESSIONS',
'TEMPLATES',
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
// P3: poor mode (disable extract_memories + prompt_suggestion)
'POOR',
] as const;
export const DEFAULT_BUILD_FEATURES = [
'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
'AGENT_TRIGGERS_REMOTE',
'CHICAGO_MCP',
'VOICE_MODE',
'SHOT_STATS',
'PROMPT_CACHE_BREAK_DETECTION',
'TOKEN_BUDGET',
// P0: local features
'AGENT_TRIGGERS',
'ULTRATHINK',
'BUILTIN_EXPLORE_PLAN_AGENTS',
'LODESTONE',
// P1: API-dependent features
'EXTRACT_MEMORIES',
'VERIFICATION_AGENT',
'KAIROS_BRIEF',
'AWAY_SUMMARY',
'ULTRAPLAN',
// P2: daemon + remote control server
'DAEMON',
// ACP (Agent Client Protocol) agent mode
'ACP',
// PR-package restored features
'WORKFLOW_SCRIPTS',
'HISTORY_SNIP',
'CONTEXT_COLLAPSE',
'MONITOR_TOOL',
'FORK_SUBAGENT',
// 'UDS_INBOX',
'KAIROS',
'COORDINATOR_MODE',
'LAN_PIPES',
'BG_SESSIONS',
'TEMPLATES',
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
// P3: poor mode (disable extract_memories + prompt_suggestion)
'POOR',
] as const;
export const DEFAULT_DEV_FEATURES = [
...DEFAULT_BUILD_FEATURES,
'UDS_INBOX',
] as const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/defines.ts` around lines 29 - 67, DEFAULT_BUILD_FEATURES is reused by
scripts/dev.ts but has UDS_INBOX commented out, which changes bun run dev
behavior; restore dev parity by creating a separate constant
DEFAULT_DEV_FEATURES (including UDS_INBOX and any other dev-only flags) and
update scripts/dev.ts to consume DEFAULT_DEV_FEATURES instead of
DEFAULT_BUILD_FEATURES, leaving DEFAULT_BUILD_FEATURES unchanged for production
builds.

Comment thread src/utils/attachments.ts
Comment on lines +2375 to +2379
// Poor mode: skip the side-query to save tokens
const { isPoorModeActive } = require('../commands/poor/poorMode.js') as typeof import('../commands/poor/poorMode.js')
if (isPoorModeActive()) {
return undefined
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check the new poor-mode import site and surrounding no-require lint suppression patterns.

rg -n -C3 "require\\('../commands/poor/poorMode\\.js'\\)|isPoorModeActive" --type ts
rg -n -C2 "@typescript-eslint/no-require-imports|no-require-imports" --type ts

Repository: claude-code-best/claude-code

Length of output: 50387


Convert to ESM import for isPoorModeActive.

Line 2376 uses bare require() outside any ESM suppression block. Since isPoorModeActive() is called synchronously, use a static import:

import { isPoorModeActive } from '../commands/poor/poorMode.js'

Then remove the inline require statement. This aligns with the ESM-only project standard and matches how isPoorModeActive is imported elsewhere in the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/attachments.ts` around lines 2375 - 2379, Replace the inline
CommonJS require with a static ESM import: add "import { isPoorModeActive } from
'../commands/poor/poorMode.js'" at the module top, remove the inline require
line and its type assertion, and keep the synchronous call to isPoorModeActive()
as-is; ensure no other code relies on the removed require.

Comment thread src/utils/model/model.ts
Comment on lines +129 to +134
// Fall back to user's configured model — custom providers may not
// recognize hardcoded Anthropic model IDs.
const userSpecifiedOpus = getUserSpecifiedModelSetting()
if (userSpecifiedOpus) {
return parseUserSpecifiedModel(userSpecifiedOpus)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Guard aliases before parsing user defaults.

getUserSpecifiedModelSetting() can return aliases, but parseUserSpecifiedModel() resolves aliases by calling these same default-model helpers. Settings like ANTHROPIC_MODEL=sonnet, haiku, opus, best, or opusplan can now recurse until stack overflow.

🐛 Proposed fix
+function getUserSpecifiedExplicitModelFallback(): ModelName | undefined {
+  const userSpecified = getUserSpecifiedModelSetting()
+  if (!userSpecified) {
+    return undefined
+  }
+
+  const normalized = userSpecified
+    .trim()
+    .toLowerCase()
+    .replace(/\[1m]$/i, '')
+    .trim()
+
+  if (isModelAlias(normalized)) {
+    return undefined
+  }
+
+  if (
+    getAPIProvider() === 'firstParty' &&
+    isLegacyOpusFirstParty(normalized) &&
+    isLegacyModelRemapEnabled()
+  ) {
+    return undefined
+  }
+
+  return parseUserSpecifiedModel(userSpecified)
+}
+
 // @[MODEL LAUNCH]: Update the default Opus model (3P providers may lag so keep defaults unchanged).
 export function getDefaultOpusModel(): ModelName {
@@
-  const userSpecifiedOpus = getUserSpecifiedModelSetting()
-  if (userSpecifiedOpus) {
-    return parseUserSpecifiedModel(userSpecifiedOpus)
+  const userSpecifiedOpus = getUserSpecifiedExplicitModelFallback()
+  if (userSpecifiedOpus) {
+    return userSpecifiedOpus
   }
@@
-  const userSpecified = getUserSpecifiedModelSetting()
+  const userSpecified = getUserSpecifiedExplicitModelFallback()
   if (userSpecified) {
-    return parseUserSpecifiedModel(userSpecified)
+    return userSpecified
   }
@@
-  const userSpecifiedHaiku = getUserSpecifiedModelSetting()
+  const userSpecifiedHaiku = getUserSpecifiedExplicitModelFallback()
   if (userSpecifiedHaiku) {
-    return parseUserSpecifiedModel(userSpecifiedHaiku)
+    return userSpecifiedHaiku
   }

Also applies to: 162-168, 191-196

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/model/model.ts` around lines 129 - 134, The user-specified model
parsing can recurse because getUserSpecifiedModelSetting() may return alias
tokens (e.g., "sonnet", "haiku", "opus", "best", "opusplan") that
parseUserSpecifiedModel() itself resolves by calling the same default-model
helpers; to fix, add a guard before calling parseUserSpecifiedModel(): detect
alias tokens (implement or reuse an isModelAlias(value) check) and if the value
is an alias return it or resolve to a concrete model without invoking the
default-model helpers again; update every call site that directly calls
parseUserSpecifiedModel() on getUserSpecifiedModelSetting() (including the
occurrences around parseUserSpecifiedModel at the other noted call sites) to use
the alias guard so recursion/stacks are prevented.

@claude-code-best claude-code-best merged commit e4ce08f into main Apr 20, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant