Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package opencode for openSUSE:Factory 
checked in at 2026-09-16 17:42:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/opencode (Old)
 and      /work/SRC/openSUSE:Factory/.opencode.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "opencode"

Wed Sep 16 17:42:05 2026 rev:13 rq:1378139 version:1.18.30

Changes:
--------
--- /work/SRC/openSUSE:Factory/opencode/opencode.changes        2026-09-14 
16:26:30.667953446 +0200
+++ /work/SRC/openSUSE:Factory/.opencode.new.383539/opencode.changes    
2026-09-16 17:44:16.845872808 +0200
@@ -1,0 +2,41 @@
+Tue Sep 15 06:32:42 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Highlight 31 of the languages the TUI used to download grammars
+  for from the distribution instead: their descriptors now point
+  at the tree-sitter-<lang>-wasm module and the -queries
+  highlights.scm (Recommends; cpp also takes c's, upstream's cpp
+  query is a delta on it), and %check loads and compiles every
+  pair in the bundled web-tree-sitter runtime. hcl, kotlin and vue
+  stay blocked: no packaged queries (hcl, kotlin), a query the
+  runtime rejects (vue)
+
+-------------------------------------------------------------------
+Mon Sep 14 19:35:42 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Take the highlighter's five grammar modules from the
+  tree-sitter-javascript-wasm, -typescript-wasm, -markdown-wasm and
+  -zig-wasm packages instead of building them from grammar tarballs
+  here, so the grammar versions follow the packaged releases
+  (javascript 0.23.1, markdown 0.5.3); drop those tarballs and the
+  clang, lld and wasi-libc build dependencies
+
+-------------------------------------------------------------------
+Mon Sep 14 15:34:15 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Build the native code the executable carries from source, or load
+  it from the distribution:
+  * Use the fff and bun-pty packages (required at the pinned
+    versions) for the file finder and the shell pty, loaded at
+    run time
+  * Take photon's WebAssembly module and glue from photon-node
+  * Compile @parcel/watcher's addon from its own sources
+  * Build the highlighter's five tree-sitter grammar modules from
+    the grammar sources with clang, lld and wasi-libc
+- Add opencode-native-tree-sitter.patch: parse shell commands with
+  libtree-sitter and the tree-sitter-bash and
+  tree-sitter-powershell packages through bun:ffi, with a small C
+  shim (opencode-tsshim.c) installed under libdir;
+  web-tree-sitter's runtime stays only for the highlighter and is
+  declared bundled
+
+-------------------------------------------------------------------

New:
----
  node-addon-api-7.1.1.tgz
  opencode-native-tree-sitter.patch
  opencode-tsshim.c

----------(New B)----------
  New:    the grammar sources with clang, lld and wasi-libc
- Add opencode-native-tree-sitter.patch: parse shell commands with
  libtree-sitter and the tree-sitter-bash and
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ opencode.spec ++++++
--- /var/tmp/diff_new_pack.JRFnoi/_old  2026-09-16 17:44:19.393979270 +0200
+++ /var/tmp/diff_new_pack.JRFnoi/_new  2026-09-16 17:44:19.398979480 +0200
@@ -26,6 +26,27 @@
 # versioning of its own, so the runtime opentui package must be the
 # release this tree pins. %%prep checks that this still matches.
 %global opentui_version 0.4.5
+# The two native libraries loaded through bun:ffi at run time. Both ABIs are
+# private to the TypeScript that ships in the vendor tree, so the packages
+# are required at exactly the version that tree was generated from; %%prep
+# checks the pins.
+%global fff_version 0.9.4
+%global bun_pty_version 0.4.8
+%global photon_version 0.3.4
+# The tree-sitter grammars @opentui/core highlights with. The modules come
+# from the tree-sitter-<lang>-wasm packages at these versions (its own
+# parsers-config.ts pins javascript 0.25.0 and markdown 0.5.1; the
+# highlight queries were checked against the packaged releases).
+%global ts_javascript_version 0.23.1
+%global ts_typescript_version 0.23.2
+%global ts_markdown_version 0.5.3
+%global ts_zig_version 1.1.2
+%global parcel_watcher_version 2.5.1
+%global node_addon_api_version 7.1.1
+# The TUI highlighter's languages served from tree-sitter-<lang>-wasm and
+# -queries packages (grammar names as in the upstream descriptor list; the
+# c_sharp module lives in tree-sitter-c-sharp).
+%global opencode_system_grammars python rust go cpp csharp bash c java ruby 
php scala html json yaml haskell css julia lua ocaml clojure swift toml nix 
diff elixir fsharp r make vim xml agda
 # Node's names for the platform, not RPM's: the build target is derived from
 # them, and @opentui/core resolves its native library by the same names.
 %ifarch x86_64
@@ -65,6 +86,10 @@
 Source4:        %{name}_vendor_trace
 Source5:        %{name}-vendor-keep.txt
 Source6:        README.SUSE-maint
+# Header-only N-API wrapper @parcel/watcher's addon is compiled against.
+Source11:       
https://registry.npmjs.org/node-addon-api/-/node-addon-api-%{node_addon_api_version}.tgz
+# C side of the native shell parser (Patch5).
+Source12:       %{name}-tsshim.c
 # Upstream's build script fails unless bun satisfies a caret range around the
 # version it pins. It pins 1.3.14 and Factory has 1.4.2, so the check passes
 # and this patch is inert today; it stays because both versions float, and a
@@ -79,22 +104,182 @@
 Patch3:         %{name}-no-grammar-download.patch
 # PATCH-FIX-UPSTREAM opencode-fix-filesystem-cycle.patch boo#1280159 
gh#anomalyco/opencode#48397
 Patch4:         %{name}-fix-filesystem-cycle.patch
+# Parses shell commands with the system libtree-sitter and grammar packages
+# through bun:ffi; the wasm route needs a runtime module only emscripten can
+# build. Placeholders are filled in below.
+Patch5:         %{name}-native-tree-sitter.patch
 # No floor. Which bun upstream wants changes with every release and Patch0
 # turns a mismatch into a warning; a floor here would be a guess at which
 # older bun still works, and the package is a git snapshot anyway, so
 # 1.4.0~git sorts below 1.4.0.
 BuildRequires:  bun
+BuildRequires:  gcc
+BuildRequires:  gcc-c++
+BuildRequires:  nodejs26-devel
+BuildRequires:  photon-node = %{photon_version}
 # %%prep reads the @opentui/core pin out of package.json.
 BuildRequires:  python3-base
+# Only for %%check, which loads every system grammar module with its
+# queries the way the highlighter will.
+BuildRequires:  tree-sitter-agda-queries
+BuildRequires:  tree-sitter-agda-wasm
+BuildRequires:  tree-sitter-bash
+BuildRequires:  tree-sitter-bash-queries
+BuildRequires:  tree-sitter-bash-wasm
+BuildRequires:  tree-sitter-c-queries
+BuildRequires:  tree-sitter-c-sharp-queries
+BuildRequires:  tree-sitter-c-sharp-wasm
+BuildRequires:  tree-sitter-c-wasm
+BuildRequires:  tree-sitter-clojure-queries
+BuildRequires:  tree-sitter-clojure-wasm
+BuildRequires:  tree-sitter-cpp-queries
+BuildRequires:  tree-sitter-cpp-wasm
+BuildRequires:  tree-sitter-css-queries
+BuildRequires:  tree-sitter-css-wasm
+BuildRequires:  tree-sitter-devel
+BuildRequires:  tree-sitter-diff-queries
+BuildRequires:  tree-sitter-diff-wasm
+BuildRequires:  tree-sitter-elixir-queries
+BuildRequires:  tree-sitter-elixir-wasm
+BuildRequires:  tree-sitter-fsharp-queries
+BuildRequires:  tree-sitter-fsharp-wasm
+BuildRequires:  tree-sitter-go-queries
+BuildRequires:  tree-sitter-go-wasm
+BuildRequires:  tree-sitter-haskell-queries
+BuildRequires:  tree-sitter-haskell-wasm
+BuildRequires:  tree-sitter-html-queries
+BuildRequires:  tree-sitter-html-wasm
+BuildRequires:  tree-sitter-java-queries
+BuildRequires:  tree-sitter-java-wasm
+BuildRequires:  tree-sitter-javascript-wasm = %{ts_javascript_version}
+BuildRequires:  tree-sitter-json-queries
+BuildRequires:  tree-sitter-json-wasm
+BuildRequires:  tree-sitter-julia-queries
+BuildRequires:  tree-sitter-julia-wasm
+BuildRequires:  tree-sitter-lua-queries
+BuildRequires:  tree-sitter-lua-wasm
+BuildRequires:  tree-sitter-make-queries
+BuildRequires:  tree-sitter-make-wasm
+BuildRequires:  tree-sitter-markdown-wasm = %{ts_markdown_version}
+BuildRequires:  tree-sitter-nix-queries
+BuildRequires:  tree-sitter-nix-wasm
+BuildRequires:  tree-sitter-ocaml-queries
+BuildRequires:  tree-sitter-ocaml-wasm
+BuildRequires:  tree-sitter-php-queries
+BuildRequires:  tree-sitter-php-wasm
+BuildRequires:  tree-sitter-powershell
+BuildRequires:  tree-sitter-python-queries
+BuildRequires:  tree-sitter-python-wasm
+BuildRequires:  tree-sitter-r-queries
+BuildRequires:  tree-sitter-r-wasm
+BuildRequires:  tree-sitter-ruby-queries
+BuildRequires:  tree-sitter-ruby-wasm
+BuildRequires:  tree-sitter-rust-queries
+BuildRequires:  tree-sitter-rust-wasm
+BuildRequires:  tree-sitter-scala-queries
+BuildRequires:  tree-sitter-scala-wasm
+BuildRequires:  tree-sitter-swift-queries
+BuildRequires:  tree-sitter-swift-wasm
+BuildRequires:  tree-sitter-toml-queries
+BuildRequires:  tree-sitter-toml-wasm
+BuildRequires:  tree-sitter-typescript-wasm = %{ts_typescript_version}
+BuildRequires:  tree-sitter-vim-queries
+BuildRequires:  tree-sitter-vim-wasm
+BuildRequires:  tree-sitter-xml-queries
+BuildRequires:  tree-sitter-xml-wasm
+BuildRequires:  tree-sitter-yaml-queries
+BuildRequires:  tree-sitter-yaml-wasm
+BuildRequires:  tree-sitter-zig-wasm = %{ts_zig_version}
 BuildRequires:  zstd
+Requires:       bun-pty = %{bun_pty_version}
+Requires:       fff = %{fff_version}
 Requires:       git-core
 # Native TUI library, loaded at runtime (not compiled into the binary).
 # Equality because the FFI ABI is private and unversioned.
 Requires:       opentui = %{opentui_version}
 # Downloaded on first use otherwise; opencode shells out to it for grep.
 Requires:       ripgrep
-# bun only supports these two, and so do the prebuilt native modules left in
-# the dependency tree.
+Requires:       tree-sitter-bash
+Requires:       tree-sitter-powershell
+# The 31 languages the TUI highlighter can load from the distribution
+# (see %%prep): a missing pair means plain text for that language.
+Recommends:     tree-sitter-agda-queries
+Recommends:     tree-sitter-agda-wasm
+Recommends:     tree-sitter-bash-queries
+Recommends:     tree-sitter-bash-wasm
+Recommends:     tree-sitter-c-queries
+Recommends:     tree-sitter-c-sharp-queries
+Recommends:     tree-sitter-c-sharp-wasm
+Recommends:     tree-sitter-c-wasm
+Recommends:     tree-sitter-clojure-queries
+Recommends:     tree-sitter-clojure-wasm
+Recommends:     tree-sitter-cpp-queries
+Recommends:     tree-sitter-cpp-wasm
+Recommends:     tree-sitter-css-queries
+Recommends:     tree-sitter-css-wasm
+Recommends:     tree-sitter-diff-queries
+Recommends:     tree-sitter-diff-wasm
+Recommends:     tree-sitter-elixir-queries
+Recommends:     tree-sitter-elixir-wasm
+Recommends:     tree-sitter-fsharp-queries
+Recommends:     tree-sitter-fsharp-wasm
+Recommends:     tree-sitter-go-queries
+Recommends:     tree-sitter-go-wasm
+Recommends:     tree-sitter-haskell-queries
+Recommends:     tree-sitter-haskell-wasm
+Recommends:     tree-sitter-html-queries
+Recommends:     tree-sitter-html-wasm
+Recommends:     tree-sitter-java-queries
+Recommends:     tree-sitter-java-wasm
+Recommends:     tree-sitter-json-queries
+Recommends:     tree-sitter-json-wasm
+Recommends:     tree-sitter-julia-queries
+Recommends:     tree-sitter-julia-wasm
+Recommends:     tree-sitter-lua-queries
+Recommends:     tree-sitter-lua-wasm
+Recommends:     tree-sitter-make-queries
+Recommends:     tree-sitter-make-wasm
+Recommends:     tree-sitter-nix-queries
+Recommends:     tree-sitter-nix-wasm
+Recommends:     tree-sitter-ocaml-queries
+Recommends:     tree-sitter-ocaml-wasm
+Recommends:     tree-sitter-php-queries
+Recommends:     tree-sitter-php-wasm
+Recommends:     tree-sitter-python-queries
+Recommends:     tree-sitter-python-wasm
+Recommends:     tree-sitter-r-queries
+Recommends:     tree-sitter-r-wasm
+Recommends:     tree-sitter-ruby-queries
+Recommends:     tree-sitter-ruby-wasm
+Recommends:     tree-sitter-rust-queries
+Recommends:     tree-sitter-rust-wasm
+Recommends:     tree-sitter-scala-queries
+Recommends:     tree-sitter-scala-wasm
+Recommends:     tree-sitter-swift-queries
+Recommends:     tree-sitter-swift-wasm
+Recommends:     tree-sitter-toml-queries
+Recommends:     tree-sitter-toml-wasm
+Recommends:     tree-sitter-vim-queries
+Recommends:     tree-sitter-vim-wasm
+Recommends:     tree-sitter-xml-queries
+Recommends:     tree-sitter-xml-wasm
+Recommends:     tree-sitter-yaml-queries
+Recommends:     tree-sitter-yaml-wasm
+# Compiled into the executable from source during this build.
+Provides:       bundled(node-addon-api) = %{node_addon_api_version}
+Provides:       bundled(parcel-watcher) = %{parcel_watcher_version}
+# Embedded from the distribution's own packages (the exact BuildRequires
+# above keep these versions truthful; an update of one of those packages
+# makes this one unresolvable until the pin follows).
+Provides:       bundled(photon-node) = %{photon_version}
+Provides:       bundled(tree-sitter-javascript) = %{ts_javascript_version}
+Provides:       bundled(tree-sitter-markdown) = %{ts_markdown_version}
+Provides:       bundled(tree-sitter-typescript) = %{ts_typescript_version}
+Provides:       bundled(tree-sitter-zig) = %{ts_zig_version}
+# The one module still taken from npm: web-tree-sitter's runtime needs
+# emscripten, which the distribution does not have. Used by the highlighter.
+Provides:       bundled(web-tree-sitter) = 0.25.10
+# bun only supports these two.
 ExclusiveArch:  x86_64 aarch64
 
 %description
