paseo

maintainer jinzhongjia · 1 votes · scanned 2026-08-03 00:08:14.047287
LOW
View on AUR ↗
Why flagged The npx usage in build() is for running node-gyp rebuild and Expo export within the project's own build process, which is a legitimate and common practice when building from source; the commands are not executing arbitrary remote code but are part of the project's declared toolchain.

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 90%): The npx usage in build() is for running node-gyp rebuild and Expo export within the project's own build process, which is a legitimate and common practice when building from source; the commands are not executing arbitrary remote code but are part of the project's declared toolchain.

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:87 (cd node_modules/node-pty && npx node-gyp rebuild)
  • PKGBUILD:94 (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.2.5
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=electron41
13license=('AGPL-3.0-or-later')
14depends=("${_electron_pkg}" 'gcc-libs' 'glibc' 'hicolor-icon-theme')
15makedepends=('nodejs' '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=('71edd6c0df146b60fcce27557ba9ae1db1c0dff6b5275055e3d4598e7c9f5af3'
30 '5f744a24a3605f78ee30348e1d705f47d803f915e58e076ea6e11f151d678407'
31 '6ae9c520668f639a22f17df7814548056ee46aa99a2886639405297a7b1ef212'
32 'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'
33 '0bd531415e7504c4bbff0ce137a5541a4ba7d0c29281139b29d94ee537fde307'
34 '6be3fbd2634a77faa21fed02abe3d486680cdb880db97f5c1a9fe948a99e1865'
35 '437a8ef0ad31411c6c96dc361718d6de32bb286cc1e0ed1d25c932080290c7d6')
36
37prepare() {
38 cd "${pkgname}-${pkgver}"
39
40 # Refuse to build against the wrong Electron major: the app would compile
41 # fine but hit runtime API drift. Bump _electron_pkg= (and pkgrel) when
42 # upstream moves on.
43 local _upstream_electron
44 _upstream_electron="$(node -p "require('./packages/desktop/package.json').devDependencies.electron.match(/\d+/)[0]")"
45 if [[ "electron${_upstream_electron}" != "${_electron_pkg}" ]]; then
46 printf 'ERROR: upstream now pins electron %s but this package uses %s; update _electron_pkg= in the PKGBUILD\n' \
47 "${_upstream_electron}" "${_electron_pkg}" >&2
48 return 1
49 fi
50
51 # Arch's system electron reports app.isPackaged=true, so the app takes
52 # its packaged code paths; point the electron-builder resource lookups
53 # (process.resourcesPath / app.asar*) at /usr/lib/paseo instead, and
54 # leave updates to pacman rather than electron-updater.
55 patch -Np1 -i "${srcdir}/system-electron-paths.patch"
56
57 # Keep npm state inside $srcdir; skip lifecycle scripts (no electron /
58 # onnxruntime binary downloads — mirrors upstream nix/desktop-package.nix).
59 export npm_config_cache="${srcdir}/npm-cache"
60 export npm_config_update_notifier=false
61 # Survive transient registry ECONNRESETs (npm defaults to only 2 retries).
62 export npm_config_fetch_retries=5
63 export npm_config_fetch_retry_mintimeout=20000
64 export npm_config_fetch_retry_maxtimeout=120000
65 npm ci --ignore-scripts --no-audit --no-fund
66
67 # Root postinstall applies patches/ via patch-package.
68 npm run postinstall
69}
70
71build() {
72 cd "${pkgname}-${pkgver}"
73
74 export npm_config_cache="${srcdir}/npm-cache"
75 export npm_config_update_notifier=false
76 # build() still hits the network (node-gyp headers, expo); same retry bump.
77 export npm_config_fetch_retries=5
78 export npm_config_fetch_retry_mintimeout=20000
79 export npm_config_fetch_retry_maxtimeout=120000
80 export EXPO_NO_TELEMETRY=1
81 export CI=1
82
83 # node-pty is the only native addon the daemon needs (N-API, so it stays
84 # ABI-compatible with the Electron runtime). Compiled directly with
85 # node-gyp: `npm rebuild` is skipped by npm 11's allowScripts gate and by
86 # the npm-shipped prebuild.
87 (cd node_modules/node-pty && npx node-gyp rebuild)
88
89 # Mirrors upstream nix/desktop-package.nix — tsc workspaces, Expo web
90 # export for the renderer, then the desktop main process. No
91 # electron-builder involved.
92 npm run build:server
93 npm run build --workspace=@getpaseo/expo-two-way-audio
94 (cd packages/app && PASEO_WEB_PLATFORM=electron npx expo export --platform web)
95 npm run build:main --workspace=@getpaseo/desktop
96}
97
98package() {
99 cd "${pkgname}-${pkgver}"
100
101 # Runtime closure by static module-graph tracing: upstream's daemon/CLI
102 # trace plus our desktop-main trace, instead of the 2 GB node_modules.
103 node scripts/trace-daemon.mjs > "${srcdir}/runtime-files.txt" \
104 2> "${srcdir}/trace-stderr.log" \
105 || { cat "${srcdir}/trace-stderr.log" >&2; return 1; }
106 node "${srcdir}/trace-desktop.mjs" >> "${srcdir}/runtime-files.txt" \
107 2>> "${srcdir}/trace-stderr.log" \
108 || { cat "${srcdir}/trace-stderr.log" >&2; return 1; }
109
110 # Known-benign trace noise is dropped; anything unexpected still prints.
111 # ws/node-fetch probe optional native accelerators (bufferutil,
112 # utf-8-validate, encoding) that the lockfile never installs — pure-JS
113 # fallbacks are used. nft also tries to parse non-JS assets it carries
114 # (a stray src/*.ts, zsh shell-integration dotfiles) and logs the
115 # resulting token errors.
116 grep -vE "utf-8-validate|bufferutil|[\"']encoding[\"']|Failed to parse .*(packages/server/src/|shell-integration)|^Unexpected token" \
117 "${srcdir}/trace-stderr.log" >&2 || true
118
119 local _libdir="${pkgdir}/usr/lib/paseo"
120 install -d "${_libdir}"
121
122 # Root manifest lets node resolve the workspace layout at runtime.
123 cp package.json "${_libdir}/"
124
125 # Copy file-by-file, preserving workspace symlinks
126 # (node_modules/@getpaseo/* -> packages/*). Directory entries are skipped:
127 # their contents are listed individually, and copying a directory onto a
128 # path that already exists would nest instead of merge.
129 # node-pty's npm-shipped prebuilds are dropped: its loader prefers the
130 # build/Release addon we compile ourselves (lib/utils.js search order).
131 sort -u "${srcdir}/runtime-files.txt" | grep -v '^node_modules/node-pty/prebuilds/' | \
132 while IFS= read -r f; do
133 if [ ! -e "$f" ] && [ ! -L "$f" ]; then
134 continue
135 fi
136 if [ -d "$f" ] && [ ! -L "$f" ]; then
137 continue
138 fi
139 install -d "${_libdir}/$(dirname "$f")"
140 cp -a "$f" "${_libdir}/$f"
141 done
142
143 # Under `electron <dir>` (default_app), Electron derives the Wayland app_id
144 # from the loaded package.json "name" *before* main.js runs, so the in-app
145 # app.setName("Paseo") is too late and the window reports "getpaseo-desktop"
146 # (sanitised @getpaseo/desktop) — GNOME then can't match it to paseo.desktop
147 # and shows no icon. Rename the installed manifest so the app_id is "Paseo",
148 # matching StartupWMClass= (and paseo-bin). Runtime module resolution is
149 # path-based via the node_modules/@getpaseo/* symlinks, so the name field is
150 # never read at runtime; npm tooling that does isn't present post-install.
151 local _desktop_manifest="${_libdir}/packages/desktop/package.json"
152 sed -i 's#"name": "@getpaseo/desktop"#"name": "Paseo"#' "${_desktop_manifest}"
153 if grep -q '"name": "@getpaseo/desktop"' "${_desktop_manifest}"; then
154 printf 'ERROR: failed to rewrite desktop package.json name for the Wayland app_id\n' >&2
155 return 1
156 fi
157
158 # Launcher tracks _electron_pkg so an Electron bump is a one-line change.
159 install -d "${pkgdir}/usr/bin"
160 sed "s/electron41/${_electron_pkg}/g" "${srcdir}/paseo.sh" > "${pkgdir}/usr/bin/paseo"
161 chmod 755 "${pkgdir}/usr/bin/paseo"
162
163 install -Dm644 "${srcdir}/paseo.desktop" \
164 "${pkgdir}/usr/share/applications/paseo.desktop"
165
166 # Session-scoped daemon launcher (node CLI entry, full login-shell env) and
167 # the static user unit that runs it. Started via XDG autostart, not enabled
168 # — see paseo.install.
169 install -Dm755 "${srcdir}/paseo-daemon-session.sh" \
170 "${pkgdir}/usr/bin/paseo-daemon-session"
171
172 install -Dm644 "${srcdir}/paseo.service" \
173 "${pkgdir}/usr/lib/systemd/user/paseo.service"
174
175 install -Dm644 packages/app/dist/pwa-icon-192.png \
176 "${pkgdir}/usr/share/icons/hicolor/192x192/apps/paseo.png"
177 install -Dm644 packages/app/dist/pwa-icon-512.png \
178 "${pkgdir}/usr/share/icons/hicolor/512x512/apps/paseo.png"
179
180 install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
181
182 # Guard against trace regressions: every path here is load-bearing for
183 # the CLI, the daemon spawn chain, or the renderer. A miss fails the
184 # build instead of surfacing as a runtime error after install.
185 local _required=(
186 usr/bin/paseo
187 usr/bin/paseo-daemon-session
188 usr/lib/paseo/package.json
189 usr/lib/paseo/packages/cli/bin/paseo
190 usr/lib/paseo/packages/desktop/dist/main.js
191 usr/lib/paseo/packages/desktop/dist/preload.js
192 usr/lib/paseo/packages/desktop/dist/daemon/node-entrypoint-runner.js
193 usr/lib/paseo/packages/desktop/package.json
194 usr/lib/paseo/packages/cli/dist/index.js
195 usr/lib/paseo/packages/cli/dist/run.js
196 usr/lib/paseo/packages/server/dist/scripts/supervisor-entrypoint.js
197 usr/lib/paseo/node_modules/@getpaseo/cli
198 usr/lib/paseo/node_modules/@getpaseo/server
199 usr/lib/paseo/node_modules/node-pty/build/Release/pty.node
200 usr/lib/paseo/packages/app/dist/index.html
201 usr/lib/paseo/skills
202 )
203 local _f
204 for _f in "${_required[@]}"; do
205 if [[ ! -e "${pkgdir}/${_f}" ]]; then
206 printf 'ERROR: runtime closure check failed: missing %s\n' "${_f}" >&2
207 return 1
208 fi
209 done
210}
211

Changes since previous scan

--- PKGBUILD @ 2026-07-31 00:14
+++ PKGBUILD @ 2026-08-03 00:08
@@ -1,7 +1,7 @@
# Maintainer: jinzhongjia <mail@nvimer.org>
pkgname=paseo
-pkgver=0.2.4
+pkgver=0.2.5
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=('ae3b69ea138f28455a69da45f567bf1442f792f8e85fda48cbbfef40b5039bb9'
+sha256sums=('71edd6c0df146b60fcce27557ba9ae1db1c0dff6b5275055e3d4598e7c9f5af3'
'5f744a24a3605f78ee30348e1d705f47d803f915e58e076ea6e11f151d678407'
'6ae9c520668f639a22f17df7814548056ee46aa99a2886639405297a7b1ef212'
'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'

Scan history

Scanned at (UTC)SeverityRules
2026-08-03 00:08:14 LOW 2
2026-08-02 00:16:08 LOW 2
2026-08-01 00:11:18 LOW 2
2026-07-31 03:17:12 MEDIUM 1
2026-07-31 00:14:10 LOW 2
2026-07-30 07:14:03 MEDIUM 1
2026-07-30 00:17:23 LOW 2
2026-07-29 00:25:53 LOW 2
2026-07-28 15:39:03 MEDIUM 1
2026-07-28 00:07:28 LOW 2
2026-07-27 00:24:32 LOW 2
2026-07-26 13:32:26 MEDIUM 1
2026-07-26 00:07:32 LOW 2
2026-07-25 05:29:17 MEDIUM 1
2026-07-25 03:28:44 MEDIUM 1
2026-07-25 00:13:44 LOW 2
2026-07-24 00:02:28 LOW 2
2026-07-23 00:14:47 LOW 2
2026-07-22 00:29:32 LOW 2
2026-07-21 00:24:15 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