paseo

LOW
maintainer jinzhongjia 1 votes scanned 2026-11-01 00:21:48.120785
View on AUR
Why flagged

The npx usage in build() runs node-gyp rebuild and expo export, which are legitimate build tools acting on the project's own source; no remote code execution or untrusted package installation occurs.

Triggered rules

Low AI review downgraded a static finding llm_review

The static rules flagged this MEDIUM, but an AI model (qwen/qwen3-235b-a22b-2507) reviewed the full PKGBUILD and judged it LOW (confidence 95%): The npx usage in build() runs node-gyp rebuild and expo export, which are legitimate build tools acting on the project's own source; no remote code execution or untrusted package installation occurs.

1 higher static finding superseded - not the current verdict (shown for transparency)
Medium npx/bunx/deno executes a remote package remote_code_tool

`npx`/`bunx`/`pnpm dlx`/`deno run <url>` downloads AND runs a remote package at build time — the moral equivalent of piping a download into a shell. Severity downgraded: Node.js consumer context.

  • PKGBUILD:118 (cd "$(_node_pty_dir)" && npx node-gyp rebuild)
  • PKGBUILD:132 (cd packages/app && PASEO_WEB_PLATFORM=electron npx expo export --platform web)

PKGBUILD

2 offending line(s) highlighted
1# Maintainer: jinzhongjia <mail@nvimer.org>
2
3pkgname=paseo
4pkgver=0.13.2
5pkgrel=1
6pkgdesc="One interface for all your Claude Code, Codex and OpenCode agents (built from source, runs on system Electron)"
7arch=('x86_64')
8url="https://paseo.sh"
9_github_url="https://github.com/getpaseo/paseo"
10# Keep in sync with packages/desktop/package.json devDependencies.electron —
11# prepare() fails the build when the majors drift apart.
12_electron_pkg=electron44
13license=('Apache-2.0')
14depends=("${_electron_pkg}" 'gcc-libs' 'glibc' 'hicolor-icon-theme' 'nodejs>=22')
15makedepends=('npm' 'python' 'git')
16optdepends=('git: agent worktree management')
17conflicts=('paseo-bin' 'paseo-desktop-bin' 'paseo-appimage')
18options=('!debug')
19install=paseo.install
20source=(
21 "${pkgname}-${pkgver}.tar.gz::${_github_url}/archive/refs/tags/v${pkgver}.tar.gz"
22 'paseo.sh'
23 'paseo.desktop'
24 'paseo.service'
25 'paseo-daemon-session.sh'
26 'trace-desktop.mjs'
27 'system-electron-paths.patch'
28)
29sha256sums=('07023ced1de45a32db63a50b8989e86217c09750d5fe7cacba20ca80dfec1d8a'
30 'f9e194a879a87d87021ad06f489a9e4197ded629055a38e2da3557a423785de4'
31 '8219842d8f7bb20e0608450f2574fa37d98e37ef410de459e0792651a78c1b47'
32 'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'
33 '620279e619a4f42dcfb45991d679bc82e891d69cabc77a9512b77a47f4df59c2'
34 '9ed8aeb2692ae8c51e9fb72f9b099e09358159bec5f7d3bdae1fbdf5940382f2'
35 '4111231339f8fcad31ec5fc139f9292c26182785838f22076d4c05f8c8463579')
36
37# Repo-relative path of the installed node-pty. npm hoists it to the root
38# node_modules in some releases and nests it under packages/server in others
39# (0.3.1 nests it), so resolve it instead of hardcoding either location.
40_node_pty_dir() {
41 node -p "const p=require('node:path');p.relative(process.cwd(),p.dirname(require.resolve('node-pty/package.json',{paths:['packages/server']})))"
42}
43
44prepare() {
45 cd "${pkgname}-${pkgver}"
46
47 # Refuse to build against the wrong Electron major: the app would compile
48 # fine but hit runtime API drift. Bump _electron_pkg= (and pkgrel) when
49 # upstream moves on.
50 local _upstream_electron
51 _upstream_electron="$(node -p "require('./packages/desktop/package.json').devDependencies.electron.match(/\d+/)[0]")"
52 if [[ "electron${_upstream_electron}" != "${_electron_pkg}" ]]; then
53 printf 'ERROR: upstream now pins electron %s but this package uses %s; update _electron_pkg= in the PKGBUILD\n' \
54 "${_upstream_electron}" "${_electron_pkg}" >&2
55 return 1
56 fi
57
58 # Arch's system electron reports app.isPackaged=true, so the app takes
59 # its packaged code paths; point the electron-builder resource lookups
60 # (process.resourcesPath / app.asar*) at /usr/lib/paseo instead, and
61 # leave updates to pacman rather than electron-updater.
62 #
63 # The patch used to carry a sixth hunk redirecting getBundledSkillsDir()
64 # in packages/desktop/src/integrations/skills/paths.ts. 0.5.1 deleted that
65 # file: skills resolution moved to packages/server's
66 # orchestration-skills/internal/paths.ts, which resolves relative to its
67 # own compiled location and takes the first candidate that exists instead
68 # of reading process.resourcesPath. Its first candidate lands on
69 # packages/server/dist/server/skills, which the trace already installs
70 # (byte-identical to the top-level skills/ that package() checks for), so
71 # nothing needs redirecting and the hunk was dropped rather than ported.
72 #
73 # A hunk for features/editor-targets/runtime.ts was added instead:
74 # iconPath() reads the editor-target icons from process.resourcesPath, and
75 # listEditorTargets() awaits describe() -> loadIcon() for every installed
76 # editor with no try/catch anywhere in the chain. Under system Electron
77 # that path resolves into electron*/resources, so the read threw ENOENT and
78 # the whole editor-target list failed for anyone with a supported editor
79 # installed — not just a missing icon. Point it at the assets we ship.
80 #
81 # 0.11.0 folded getBundledCliShimPath()'s per-platform branches into
82 # resolveCliShimPath() (cli-install/path.ts), which for packaged Linux
83 # still resolves <dir of exe>/resources/bin/paseo — i.e. inside the system
84 # electron* tree. The cli-install/paths.ts hunk now short-circuits Linux to
85 # /usr/bin/paseo before that call, same intent as before.
86 patch -Np1 -i "${srcdir}/system-electron-paths.patch"
87
88 # Keep npm state inside $srcdir; skip lifecycle scripts (no electron /
89 # onnxruntime binary downloads — mirrors upstream nix/desktop-package.nix).
90 export npm_config_cache="${srcdir}/npm-cache"
91 export npm_config_update_notifier=false
92 # Survive transient registry ECONNRESETs (npm defaults to only 2 retries).
93 export npm_config_fetch_retries=5
94 export npm_config_fetch_retry_mintimeout=20000
95 export npm_config_fetch_retry_maxtimeout=120000
96 npm ci --ignore-scripts --no-audit --no-fund
97
98 # Root postinstall applies patches/ via patch-package.
99 npm run postinstall
100}
101
102build() {
103 cd "${pkgname}-${pkgver}"
104
105 export npm_config_cache="${srcdir}/npm-cache"
106 export npm_config_update_notifier=false
107 # build() still hits the network (node-gyp headers, expo); same retry bump.
108 export npm_config_fetch_retries=5
109 export npm_config_fetch_retry_mintimeout=20000
110 export npm_config_fetch_retry_maxtimeout=120000
111 export EXPO_NO_TELEMETRY=1
112 export CI=1
113
114 # node-pty is the only native addon the daemon needs (N-API, so it stays
115 # ABI-compatible with the Electron runtime). Compiled directly with
116 # node-gyp: `npm rebuild` is skipped by npm 11's allowScripts gate and by
117 # the npm-shipped prebuild.
118 (cd "$(_node_pty_dir)" && npx node-gyp rebuild)
119
120 # Mirrors upstream nix/desktop-package.nix — tsc workspaces, Expo web
121 # export for the renderer, then the desktop main process. No
122 # electron-builder involved.
123 npm run build:server
124 # Daemon Web UI (browser build, precompressed) into
125 # packages/server/dist/server/web-ui, as upstream's nix/package.nix does.
126 # Official desktop builds serve resources/app-dist instead; under system
127 # Electron that path points into electron*/resources, so the daemon falls
128 # back to web-ui and returned 404 without this. Runs before the Electron
129 # renderer export below, since both write packages/app/dist.
130 npm run build:daemon-web-ui
131 npm run build --workspace=@getpaseo/expo-two-way-audio
132 (cd packages/app && PASEO_WEB_PLATFORM=electron npx expo export --platform web)
133 npm run build:main --workspace=@getpaseo/desktop
134}
135
136package() {
137 cd "${pkgname}-${pkgver}"
138
139 # Runtime closure by static module-graph tracing: upstream's daemon/CLI
140 # trace (PASEO_TRACE_DESKTOP=1 also pulls in the Electron main process and
141 # its preloads) plus our supplement, instead of the 2 GB node_modules.
142 PASEO_TRACE_DESKTOP=1 node scripts/trace-daemon.mjs > "${srcdir}/runtime-files.txt" \
143 2> "${srcdir}/trace-stderr.log" \
144 || { cat "${srcdir}/trace-stderr.log" >&2; return 1; }
145 node "${srcdir}/trace-desktop.mjs" >> "${srcdir}/runtime-files.txt" \
146 2>> "${srcdir}/trace-stderr.log" \
147 || { cat "${srcdir}/trace-stderr.log" >&2; return 1; }
148
149 # Known-benign trace noise is dropped; anything unexpected still prints.
150 # ws/node-fetch probe optional native accelerators (bufferutil,
151 # utf-8-validate, encoding) that the lockfile never installs — pure-JS
152 # fallbacks are used. nft also tries to parse non-JS assets it carries
153 # (a stray src/*.ts, zsh shell-integration dotfiles) and logs the
154 # resulting token errors.
155 grep -vE "utf-8-validate|bufferutil|[\"']encoding[\"']|Failed to parse .*(packages/server/src/|shell-integration)|^Unexpected token" \
156 "${srcdir}/trace-stderr.log" >&2 || true
157
158 local _libdir="${pkgdir}/usr/lib/paseo"
159 install -d "${_libdir}"
160
161 # Root manifest lets node resolve the workspace layout at runtime.
162 cp package.json "${_libdir}/"
163
164 # Copy file-by-file, preserving workspace symlinks
165 # (node_modules/@getpaseo/* -> packages/*). Directory entries are skipped:
166 # their contents are listed individually, and copying a directory onto a
167 # path that already exists would nest instead of merge.
168 # node-pty's npm-shipped prebuilds are dropped: its loader prefers the
169 # build/Release addon we compile ourselves (lib/utils.js search order).
170 sort -u "${srcdir}/runtime-files.txt" | grep -v 'node_modules/node-pty/prebuilds/' | \
171 while IFS= read -r f; do
172 if [ ! -e "$f" ] && [ ! -L "$f" ]; then
173 continue
174 fi
175 if [ -d "$f" ] && [ ! -L "$f" ]; then
176 continue
177 fi
178 install -d "${_libdir}/$(dirname "$f")"
179 cp -a "$f" "${_libdir}/$f"
180 done
181
182 # Under `electron <dir>` (default_app), Electron derives the Wayland app_id
183 # from the loaded package.json "name" *before* main.js runs, so the in-app
184 # app.setName("Paseo") is too late and the window reports "getpaseo-desktop"
185 # (sanitised @getpaseo/desktop) — GNOME then can't match it to paseo.desktop
186 # and shows no icon. Rename the installed manifest so the app_id is "Paseo",
187 # matching StartupWMClass= (and paseo-bin). Runtime module resolution is
188 # path-based via the node_modules/@getpaseo/* symlinks, so the name field is
189 # never read at runtime; npm tooling that does isn't present post-install.
190 local _desktop_manifest="${_libdir}/packages/desktop/package.json"
191 sed -i 's#"name": "@getpaseo/desktop"#"name": "Paseo"#' "${_desktop_manifest}"
192 if grep -q '"name": "@getpaseo/desktop"' "${_desktop_manifest}"; then
193 printf 'ERROR: failed to rewrite desktop package.json name for the Wayland app_id\n' >&2
194 return 1
195 fi
196
197 # Launcher tracks _electron_pkg so an Electron bump is a one-line change.
198 install -d "${pkgdir}/usr/bin"
199 sed "s/@ELECTRON@/${_electron_pkg}/g" "${srcdir}/paseo.sh" > "${pkgdir}/usr/bin/paseo"
200 chmod 755 "${pkgdir}/usr/bin/paseo"
201
202 install -Dm644 "${srcdir}/paseo.desktop" \
203 "${pkgdir}/usr/share/applications/paseo.desktop"
204
205 # Session-scoped daemon launcher (node CLI entry, full login-shell env) and
206 # the static user unit that runs it. Started via XDG autostart, not enabled
207 # — see paseo.install.
208 install -Dm755 "${srcdir}/paseo-daemon-session.sh" \
209 "${pkgdir}/usr/bin/paseo-daemon-session"
210
211 install -Dm644 "${srcdir}/paseo.service" \
212 "${pkgdir}/usr/lib/systemd/user/paseo.service"
213
214 install -Dm644 packages/app/dist/pwa-icon-192.png \
215 "${pkgdir}/usr/share/icons/hicolor/192x192/apps/paseo.png"
216 install -Dm644 packages/app/dist/pwa-icon-512.png \
217 "${pkgdir}/usr/share/icons/hicolor/512x512/apps/paseo.png"
218
219 install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
220
221 # Guard against trace regressions: every path here is load-bearing for
222 # the CLI, the daemon spawn chain, or the renderer. A miss fails the
223 # build instead of surfacing as a runtime error after install.
224 local _required=(
225 usr/bin/paseo
226 usr/bin/paseo-daemon-session
227 usr/lib/paseo/package.json
228 usr/lib/paseo/packages/cli/bin/paseo
229 usr/lib/paseo/packages/desktop/dist/main.js
230 usr/lib/paseo/packages/desktop/dist/preload.js
231 usr/lib/paseo/packages/desktop/dist/features/browser-keyboard/guest-preload.js
232 usr/lib/paseo/packages/desktop/dist/daemon/node-entrypoint-runner.js
233 usr/lib/paseo/packages/desktop/package.json
234 usr/lib/paseo/packages/cli/dist/index.js
235 usr/lib/paseo/packages/cli/dist/run.js
236 usr/lib/paseo/packages/server/dist/scripts/supervisor-entrypoint.js
237 usr/lib/paseo/packages/server/dist/server/server/exports.js
238 usr/lib/paseo/node_modules/@getpaseo/cli
239 usr/lib/paseo/node_modules/@getpaseo/server
240 "usr/lib/paseo/$(_node_pty_dir)/build/Release/pty.node"
241 usr/lib/paseo/packages/app/dist/index.html
242 usr/lib/paseo/skills
243 # 0.11.0 built-in plugins, compiled by the daemon at runtime (esbuild)
244 # and resolved relative to the server dist, not through the module
245 # graph.
246 usr/lib/paseo/packages/server/dist/server/builtin-plugins/claude-usage-source/paseo-plugin.json
247 # Daemon Web UI, served from disk rather than through the module graph.
248 usr/lib/paseo/packages/server/dist/server/web-ui/index.html
249 # Hardcoded by system-electron-paths.patch: the window icon and the
250 # editor-target icons. Upstream reads both out of process.resourcesPath,
251 # which under system Electron points into electron*/resources instead of
252 # here, so the patch redirects them and these must ship.
253 usr/lib/paseo/packages/desktop/assets/icon.png
254 usr/lib/paseo/packages/desktop/assets/editor-targets/vscode.png
255 )
256 local _f
257 for _f in "${_required[@]}"; do
258 if [[ ! -e "${pkgdir}/${_f}" ]]; then
259 printf 'ERROR: runtime closure check failed: missing %s\n' "${_f}" >&2
260 return 1
261 fi
262 done
263}
264