@@ -112,6 +297,8 @@
 
 %prep
 %autosetup -p1 -a1
+# rpm honours one -a per %%autosetup, so the second tarball by hand.
+tar -xzf %{SOURCE11}
 cp -a %{SOURCE6} .
 
 # Dependencies compiled into the executable whose licence asks for the text to
@@ -144,7 +331,138 @@
 export default 
"%{_libdir}/opentui/@opentui/core-linux-%{node_arch}/libopentui.so"
 EOF
 
+# The two native libraries are loaded from their packages at run time, like
+# libopentui.so above: the vendor tree's loaders get literal paths and the
+# npm binaries are removed so nothing embeds them. Pins first.
+for pin in "@ff-labs+fff-bun@%{fff_version}" "bun-pty@%{bun_pty_version}" \
+           "@silvia-odwyer+photon-node@%{photon_version}" \
+           "@parcel+watcher@%{parcel_watcher_version}"; do
+    test -d "node_modules/.bun/$pin" || {
+        echo "vendor tree has no $pin; the pinned package versions in this 
spec are stale" >&2
+        exit 1
+    }
+done
+fffbun="node_modules/.bun/@ff-labs+fff-bun@%{fff_version}/node_modules/@ff-labs/fff-bun/src"
+cat > "$fffbun/embedded.ts" <<EOF
+export const embeddedLibPath: string | null = "%{_libdir}/fff/libfff_c.so"
+EOF
+sed -i 's|const isEmbedded = embeddedLibPath?.includes("$bunfs") ?? 
false;|const isEmbedded = embeddedLibPath !== null;|' "$fffbun/ffi.ts"
+grep -q 'const isEmbedded = embeddedLibPath !== null;' "$fffbun/ffi.ts"
+rm -rf node_modules/.bun/@ff-labs+fff-bin-*
+pty="node_modules/.bun/bun-pty@%{bun_pty_version}/node_modules/bun-pty/src/terminal.ts"
+python3 - "$pty" <<'EOF'
+import sys
+p = sys.argv[1]; s = open(p).read()
+a = s.index("\t// For bun compile:")
+b = s.index("\t// Fallback: dynamic resolution")
+s = s[:a] + '\treturn "@BUN_PTY_LIB@";\n\n' + s[b:]
+open(p, "w").write(s)
+EOF
+sed -i 's|@BUN_PTY_LIB@|%{_libdir}/bun-pty/librust_pty.so|' "$pty"
+grep -q 'return "%{_libdir}/bun-pty/librust_pty.so";' "$pty"
+rm -rf 
node_modules/.bun/bun-pty@%{bun_pty_version}/node_modules/bun-pty/rust-pty
+
+# photon: the module and glue come from the photon-node package. Upstream
+# patches the npm glue (patches/@silvia-odwyer%%2Fphoton-node@*.patch) so
+# that it bundles under bun and finds the module at the path opencode
+# embeds it under; the same two edits are applied to the package's glue,
+# which a different wasm-bindgen release wrote, so hunks would not apply.
+photon="node_modules/.bun/@silvia-odwyer+photon-node@%{photon_version}/node_modules/@silvia-odwyer/photon-node"
+rm -f "$photon"/photon_rs_bg.wasm "$photon"/photon_rs.js 
"$photon"/photon_rs_bg.js "$photon"/*.d.ts
+cp -p %{_datadir}/photon-node/* "$photon"/
+python3 - "$photon/photon_rs.js" <<'EOF'
+import re, sys
+p = sys.argv[1]; s = open(p).read()
+s, n = re.subn(r"^imports\['__wbindgen_placeholder__'\] = module\.exports;$",
+               "const __wbindgen_placeholder__ = 
{};\nimports['__wbindgen_placeholder__'] = __wbindgen_placeholder__;", s, 
flags=re.M)
+assert n == 1, "placeholder line not found"
+s, n = re.subn(r"^module\.exports\.(__wb\w+) = function", 
r"__wbindgen_placeholder__.\1 = function", s, flags=re.M)
+assert n > 10, "import shims not found"
+old = "const path = require('path').join(__dirname, 'photon_rs_bg.wasm');"
+assert old in s, "wasm path line not found"
+s = s.replace(old, "const path = globalThis.__OPENCODE_PHOTON_WASM_PATH || 
require('path').join(__dirname, 'photon_rs_bg.wasm');")
+open(p, "w").write(s)
+EOF
+
+# Patch5's placeholders, and the npm modules the shell tool no longer loads.
+sed -i 's|@OPENCODE_LIBDIR@|%{_libdir}/%{name}|; 
s|@TREE_SITTER_GRAMMARS@|%{_libdir}/tree-sitter|' \
+    packages/opencode/src/tool/shell.ts 
packages/opencode/src/tool/shell-native.ts
+grep -q '%{_libdir}/tree-sitter/libtree-sitter-bash.so' 
packages/opencode/src/tool/shell.ts
+
+# The TUI highlighter's other languages: upstream downloads the grammar
+# module and a highlights.scm per language on first use (blocked by
+# Patch3). Point the descriptors at the tree-sitter-<lang>-wasm and
+# -queries packages instead; the loader takes a local path as it takes a
+# URL. hcl and kotlin stay blocked: their packaged grammars ship no queries
+# (Factory's kotlin is another grammar than the one upstream pins), and a
+# module without queries highlights nothing. vue stays blocked too: its
+# highlights.scm inherits html_tags and carries a #set! form the
+# web-tree-sitter runtime opencode ships rejects, so it never compiles.
+# Anything else upstream adds stays blocked until it is packaged and
+# listed here. Each descriptor must carry exactly one highlights source
+# and no injections, or the rewrite (and the download block) would not
+# cover it. cpp's packaged query is upstream's delta on top of the C one,
+# so its descriptor gets both files, C first. The locals entries (dead:
+# nothing in @opentui/core reads them) are dropped so no web URL is left
+# in a descriptor the download block no longer filters.
+python3 - packages/tui/src/parsers-config.ts <<'EOF'
+import re, sys
+langs = "%{opencode_system_grammars}".split()
+grammar = {"csharp": "c_sharp"}
+before = {"cpp": ["c"]}
+p = sys.argv[1]; s = open(p).read()
+blocks = re.split(r'(?=\n    \{\n      filetype: ")', s)
+out = []; done = []
+for b in blocks:
+    m = re.match(r'\n    \{\n      filetype: "([a-z_]+)"', b)
+    if m and m.group(1) in langs:
+        ft = m.group(1); g = grammar.get(ft, ft)
+        b = re.sub(r'\n\s*locals: \[.*?\],', '', b, count=1, flags=re.S)
+        live = re.sub(r'^\s*//.*$', '', b, flags=re.M)
+        assert "injections" not in live and "locals" not in live, ft + ": 
injections/locals not handled"
+        hl = re.search(r'highlights: \[(.*?)\],', live, flags=re.S)
+        assert hl and len(re.findall(r'"https://[^"]+";', hl.group(1))) == 1, 
ft + ": not exactly one highlights source"
+        b, n1 = re.subn(r'wasm: "https://[^"]+";', 'wasm: 
"%{_datadir}/tree-sitter/wasm/tree-sitter-' + g + '.wasm"', b, count=1)
+        srcs = ", ".join('"%{_datadir}/tree-sitter/queries/' + q + 
'/highlights.scm"' for q in before.get(ft, []) + [g])
+        b, n2 = re.subn(r'highlights: \[.*?\],', 'highlights: [' + srcs + 
'],', b, count=1, flags=re.S)
+        assert n1 == 1 and n2 == 1, ft
+        done.append(ft)
+    out.append(b)
+missing = sorted(set(langs) - set(done))
+assert not missing, "not in upstream parsers-config: " + " ".join(missing)
+open(p, "w").write("".join(out))
+EOF
+rm -rf 
node_modules/.bun/tree-sitter-bash@*/node_modules/tree-sitter-bash/prebuilds
+rm -f 
node_modules/.bun/tree-sitter-bash@*/node_modules/tree-sitter-bash/tree-sitter-bash.wasm
 \
+      
node_modules/.bun/tree-sitter-powershell@*/node_modules/tree-sitter-powershell/tree-sitter-powershell.wasm
 \
+      
node_modules/.bun/web-tree-sitter@*/node_modules/web-tree-sitter/lib/tree-sitter.wasm
 \
+      
node_modules/.bun/web-tree-sitter@*/node_modules/web-tree-sitter/lib/tree-sitter.wasm.map
 \
+      
node_modules/.bun/web-tree-sitter@*/node_modules/web-tree-sitter/tree-sitter.wasm.map
+
 %build
+# @parcel/watcher's addon, compiled from the source in its own npm package:
+# the sources and defines are binding.gyp's Linux branch, the headers are
+# Node's and node-addon-api's (Source11 unpacks as package/).
+w="node_modules/.bun/@parcel+watcher@%{parcel_watcher_version}/node_modules/@parcel/watcher"
+plat="node_modules/.bun/@parcel+watcher-linux-%{node_arch}-glibc@%{parcel_watcher_version}/node_modules/@parcel/watcher-linux-%{node_arch}-glibc"
+test -d "$plat"
+g++ %{optflags} -shared -fPIC -std=c++17 -DNAPI_DISABLE_CPP_EXCEPTIONS 
-DWATCHMAN -DINOTIFY -DBRUTE_FORCE \
+    -I%{_includedir}/node26 -Ipackage -I"$w/src" \
+    "$w"/src/binding.cc "$w"/src/Watcher.cc "$w"/src/Backend.cc 
"$w"/src/DirTree.cc \
+    "$w"/src/Glob.cc "$w"/src/Debounce.cc "$w"/src/watchman/BSER.cc \
+    "$w"/src/watchman/WatchmanBackend.cc "$w"/src/shared/BruteForceBackend.cc \
+    "$w"/src/linux/InotifyBackend.cc "$w"/src/unix/legacy.cc -o watcher.node
+# It goes into the payload, where no brp script reaches it.
+strip --strip-debug watcher.node
+install -pm 0644 watcher.node "$plat/watcher.node"
+
+# The highlighter's grammar modules, from the tree-sitter-<lang>-wasm
+# packages (bun embeds what sits in the asset directories).
+assets=$(ls -d 
node_modules/.bun/@opentui+core@%{opentui_version}+*/node_modules/@opentui/core/assets)
+for lang in javascript typescript markdown markdown_inline zig; do
+    install -pm 0644 %{_datadir}/tree-sitter/wasm/tree-sitter-$lang.wasm 
"$assets/$lang/tree-sitter-$lang.wasm"
+done
+
 export HOME="$PWD/.home"
 export BUN_INSTALL_CACHE_DIR="$PWD/.bun-cache"
 mkdir -p "$HOME" "$BUN_INSTALL_CACHE_DIR"
@@ -158,6 +476,10 @@
 export OPENCODE_VERSION="%{version}"
 export OPENCODE_CHANNEL=latest
 
+# No DWARF and stripped by hand: this package has no debuginfo subpackage
+# (see the top of the file) and brp stripping is off for the payload's sake.
+gcc %{optflags} -g0 -shared -fPIC -o libopencode-tsshim.so %{SOURCE12} 
-ltree-sitter
+strip --strip-unneeded libopencode-tsshim.so
 cd packages/opencode
 # --single builds only the host platform. --skip-embed-web-ui leaves out the
 # browser interface, which needs another 101 npm packages and embeds two fonts
@@ -173,6 +495,7 @@
 export NO_BRP_STRIP_DEBUG=true
 install -Dpm 0755 
packages/opencode/dist/%{name}-linux-%{node_arch}/bin/%{name} \
     %{buildroot}%{_bindir}/%{name}
+install -Dpm 0755 libopencode-tsshim.so 
%{buildroot}%{_libdir}/%{name}/libopencode-tsshim.so
 
 %check
 # The executable carries its own runtime and payload; if anything stripped or
@@ -180,8 +503,77 @@
 %{buildroot}%{_bindir}/%{name} --version
 test "$(%{buildroot}%{_bindir}/%{name} --version)" = "%{version}"
 
+# What the payload carries: the distribution's modules and the addon built
+# above, nothing from npm.
+python3 - %{buildroot}%{_bindir}/%{name} %{_datadir}/tree-sitter/wasm 
%{_datadir}/photon-node/photon_rs_bg.wasm watcher.node <<'EOF'
+import sys
+exe = open(sys.argv[1], "rb").read()
+for f in ["{}/tree-sitter-{}.wasm".format(sys.argv[2], l) for l in
+          ("javascript", "typescript", "markdown", "markdown_inline", "zig")] 
+ sys.argv[3:]:
+    assert open(f, "rb").read() in exe, f + " is not embedded as built"
+# bun's embedded-file table names every module the payload carries.
+import re
+found = sorted(set((m.group(1), m.group(2)) for m in
+               
re.finditer(rb"\$bunfs/root/([A-Za-z0-9_.-]+?)-[a-z0-9]{8}\.(so|node|wasm)\b", 
exe)))
+expected = sorted([(b"photon_rs_bg", b"wasm"), (b"tree-sitter", b"wasm"), 
(b"watcher", b"node")] +
+                  [(b"tree-sitter-" + l.encode(), b"wasm") for l in
+                   ("javascript", "typescript", "markdown", "markdown_inline", 
"zig")])
+assert found == expected, "embedded native/wasm files: {}".format(found)
+EOF
+# The native shell parser through the shim that ships and the grammar
+# packages: a pipeline yields its two commands.
+cat > check-parse.ts <<'EOF'
+import { NativeParser, loadLanguage } from 
"./packages/opencode/src/tool/shell-native"
+const bash = new 
NativeParser(loadLanguage("%{_libdir}/tree-sitter/libtree-sitter-bash.so", 
"tree_sitter_bash"))
+const tree = bash.parse("cat foo | grep -i bar > out")
+const cmds = tree.rootNode.descendantsOfType("command").map((n) => n.text)
+if (cmds.length !== 2 || cmds[0] !== "cat foo") { console.log(cmds); 
process.exit(1) }
+// Everything else shell.ts reads from a node or a tree.
+const root = tree.rootNode
+const first = root.child(0)
+if (root.childCount < 1 || first === null || first.parent !== root || 
first.type === "" || cmds[1] !== "grep -i bar") {
+  console.log({ childCount: root.childCount, first: first?.type, parent: 
first?.parent?.type, cmds })
+  process.exit(1)
+}
+tree.delete()
+const ps = new 
NativeParser(loadLanguage("%{_libdir}/tree-sitter/libtree-sitter-powershell.so",
 "tree_sitter_powershell"))
+if (ps.parse("Get-ChildItem -Recurse | Select-Object -First 
5").rootNode.descendantsOfType("command").length < 1) process.exit(1)
+EOF
+OPENCODE_TSSHIM=%{buildroot}%{_libdir}/%{name}/libopencode-tsshim.so bun 
check-parse.ts
+# Every language the descriptors now point at the distribution for: the
+# module loads in the web-tree-sitter runtime opencode ships, its
+# highlights.scm compiles against it, and a parse works. A query naming a
+# node the packaged grammar lacks fails here instead of leaving that
+# language unhighlighted at run time.
+W=$(ls -d node_modules/.bun/web-tree-sitter@*/node_modules/web-tree-sitter | 
head -1)
+test -d "$W"
+cat > check-grammars.ts <<EOF
+const { Parser, Language, Query } = await import("$PWD/$W/tree-sitter.js")
+await Parser.init({ locateFile: () => "$PWD/$W/tree-sitter.wasm" })
+const grammar: Record<string, string> = { csharp: "c_sharp" }
+const before: Record<string, string[]> = { cpp: ["c"] }
+let bad = 0
+for (const ft of "%{opencode_system_grammars}".split(" ")) {
+  const g = grammar[ft] ?? ft
+  try {
+    const L = await Language.load("%{_datadir}/tree-sitter/wasm/tree-sitter-" 
+ g + ".wasm")
+    const parts = []
+    for (const q of [...(before[ft] ?? []), g]) parts.push(await 
Bun.file("%{_datadir}/tree-sitter/queries/" + q + "/highlights.scm").text())
+    new Query(L, parts.join("\n"))
+    const p = new Parser(); p.setLanguage(L); if (!p.parse("x")) throw new 
Error("parse returned null")
+  } catch (e) { bad++; console.log(ft + ": " + String(e).slice(0, 200)) }
+}
+if (bad) process.exit(1)
+EOF
+bun check-grammars.ts
+# What stays blocked (hcl, kotlin, vue, and anything upstream adds).
+echo "descriptors still pointing at the web:"
+grep -B1 -E 'wasm: "https://' packages/tui/src/parsers-config.ts | grep -oE 
'filetype: "[a-z_]+"' || :
+
 %files
 %license LICENSE licenses/LICENSE.caniuse-lite
 %doc README.md README.SUSE-maint
 %{_bindir}/%{name}
+%dir %{_libdir}/%{name}
+%{_libdir}/%{name}/libopencode-tsshim.so
 

++++++ README.SUSE-maint ++++++
--- /var/tmp/diff_new_pack.JRFnoi/_old  2026-09-16 17:44:19.492983407 +0200
+++ /var/tmp/diff_new_pack.JRFnoi/_new  2026-09-16 17:44:19.502983825 +0200
@@ -30,15 +30,30 @@
    producing something subtly broken - see "OpenTUI" below. If it moved, bump
    the opentui package first and update opentui_version here.
 
-2. Rebase the five patches. They are small and all of them sit in code
+2. Rebase the six patches. They are small and all of them sit in code
    upstream changes rarely, but the grammar patch in particular is a single
    line in a large file. Drop opencode-fix-filesystem-cycle.patch once the
    release contains upstream PR 48397 (see "Runtime network access").
+   opencode-native-tree-sitter.patch replaces the parser() block of
+   packages/opencode/src/tool/shell.ts; if upstream changes what shell.ts
+   reads from a node, shell-native.ts (added by the patch) must grow with it.
+
+3. Check the native pins. %prep fails if the vendor tree's @ff-labs/fff-bun,
+   bun-pty, @silvia-odwyer/photon-node or @parcel/watcher moved away from
+   fff_version, bun_pty_version, photon_version or parcel_watcher_version;
+   bump the fff, bun-pty and photon-node packages first (their ABIs are
+   private to the TypeScript in the tree, so the Requires are exact). The
+   grammar modules follow the tree-sitter-<lang>-wasm packages: the
+   BuildRequires are exact on ts_*_version, so a tree-sitter-<lang>
+   update in Factory makes this package unresolvable until the pin (and
+   the bundled() version it feeds) follows - by design. On an opentui
+   bump re-check its parsers-config.ts pins and highlight queries
+   against those versions. See "Native code" below.
 
-3. Build locally, then read %check. It runs the compiled binary, which is the
+4. Build locally, then read %check. It runs the compiled binary, which is the
    only thing that proves the payload survived packaging.
 
-4. Re-run the licence check described under "Licensing".
+5. Re-run the licence check described under "Licensing".
 
 
 Why the sources are generated
@@ -156,16 +171,45 @@
         OPENCODE_ALLOW_NPM_INSTALL=1
 
   opencode-no-grammar-download.patch
-        29 of the 34 syntax highlighting grammars in
+        All 34 syntax highlighting grammars in
         packages/tui/src/parsers-config.ts are https URLs; the .wasm comes
         from a GitHub release and the highlight queries from the master
         branch of nvim-treesitter, so what gets fetched changes over time.
         The five grammars @opentui/core ships as real assets - javascript,
-        typescript, markdown, markdown_inline, zig - still work; other
-        filetypes render unhighlighted, which is what upstream already does
-        when a download fails.
+        typescript, markdown, markdown_inline, zig - are not in that table
+        and still work; other filetypes render unhighlighted, which is what
+        upstream already does when a download fails.
         OPENCODE_ALLOW_GRAMMAR_DOWNLOAD=1
 
+31 of the 34 languages that paragraph is about now come from the
+distribution instead: %prep rewrites packages/tui/src/parsers-config.ts so
+that each descriptor's wasm and highlights point at
+/usr/share/tree-sitter/wasm/tree-sitter-<grammar>.wasm and
+/usr/share/tree-sitter/queries/<grammar>/highlights.scm (the loader takes a
+local path exactly as it takes a URL, and a missing file means plain text
+for that language, nothing worse), and the package Recommends the
+tree-sitter-<lang>-wasm and -queries pair for each of them
+(opencode_system_grammars in the spec; csharp's grammar is c_sharp in
+tree-sitter-c-sharp; cpp's descriptor lists the C highlights before its
+own, as upstream's tree-sitter-cpp query set is a delta on top of them).
+The rewrite also drops the locals entries: nothing in @opentui/core reads
+them, and they would otherwise keep web URLs in descriptors the download
+block no longer filters. Three upstream entries stay blocked on purpose:
+hcl, whose packaged grammar ships no queries; kotlin, where Factory
+packages another grammar than the fwcd one upstream pins, also without
+queries; and vue, whose highlights.scm inherits html_tags (upstream lists
+two sources, the rewrite handles exactly one) and ends in a #set! with a
+capture argument that web-tree-sitter 0.25 rejects, so it would never
+compile. The rewrite asserts exactly one upstream highlights source and no
+injections or locals left per descriptor; a descriptor that grows another
+kind of entry needs the rewrite extended first.
+%check loads every listed module with its queries in the web-tree-sitter
+runtime opencode ships, so a query naming a node the packaged grammar lacks
+fails the build rather than the highlighter. On a bump, diff upstream's
+descriptor list against opencode_system_grammars: a new language needs its
+grammar packaged (with -wasm and -queries) before it is added; until then
+Patch3 keeps it blocked.
+
 The other two patches are unrelated to the network.
 
 opencode-relax-bun-version.patch is, as of 1.18.30, inert. Upstream's build
@@ -243,39 +287,61 @@
 above must still hold - but a changed one only tells you where to look.
 
 
-Prebuilt binaries
------------------
+Native code
+-----------
+
+Everything compiled into the executable that is not JavaScript is built
+from source, in three ways:
 
-Some dependencies ship compiled code with no source in the tree, and it ends
-up inside the executable. This is the part of the package a reviewer should
-look at hardest. On aarch64 the embedded blobs are:
-
-    @ff-labs/fff-bin-linux-arm64-gnu  libfff_c.so       4.7 MB  no source
-    @silvia-odwyer/photon-node        photon_rs_bg.wasm 1.8 MB  no source
-    bun-pty                           librust_pty.so    0.5 MB  no source
-    tree-sitter-bash                  .node and .wasm   2.7 MB  parser.c 
present
-    tree-sitter-powershell            .wasm             0.9 MB  parser.c 
present
-    @parcel/watcher-linux-arm64-glibc watcher.node      0.4 MB  C++ in sibling
-    @opentui/core                     5 grammar .wasm   3.1 MB  no source
-    web-tree-sitter                   tree-sitter.wasm  0.2 MB  no source
-
-What they do: fff is the fast file finder (OPENCODE_DISABLE_FFF falls back to
-an internal walk), photon resizes images for vision models, bun-pty is the
-pty behind the shell tool, and the tree-sitter pieces parse shell commands
-for the permission system as well as highlighting.
-
-opencode_vendor removes everything of this kind that the two supported
-architectures cannot run - foreign prebuilds/ directories, .dylib, .dll,
-.exe, the Windows and x86_64 clipboardy fallbacks, web-tree-sitter's debug
-build, and the .tgz copies some packages keep of themselves inside dist/.
-That is 10.8 MB and it changes nothing about the result. What is listed above
-is what remains after that, and it is genuinely used.
-
-Reducing it further means building those artefacts from source: the
-tree-sitter grammars have their parser.c and could be compiled, though the
-.wasm form needs emscripten; fff, bun-pty and photon are Rust with no source
-in the tree at all and would each need their crate closure vendored
-separately.
+  - Loaded from a package at run time (like libopentui.so): libfff_c.so
+    from the fff package (the file finder behind the @ file picker,
+    OPENCODE_DISABLE_FFF falls back to an internal walk) and librust_pty.so
+    from the bun-pty package (the pty behind the shell tool). %prep rewrites
+    the two npm loaders to those literal paths and removes the npm binaries,
+    so bun has nothing to embed. Both ABIs are unversioned and private to
+    the TypeScript shipped here, hence the exact Requires.
+
+  - Embedded, built here from source: @parcel/watcher's watcher.node from the
+    C++ in its own npm package (binding.gyp's Linux branch, node-addon-api
+    headers from Source11).
+
+  - Embedded, taken from packages: the five grammar modules @opentui/core
+    highlights with (javascript, typescript, markdown, markdown_inline, zig)
+    are the tree-sitter-<lang>-wasm subpackages' files, copied over the
+    asset directories before bun build. Those packages build every Factory
+    grammar to WebAssembly with the %treesitter_wasm_* macros (clang, lld,
+    wasi-libc through the tree-sitter CLI's own wasi-sdk invocation); the
+    modules parse identically to upstream's release modules under the
+    web-tree-sitter runtime opencode ships and accept opentui's highlight
+    queries (checked when this was introduced, against javascript 0.23.1
+    and markdown 0.5.3 where opentui pins 0.25.0 and 0.5.1).
+
+  - Embedded, taken from a package: photon_rs_bg.wasm and its glue from
+    photon-node (image resizing for vision models). The glue must be the one
+    the same wasm-bindgen wrote, so the whole npm package directory is
+    replaced by the package's files and upstream's two edits to the glue
+    (patches/@silvia-odwyer%2Fphoton-node@*.patch: bundle under bun, read
+    the module from where opencode embeds it) are re-applied by %prep.
+
+The shell tool's command parser no longer goes through wasm at all:
+opencode-native-tree-sitter.patch loads libtree-sitter and the
+tree-sitter-bash / tree-sitter-powershell packages' grammars through
+bun:ffi, with libopencode-tsshim.so (Source12, installed under %_libdir)
+walking the tree, because TSNode is returned by value and bun:ffi cannot
+receive that. %check parses a pipeline through the shipped shim.
+
+One module is still the npm file: web-tree-sitter's tree-sitter.wasm
+(205 KB, MIT), used by @opentui/core's highlighter. Its build needs
+emscripten (MAIN_MODULE dynamic linking plus generated JavaScript glue),
+which the distribution does not have. It is declared as
+bundled(web-tree-sitter). Retiring it means either packaging emscripten or
+giving the highlighter the same native treatment as the shell parser.
+
+%check reads bun's embedded-file table out of the executable and asserts it
+lists exactly watcher.node, the five grammar modules, photon's module and
+tree-sitter.wasm, and that the files built here are in the payload byte
+for byte. (Counting ELF headers does not work: bun's own executable
+contains the magic three times.)
 
 
 Things that will surprise you

++++++ opencode-native-tree-sitter.patch ++++++
From: Martin Pluskal <[email protected]>
Subject: Parse shell commands with the system tree-sitter

The permission system parses every shell command with tree-sitter. Upstream
does that through web-tree-sitter, whose runtime module can only be built
with emscripten, plus the grammar wasm files from the tree-sitter-bash and
tree-sitter-powershell npm packages. The distribution build loads
libtree-sitter and the grammar packages' shared objects through bun:ffi
instead. TSNode is passed by value in the C API, which bun:ffi cannot
receive, so opencode-tsshim.c walks the tree and hands over one JSON dump
per parse; shell-native.ts turns that into the Node subset shell.ts reads.
Placeholders @OPENCODE_LIBDIR@ and @TREE_SITTER_GRAMMARS@ are filled in by
the spec. Distribution-specific, not for upstream.

diff -Naur a/packages/opencode/src/tool/shell-native.ts 
b/packages/opencode/src/tool/shell-native.ts
--- a/packages/opencode/src/tool/shell-native.ts        1970-01-01 
01:00:00.000000000 +0100
+++ b/packages/opencode/src/tool/shell-native.ts        2026-09-14 
17:51:24.493274369 +0200
@@ -0,0 +1,95 @@
+// Native tree-sitter for the shell tool: bun:ffi over the system 
libtree-sitter,
+// with a C shim (opencode-tsshim.c) doing the tree walk because TSNode is
+// returned by value, which bun:ffi cannot receive. Exposes the subset of the
+// web-tree-sitter Node API that shell.ts reads: type, text, parent, children,
+// descendantsOfType.
+
+import { CString, FFIType, dlopen, ptr } from "bun:ffi"
+
+const SHIM = process.env.OPENCODE_TSSHIM ?? 
"@OPENCODE_LIBDIR@/libopencode-tsshim.so"
+
+const shim = dlopen(SHIM, {
+  ocshim_parser_new: { args: [FFIType.ptr], returns: FFIType.ptr },
+  ocshim_parser_delete: { args: [FFIType.ptr], returns: FFIType.void },
+  ocshim_parse: { args: [FFIType.ptr, FFIType.ptr, FFIType.u32], returns: 
FFIType.ptr },
+  ocshim_free: { args: [FFIType.ptr], returns: FFIType.void },
+  ocshim_abi_version: { args: [FFIType.ptr], returns: FFIType.u32 },
+})
+
+export function loadLanguage(path: string, symbol: string): number {
+  const lib = dlopen(path, { [symbol]: { args: [], returns: FFIType.ptr } })
+  const lang = lib.symbols[symbol]() as number
+  if (!lang) throw new Error(`${symbol} returned NULL`)
+  return lang
+}
+
+export class NativeNode {
+  children: NativeNode[] = []
+  constructor(
+    readonly type: string,
+    readonly isNamed: boolean,
+    readonly startIndex: number,
+    readonly endIndex: number,
+    readonly parent: NativeNode | null,
+    private readonly buf: Buffer,
+  ) {}
+  get text(): string {
+    return this.buf.subarray(this.startIndex, this.endIndex).toString("utf8")
+  }
+  get namedChildren(): NativeNode[] {
+    return this.children.filter((c) => c.isNamed)
+  }
+  get childCount(): number {
+    return this.children.length
+  }
+  child(index: number): NativeNode | null {
+    return this.children[index] ?? null
+  }
+  descendantsOfType(types: string | string[]): NativeNode[] {
+    const set = new Set(Array.isArray(types) ? types : [types])
+    const out: NativeNode[] = []
+    const walk = (n: NativeNode) => {
+      if (set.has(n.type)) out.push(n)
+      for (const c of n.children) walk(c)
+    }
+    walk(this)
+    return out
+  }
+  toString(): string {
+    return this.isNamed ? `(${this.type}${this.children.filter((c) => 
c.isNamed).map((c) => " " + c.toString()).join("")})` : ""
+  }
+}
+
+type Raw = [string, number, number, number, Raw[]]
+
+// The C side frees the tree before returning, so there is nothing to
+// release here; delete() exists because shell.ts calls it.
+export class NativeTree {
+  constructor(readonly rootNode: NativeNode) {}
+  delete(): void {}
+}
+
+export class NativeParser {
+  private p: number
+  constructor(lang: number) {
+    const p = shim.symbols.ocshim_parser_new(lang) as number
+    if (!p) throw new Error(`ts_parser_set_language failed (grammar ABI 
${shim.symbols.ocshim_abi_version(lang)})`)
+    this.p = p
+  }
+  parse(src: string): NativeTree {
+    const buf = Buffer.from(src, "utf8")
+    const out = shim.symbols.ocshim_parse(this.p, ptr(buf), buf.length) as 
number
+    if (!out) throw new Error("ts_parser_parse_string failed")
+    const json = new CString(out).toString()
+    shim.symbols.ocshim_free(out)
+    const build = (a: Raw, parent: NativeNode | null): NativeNode => {
+      const n = new NativeNode(a[0], a[1] === 1, a[2], a[3], parent, buf)
+      n.children = a[4].map((c) => build(c, n))
+      return n
+    }
+    return new NativeTree(build(JSON.parse(json) as Raw, null))
+  }
+  delete() {
+    shim.symbols.ocshim_parser_delete(this.p)
+  }
+}
diff -Naur a/packages/opencode/src/tool/shell.ts 
b/packages/opencode/src/tool/shell.ts
--- a/packages/opencode/src/tool/shell.ts       2026-09-14 17:27:48.650152184 
+0200
+++ b/packages/opencode/src/tool/shell.ts       2026-09-14 17:27:48.718159827 
+0200
@@ -6,7 +6,7 @@
 import { containsPath, type InstanceContext } from 
"../project/instance-context"
 import { InstanceState } from "@/effect/instance-state"
 import { lazy } from "@/util/lazy"
-import { Language, type Node } from "web-tree-sitter"
+import { NativeParser, loadLanguage, type NativeNode as Node } from 
"./shell-native"
 
 import { FSUtil } from "@opencode-ai/core/fs-util"
 import { fileURLToPath } from "url"
@@ -309,29 +309,11 @@
   })
 }
 const parser = lazy(async () => {
-  const { Parser } = await import("web-tree-sitter")
-  const { default: treeWasm } = await 
import("web-tree-sitter/tree-sitter.wasm" as string, {
-    with: { type: "wasm" },
-  })
-  const treePath = resolveWasm(treeWasm)
-  await Parser.init({
-    locateFile() {
-      return treePath
-    },
-  })
-  const { default: bashWasm } = await 
import("tree-sitter-bash/tree-sitter-bash.wasm" as string, {
-    with: { type: "wasm" },
-  })
-  const { default: psWasm } = await 
import("tree-sitter-powershell/tree-sitter-powershell.wasm" as string, {
-    with: { type: "wasm" },
-  })
-  const bashPath = resolveWasm(bashWasm)
-  const psPath = resolveWasm(psWasm)
-  const [bashLanguage, psLanguage] = await 
Promise.all([Language.load(bashPath), Language.load(psPath)])
-  const bash = new Parser()
-  bash.setLanguage(bashLanguage)
-  const ps = new Parser()
-  ps.setLanguage(psLanguage)
+  // The distribution build parses with the system libtree-sitter and the
+  // tree-sitter-bash / tree-sitter-powershell grammar packages instead of
+  // the wasm copies from npm; see shell-native.ts.
+  const bash = new 
NativeParser(loadLanguage("@TREE_SITTER_GRAMMARS@/libtree-sitter-bash.so", 
"tree_sitter_bash"))
+  const ps = new 
NativeParser(loadLanguage("@TREE_SITTER_GRAMMARS@/libtree-sitter-powershell.so",
 "tree_sitter_powershell"))
   return { bash, ps }
 })
 

++++++ opencode-no-grammar-download.patch ++++++
--- /var/tmp/diff_new_pack.JRFnoi/_old  2026-09-16 17:44:19.623988881 +0200
+++ /var/tmp/diff_new_pack.JRFnoi/_new  2026-09-16 17:44:19.631989215 +0200
@@ -1,6 +1,6 @@
 The syntax highlighting table in packages/tui/src/parsers-config.ts is 34
-entries, and 29 of them are plain https URLs: the tree-sitter grammar is a
-.wasm fetched from a GitHub release and the highlight queries come from
+entries, all of them plain https URLs: the tree-sitter grammar is a .wasm
+fetched from a GitHub release and the highlight queries come from
 raw.githubusercontent.com. opentui downloads and caches them under
 ~/.local/share/opentui/tree-sitter the first time a file of that type is
 rendered, then loads the .wasm into the process. There is no env var and no
@@ -11,7 +11,8 @@
 nvim-treesitter rather than a tag, so what is fetched changes over time.
 
 The five grammars @opentui/core ships as real assets - javascript,
-typescript, markdown, markdown_inline, zig - are local paths and are kept.
+typescript, markdown, markdown_inline, zig - are not in that table and keep
+working.
 Everything else renders as unhighlighted text, which is what
 loadFiletypeParser already does when a download fails, so this is a path
 upstream handles rather than a new one.

++++++ opencode-tsshim.c ++++++
/* Tree-sitter shim for the opencode shell tool (see the native-tree-sitter
 * patch). libtree-sitter passes TSNode by value, which bun:ffi cannot marshal,
 * so the walk happens here and one JSON string crosses the FFI boundary:
 *   node := [type, isNamed, startByte, endByte, [node...]]
 */
#include <tree_sitter/api.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct { char *buf; size_t len, cap; } sb;

static void sb_put(sb *b, const char *s, size_t n) {
    if (b->len + n + 1 > b->cap) {
        size_t c = b->cap ? b->cap * 2 : 4096;
        while (c < b->len + n + 1) c *= 2;
        b->buf = realloc(b->buf, c);
        b->cap = c;
    }
    memcpy(b->buf + b->len, s, n);
    b->len += n;
    b->buf[b->len] = 0;
}

static void sb_str(sb *b, const char *s) {
    sb_put(b, "\"", 1);
    for (; *s; s++) {
        unsigned char c = (unsigned char)*s;
        if (c == '"' || c == '\\') { char e[2] = {'\\', (char)c}; sb_put(b, e, 
2); }
        else if (c < 0x20) { char e[8]; int n = snprintf(e, sizeof e, 
"\\u%04x", c); sb_put(b, e, (size_t)n); }
        else sb_put(b, s, 1);
    }
    sb_put(b, "\"", 1);
}

static void dump(sb *b, TSTreeCursor *c) {
    TSNode n = ts_tree_cursor_current_node(c);
    char tmp[64];
    sb_put(b, "[", 1);
    sb_str(b, ts_node_type(n));
    int len = snprintf(tmp, sizeof tmp, ",%d,%u,%u,[", ts_node_is_named(n) ? 1 
: 0,
                       ts_node_start_byte(n), ts_node_end_byte(n));
    sb_put(b, tmp, (size_t)len);
    if (ts_tree_cursor_goto_first_child(c)) {
        int first = 1;
        do {
            if (!first) sb_put(b, ",", 1);
            first = 0;
            dump(b, c);
        } while (ts_tree_cursor_goto_next_sibling(c));
        ts_tree_cursor_goto_parent(c);
    }
    sb_put(b, "]]", 2);
}

TSParser *ocshim_parser_new(const TSLanguage *lang) {
    TSParser *p = ts_parser_new();
    if (!ts_parser_set_language(p, lang)) { ts_parser_delete(p); return NULL; }
    return p;
}

void ocshim_parser_delete(TSParser *p) { ts_parser_delete(p); }

char *ocshim_parse(TSParser *p, const char *src, uint32_t len) {
    TSTree *t = ts_parser_parse_string(p, NULL, src, len);
    if (!t) return NULL;
    TSTreeCursor c = ts_tree_cursor_new(ts_tree_root_node(t));
    sb b = {0};
    dump(&b, &c);
    ts_tree_cursor_delete(&c);
    ts_tree_delete(t);
    return b.buf;
}

void ocshim_free(char *s) { free(s); }

uint32_t ocshim_abi_version(const TSLanguage *lang) { return 
ts_language_abi_version(lang); }

++++++ opencode-vendor-1.18.30.tar.zst ++++++
/work/SRC/openSUSE:Factory/opencode/opencode-vendor-1.18.30.tar.zst 
/work/SRC/openSUSE:Factory/.opencode.new.383539/opencode-vendor-1.18.30.tar.zst 
differ: char 7, line 1

++++++ opencode_vendor ++++++
--- /var/tmp/diff_new_pack.JRFnoi/_old  2026-09-16 17:44:19.800996276 +0200
+++ /var/tmp/diff_new_pack.JRFnoi/_new  2026-09-16 17:44:19.808996610 +0200
@@ -178,6 +178,18 @@
 # from source. The shims next to it (index.js, package.json) stay, because
 # that is how @opentui/core locates the library.
 find "$store" -name 'libopentui.so' -delete -printf '    removed %P\n'
+# The same goes for the rest of the native code, see README.SUSE-maint
+# "Native code": libfff_c.so and librust_pty.so come from the fff and bun-pty
+# packages at run time, photon's module and glue from photon-node, and
+# watcher.node and the highlighter's grammar modules are compiled in %build.
+# The shell tool parses with the system tree-sitter, so its two grammar
+# packages' wasm and node prebuilds are unreferenced; web-tree-sitter's lib/
+# copy and the source maps are unreachable through its exports map.
+find "$store" \( -name 'libfff_c.so' -o -name 'librust_pty*.so' -o -name 
'watcher.node' \
+    -o -name 'photon_rs_bg.wasm' -o -name 'photon_rs.js' -o -name 
'photon_rs_bg.js' \
+    -o -name 'tree-sitter-*.wasm' -o -name 'tree-sitter.wasm.map' \) -delete 
-printf '    removed %P\n'
+find "$store" -path '*/tree-sitter-bash/prebuilds' -prune -exec rm -rf {} \; 
-printf '    removed %P\n'
+find "$store" -path '*/web-tree-sitter/lib/tree-sitter.wasm*' -delete -printf 
'    removed %P\n'
 
 echo "==> packing the dependency tree"
 # The per-workspace node_modules are symlink farms into node_modules/.bun and

Reply via email to