Skip to content

fix(doctor): guard tui.json tuple plugin entries in TUI plugin check (fixes #5786)#5801

Open
MoerAI wants to merge 1 commit into
code-yeongyu:devfrom
MoerAI:fix/doctor-tui-tuple-plugin-entry-guard
Open

fix(doctor): guard tui.json tuple plugin entries in TUI plugin check (fixes #5786)#5801
MoerAI wants to merge 1 commit into
code-yeongyu:devfrom
MoerAI:fix/doctor-tui-tuple-plugin-entry-guard

Conversation

@MoerAI

@MoerAI MoerAI commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

omo doctor falsely reported TUI plugin entry missing from tui.json whenever tui.json contained a valid "oh-my-openagent" entry alongside a tuple plugin entry such as ["./plugin.tsx", { ... }]. The tuple made a doctor predicate throw a TypeError, which the broad try/catch swallowed into an all-false registration state.

Root Cause

detectTuiPluginRegistration() and detectServerPluginRegistration() in tui-plugin-config.ts fed the raw parsed plugin array into predicates typed (entry: string) that call String.startsWith:

const plugins = parsed.plugin ?? []
return {
  registered: plugins.some(isTuiPluginEntry),
  hasNamedTuiEntry: plugins.some(isNamedTuiPluginEntry),  // <- throws on a tuple entry
  ...
}

OpenCode plugin config accepts tuple entries of the form [pathOrPackage, options]. When tui.json holds ["oh-my-openagent", ["./local.tsx", { ... }]], .some(isNamedTuiPluginEntry) iterates past the string entry, reaches the tuple, calls entry.startsWith(...) on an array, and throws TypeError: entry.startsWith is not a function. The surrounding catch treats that as an absent registration and returns registered: false, so doctor emits the misleading missing-entry warning.

Changes

File Change
packages/omo-opencode/src/cli/doctor/checks/tui-plugin-config.ts Filter the parsed plugin array to strings before evaluating predicates, in both detectTuiPluginRegistration() and detectServerPluginRegistration()
packages/omo-opencode/src/cli/doctor/checks/tui-plugin-config.test.ts Add a regression case where tui.json pairs the package entry with a tuple plugin entry

The fix reuses the exact guard already used by pluginEntries() in add-tui-plugin-to-tui-config.ts: .filter((entry): entry is string => typeof entry === "string").

Reproduction (before fix)

104 |     //#then the tuple entry is ignored and our string entry still registers the plugin
error: expect(received).toBe(expected)
Expected: "pass"
Received: "warn"
(fail) tui-plugin-config check > passes when tui.json pairs our entry with a tuple third-party plugin entry

Verification (after fix)

(pass) tui-plugin-config check > passes when tui.json pairs our entry with a tuple third-party plugin entry
 14 pass
 0 fail

Test

  • Regression test: packages/omo-opencode/src/cli/doctor/checks/tui-plugin-config.test.ts (1 case added)
  • Related suite: bun test packages/omo-opencode/src/cli/doctor/ — 158 pass. The single spawn-with-timeout failure ("returns stdout and exit code") is a pre-existing Windows subprocess flake that reproduces identically on unmodified dev, unrelated to this change.
  • Typecheck: tsgo -p packages/omo-opencode/tsconfig.json --noEmit — clean (exit 0)

Fixes #5786


Summary by cubic

Fixes a false “TUI plugin entry missing from tui.json” warning in omo doctor when tui.json includes tuple plugin entries. We now ignore tuple entries during checks so valid oh-my-openagent registrations pass.

  • Bug Fixes
    • Filter plugin arrays to strings in detectTuiPluginRegistration() and detectServerPluginRegistration() to avoid calling string methods on tuples.
    • Added a regression test for a mixed config: ["oh-my-openagent", ["./local-tui-plugin.tsx", { ... }]].

Written for commit f56b615. Summary will update on new commits.

Review in cubic

…ixes code-yeongyu#5786)

detectTuiPluginRegistration and detectServerPluginRegistration passed the raw
parsed plugin array straight into predicates that call String.startsWith.
OpenCode plugin config accepts tuple entries of the form [pathOrPackage,
options], so a valid tui.json such as ["oh-my-openagent", ["./local.tsx",
{ ... }]] made .some(isNamedTuiPluginEntry) call .startsWith on the tuple,
throw a TypeError, get swallowed by the broad try/catch, and return an
all-false registration. Doctor then emitted a false "TUI plugin entry missing
from tui.json" warning even though the entry was present.

Filter the plugin array to strings before evaluating the predicates, matching
the existing pluginEntries() guard already used in
add-tui-plugin-to-tui-config.ts.

Reproduction (before): checkTuiPluginConfig() with tui.json
["oh-my-openagent", ["./local-tui-plugin.tsx", { label: "custom" }]] returned
status "warn" (TUI plugin entry missing).
Verification (after): returns status "pass" with no issues. Doctor check suite
158 pass; the single spawn-with-timeout failure is a pre-existing Windows
subprocess flake reproduced on unmodified dev. tsgo -p packages/omo-opencode
clean.
@MoerAI

MoerAI commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author

I have read the CLA Document and I hereby sign the CLA

@github-actions github-actions Bot added the opencode OpenCode edition: packages/omo-opencode label Jul 1, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f56b615c30

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

try {
const parsed = parseJsonc<OpenCodeConfigShape>(readFileSync(configPath, "utf-8"))
const plugins = parsed.plugin ?? []
const plugins = (parsed.plugin ?? []).filter((entry): entry is string => typeof entry === "string")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Extract plugin names from tuple entries

When a user registers OMO itself with OpenCode's tuple form, e.g. ["oh-my-openagent", { ... }] in opencode.json, this filter drops the only server entry instead of normalizing it to the first tuple element. The rest of the repo already treats tuple entries as valid by taking plugin[0] in loadOpencodePlugins(), so checkTuiPluginConfig() will now report the server plugin missing even though OpenCode will load it; the same issue exists for the analogous tui.json filter below. Please normalize tuple entries to their first string element rather than filtering all non-strings out.

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Auto-approved: Fix false positive in doctor check by filtering out non-string plugin entries. Small, safe change with regression test.

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

opencode OpenCode edition: packages/omo-opencode

1 participant