Changes since previous scan

--- PKGBUILD @ 2026-10-30 00:29
+++ PKGBUILD @ 2026-11-01 00:21
@@ -1,7 +1,7 @@
# Maintainer: jinzhongjia <mail@nvimer.org>
pkgname=paseo
-pkgver=0.13.0
+pkgver=0.13.2
pkgrel=1
pkgdesc="One interface for all your Claude Code, Codex and OpenCode agents (built from source, runs on system Electron)"
arch=('x86_64')
@@ -26,7 +26,7 @@
'trace-desktop.mjs'
'system-electron-paths.patch'
)
-sha256sums=('a7d9b61ecc94316a125f36539a58fe230dfc336722aaed8e86b89505d594019f'
+sha256sums=('07023ced1de45a32db63a50b8989e86217c09750d5fe7cacba20ca80dfec1d8a'
'f9e194a879a87d87021ad06f489a9e4197ded629055a38e2da3557a423785de4'
'8219842d8f7bb20e0608450f2574fa37d98e37ef410de459e0792651a78c1b47'
'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'

Scan history

Scanned at (UTC)SeverityRules
2026-11-01 00:21:48 Low 2
2026-10-31 00:07:41 Low 2
2026-10-30 05:55:14 Medium 1
2026-10-30 00:29:30 Low 2
2026-10-29 00:13:55 Low 2
2026-10-28 00:06:54 Low 2
2026-10-27 05:46:44 Medium 1
2026-10-27 00:23:28 Low 2
2026-10-26 05:43:49 Medium 1
2026-10-26 00:12:40 Low 2
2026-10-25 00:20:48 Low 2
2026-10-24 00:14:55 Low 2
2026-10-23 00:02:19 Low 2
2026-10-22 00:13:10 Low 2
2026-10-21 00:12:50 Low 2
2026-10-20 17:28:05 Medium 1
2026-10-20 00:10:31 Low 2
2026-10-19 07:24:05 Medium 1
2026-10-19 00:03:55 Low 2
2026-10-18 00:06:55 Low 2

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion