anomalyco / anomalyco/opencode
Wildcard matcher can't escape literal * or ?, and apply_patch ignores @@ anchor for insertions
@nexxeln is already working on this.
Since Aug 8, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
Two small issues I ran into while looking at packages/core. They're unrelated to each other but both tiny, so I've bundled them in one report. Happy to split if you'd rather.
1. Wildcard.match can't match a literal *, ?, or \ (packages/core/src/util/wildcard.ts)
This backs the v1 and v2 permission checks (permission/index.ts, permission.ts) and the tool visibility filter in tool/registry.ts. The pattern is run through .replaceAll("\\", "/") first, then * -> .* and ? -> ., with no escape step in between. So there's no way to write a rule that targets a resource containing one of those characters literally.
Ran the actual function to confirm:
match("config?.json", "config?.json") // true
match("configX.json", "config?.json") // true <- "?" behaves as a wildcard
match("config?.json", "config\?.json") // false <- escaping does nothing
match("anything.ts", "\*") // false <- a literal "*" can't be matched
Net effect: a deny rule like ls config?.json also blocks ls configX.json, and a rule aimed at a file literally named * silently becomes a catch-all. For bash the permission resource is the raw command string, so commands containing a glob match wider than intended.
2. apply_patch ignores the @@ anchor when a chunk has only + lines (packages/core/src/patch.ts)
In computeReplacements the @@ context is located (and advances lineIndex), but when oldLines.length === 0 the insertion is hardcoded to lines.length, i.e. the end of the file:
Patch.derive("f.txt", [{ oldLines: [], newLines: ["inserted"], changeContext: "line2" }], "line1\nline2\nline3\n")
// actual: "line1\nline2\nline3\ninserted\n"
// expected: "line1\nline2\ninserted\nline3\n"
A chunk like @@ after the imports followed by only + lines (a common model output shape) lands at the bottom of the file instead of at the anchor.
Plugins
none
OpenCode version
dev branch, current HEAD 38e10eb
Steps to reproduce
- Permission case: run the
match()calls above against@opencode-ai/core/util/wildcard, or configure a permission rule whose resource contains?/*and try to allow/deny a matching literal resource. - Patch case: call
Patch.derivewith a chunk that has achangeContextand an emptyoldLinesarray, as in the snippet above.
Screenshot and/or share link
none, it's a code-level thing
Operating System
Windows 11
Terminal
Windows Terminal
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.