paseo

LOW
maintainer jinzhongjia 1 votes scanned 2026-09-17 00:27:14.276658
View on AUR
Why flagged

The npx usage in build() is for rebuilding a local native addon (node-pty) from the project's own source, not executing arbitrary remote code; the package builds from a verifiable upstream source tarball and does not run untrusted remote payloads.

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() is for rebuilding a local native addon (node-pty) from the project's own source, not executing arbitrary remote code; the package builds from a verifiable upstream source tarball and does not run untrusted remote payloads.

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:112 (cd "$(_node_pty_dir)" && npx node-gyp rebuild)
  • PKGBUILD:119 (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.8.0
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=('8b57de8635834de7fc2de15cdc49df9387f438a6ccff14c358150ef5995feb3d'
30 'f9e194a879a87d87021ad06f489a9e4197ded629055a38e2da3557a423785de4'
31 '6ae9c520668f639a22f17df7814548056ee46aa99a2886639405297a7b1ef212'
32 'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'
33 '0bd531415e7504c4bbff0ce137a5541a4ba7d0c29281139b29d94ee537fde307'
34 '9c76df40b274123e128228dc841f44f018e4ffd8473a97f0a6b7a9c8a4c2e4fa'
35 'a30964e6b5767a12af0ccaa1a67b325a54990ebd386fef8a8326847cc54b955d')
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 patch -Np1 -i "${srcdir}/system-electron-paths.patch"
81
82 # Keep npm state inside $srcdir; skip lifecycle scripts (no electron /
83 # onnxruntime binary downloads — mirrors upstream nix/desktop-package.nix).
84 export npm_config_cache="${srcdir}/npm-cache"
85 export npm_config_update_notifier=false
86 # Survive transient registry ECONNRESETs (npm defaults to only 2 retries).
87 export npm_config_fetch_retries=5
88 export npm_config_fetch_retry_mintimeout=20000
89 export npm_config_fetch_retry_maxtimeout=120000
90 npm ci --ignore-scripts --no-audit --no-fund
91
92 # Root postinstall applies patches/ via patch-package.
93 npm run postinstall
94}
95
96build() {
97 cd "${pkgname}-${pkgver}"
98
99 export npm_config_cache="${srcdir}/npm-cache"
100 export npm_config_update_notifier=false
101 # build() still hits the network (node-gyp headers, expo); same retry bump.
102 export npm_config_fetch_retries=5
103 export npm_config_fetch_retry_mintimeout=20000
104 export npm_config_fetch_retry_maxtimeout=120000
105 export EXPO_NO_TELEMETRY=1
106 export CI=1
107
108 # node-pty is the only native addon the daemon needs (N-API, so it stays
109 # ABI-compatible with the Electron runtime). Compiled directly with
110 # node-gyp: `npm rebuild` is skipped by npm 11's allowScripts gate and by
111 # the npm-shipped prebuild.
112 (cd "$(_node_pty_dir)" && npx node-gyp rebuild)
113
114 # Mirrors upstream nix/desktop-package.nix — tsc workspaces, Expo web
115 # export for the renderer, then the desktop main process. No
116 # electron-builder involved.
117 npm run build:server
118 npm run build --workspace=@getpaseo/expo-two-way-audio
119 (cd packages/app && PASEO_WEB_PLATFORM=electron npx expo export --platform web)
120 npm run build:main --workspace=@getpaseo/desktop
121}
122
123package() {
124 cd "${pkgname}-${pkgver}"
125
126 # Runtime closure by static module-graph tracing: upstream's daemon/CLI
127 # trace (PASEO_TRACE_DESKTOP=1 also pulls in the Electron main process and
128 # its preloads) plus our supplement, instead of the 2 GB node_modules.
129 PASEO_TRACE_DESKTOP=1 node scripts/trace-daemon.mjs > "${srcdir}/runtime-files.txt" \
130 2> "${srcdir}/trace-stderr.log" \
131 || { cat "${srcdir}/trace-stderr.log" >&2; return 1; }
132 node "${srcdir}/trace-desktop.mjs" >> "${srcdir}/runtime-files.txt" \
133 2>> "${srcdir}/trace-stderr.log" \
134 || { cat "${srcdir}/trace-stderr.log" >&2; return 1; }
135
136 # Known-benign trace noise is dropped; anything unexpected still prints.
137 # ws/node-fetch probe optional native accelerators (bufferutil,
138 # utf-8-validate, encoding) that the lockfile never installs — pure-JS
139 # fallbacks are used. nft also tries to parse non-JS assets it carries
140 # (a stray src/*.ts, zsh shell-integration dotfiles) and logs the
141 # resulting token errors.
142 grep -vE "utf-8-validate|bufferutil|[\"']encoding[\"']|Failed to parse .*(packages/server/src/|shell-integration)|^Unexpected token" \
143 "${srcdir}/trace-stderr.log" >&2 || true
144
145 local _libdir="${pkgdir}/usr/lib/paseo"
146 install -d "${_libdir}"
147
148 # Root manifest lets node resolve the workspace layout at runtime.
149 cp package.json "${_libdir}/"
150
151 # Copy file-by-file, preserving workspace symlinks
152 # (node_modules/@getpaseo/* -> packages/*). Directory entries are skipped:
153 # their contents are listed individually, and copying a directory onto a
154 # path that already exists would nest instead of merge.
155 # node-pty's npm-shipped prebuilds are dropped: its loader prefers the
156 # build/Release addon we compile ourselves (lib/utils.js search order).
157 sort -u "${srcdir}/runtime-files.txt" | grep -v 'node_modules/node-pty/prebuilds/' | \
158 while IFS= read -r f; do
159 if [ ! -e "$f" ] && [ ! -L "$f" ]; then
160 continue
161 fi
162 if [ -d "$f" ] && [ ! -L "$f" ]; then
163 continue
164 fi
165 install -d "${_libdir}/$(dirname "$f")"
166 cp -a "$f" "${_libdir}/$f"
167 done
168
169 # Under `electron <dir>` (default_app), Electron derives the Wayland app_id
170 # from the loaded package.json "name" *before* main.js runs, so the in-app
171 # app.setName("Paseo") is too late and the window reports "getpaseo-desktop"
172 # (sanitised @getpaseo/desktop) — GNOME then can't match it to paseo.desktop
173 # and shows no icon. Rename the installed manifest so the app_id is "Paseo",
174 # matching StartupWMClass= (and paseo-bin). Runtime module resolution is
175 # path-based via the node_modules/@getpaseo/* symlinks, so the name field is
176 # never read at runtime; npm tooling that does isn't present post-install.
177 local _desktop_manifest="${_libdir}/packages/desktop/package.json"
178 sed -i 's#"name": "@getpaseo/desktop"#"name": "Paseo"#' "${_desktop_manifest}"
179 if grep -q '"name": "@getpaseo/desktop"' "${_desktop_manifest}"; then
180 printf 'ERROR: failed to rewrite desktop package.json name for the Wayland app_id\n' >&2
181 return 1
182 fi
183
184 # Launcher tracks _electron_pkg so an Electron bump is a one-line change.
185 install -d "${pkgdir}/usr/bin"
186 sed "s/@ELECTRON@/${_electron_pkg}/g" "${srcdir}/paseo.sh" > "${pkgdir}/usr/bin/paseo"
187 chmod 755 "${pkgdir}/usr/bin/paseo"
188
189 install -Dm644 "${srcdir}/paseo.desktop" \
190 "${pkgdir}/usr/share/applications/paseo.desktop"
191
192 # Session-scoped daemon launcher (node CLI entry, full login-shell env) and
193 # the static user unit that runs it. Started via XDG autostart, not enabled
194 # — see paseo.install.
195 install -Dm755 "${srcdir}/paseo-daemon-session.sh" \
196 "${pkgdir}/usr/bin/paseo-daemon-session"
197
198 install -Dm644 "${srcdir}/paseo.service" \
199 "${pkgdir}/usr/lib/systemd/user/paseo.service"
200
201 install -Dm644 packages/app/dist/pwa-icon-192.png \
202 "${pkgdir}/usr/share/icons/hicolor/192x192/apps/paseo.png"
203 install -Dm644 packages/app/dist/pwa-icon-512.png \
204 "${pkgdir}/usr/share/icons/hicolor/512x512/apps/paseo.png"
205
206 install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
207
208 # Guard against trace regressions: every path here is load-bearing for
209 # the CLI, the daemon spawn chain, or the renderer. A miss fails the
210 # build instead of surfacing as a runtime error after install.
211 local _required=(
212 usr/bin/paseo
213 usr/bin/paseo-daemon-session
214 usr/lib/paseo/package.json
215 usr/lib/paseo/packages/cli/bin/paseo
216 usr/lib/paseo/packages/desktop/dist/main.js
217 usr/lib/paseo/packages/desktop/dist/preload.js
218 usr/lib/paseo/packages/desktop/dist/features/browser-keyboard/guest-preload.js
219 usr/lib/paseo/packages/desktop/dist/daemon/node-entrypoint-runner.js
220 usr/lib/paseo/packages/desktop/package.json
221 usr/lib/paseo/packages/cli/dist/index.js
222 usr/lib/paseo/packages/cli/dist/run.js
223 usr/lib/paseo/packages/server/dist/scripts/supervisor-entrypoint.js
224 usr/lib/paseo/node_modules/@getpaseo/cli
225 usr/lib/paseo/node_modules/@getpaseo/server
226 "usr/lib/paseo/$(_node_pty_dir)/build/Release/pty.node"
227 usr/lib/paseo/packages/app/dist/index.html
228 usr/lib/paseo/skills
229 # Hardcoded by system-electron-paths.patch: the window icon and the
230 # editor-target icons. Upstream reads both out of process.resourcesPath,
231 # which under system Electron points into electron*/resources instead of
232 # here, so the patch redirects them and these must ship.
233 usr/lib/paseo/packages/desktop/assets/icon.png
234 usr/lib/paseo/packages/desktop/assets/editor-targets/vscode.png
235 )
236 local _f
237 for _f in "${_required[@]}"; do
238 if [[ ! -e "${pkgdir}/${_f}" ]]; then
239 printf 'ERROR: runtime closure check failed: missing %s\n' "${_f}" >&2
240 return 1
241 fi
242 done
243}
244

Changes since previous scan

--- PKGBUILD @ 2026-09-12 00:25
+++ PKGBUILD @ 2026-09-17 00:27
@@ -1,7 +1,7 @@
# Maintainer: jinzhongjia <mail@nvimer.org>
pkgname=paseo
-pkgver=0.7.2
+pkgver=0.8.0
pkgrel=1
pkgdesc="One interface for all your Claude Code, Codex and OpenCode agents (built from source, runs on system Electron)"
arch=('x86_64')
@@ -9,10 +9,10 @@
_github_url="https://github.com/getpaseo/paseo"
# Keep in sync with packages/desktop/package.json devDependencies.electron —
# prepare() fails the build when the majors drift apart.
-_electron_pkg=electron41
-license=('AGPL-3.0-or-later')
-depends=("${_electron_pkg}" 'gcc-libs' 'glibc' 'hicolor-icon-theme')
-makedepends=('nodejs' 'npm' 'python' 'git')
+_electron_pkg=electron44
+license=('Apache-2.0')
+depends=("${_electron_pkg}" 'gcc-libs' 'glibc' 'hicolor-icon-theme' 'nodejs>=22')
+makedepends=('npm' 'python' 'git')
optdepends=('git: agent worktree management')
conflicts=('paseo-bin' 'paseo-desktop-bin' 'paseo-appimage')
options=('!debug')
@@ -26,13 +26,13 @@
'trace-desktop.mjs'
'system-electron-paths.patch'
)
-sha256sums=('8ff41592068771394cbcd9276d89ac7c1d8332f9f2660515dd62bd0d2130279f'
- '5f744a24a3605f78ee30348e1d705f47d803f915e58e076ea6e11f151d678407'
+sha256sums=('8b57de8635834de7fc2de15cdc49df9387f438a6ccff14c358150ef5995feb3d'
+ 'f9e194a879a87d87021ad06f489a9e4197ded629055a38e2da3557a423785de4'
'6ae9c520668f639a22f17df7814548056ee46aa99a2886639405297a7b1ef212'
'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'
'0bd531415e7504c4bbff0ce137a5541a4ba7d0c29281139b29d94ee537fde307'
'9c76df40b274123e128228dc841f44f018e4ffd8473a97f0a6b7a9c8a4c2e4fa'
- '94bd85443217eb476eeac64a35e2cd2ccd2c192643fe35ad12078b15f4768c06')
+ 'a30964e6b5767a12af0ccaa1a67b325a54990ebd386fef8a8326847cc54b955d')
# Repo-relative path of the installed node-pty. npm hoists it to the root
# node_modules in some releases and nests it under packages/server in others
@@ -183,7 +183,7 @@
# Launcher tracks _electron_pkg so an Electron bump is a one-line change.
install -d "${pkgdir}/usr/bin"
- sed "s/electron41/${_electron_pkg}/g" "${srcdir}/paseo.sh" > "${pkgdir}/usr/bin/paseo"
+ sed "s/@ELECTRON@/${_electron_pkg}/g" "${srcdir}/paseo.sh" > "${pkgdir}/usr/bin/paseo"
chmod 755 "${pkgdir}/usr/bin/paseo"
install -Dm644 "${srcdir}/paseo.desktop" \

Scan history

Scanned at (UTC)SeverityRules
2026-09-17 00:27:14 Low 2
2026-09-16 00:03:17 Low 2
2026-09-15 00:25:31 Low 2
2026-09-14 00:27:57 Low 2
2026-09-13 00:19:54 Low 2
2026-09-12 21:12:39 Medium 1
2026-09-12 00:25:17 Low 2
2026-09-11 00:19:22 Low 2
2026-09-10 00:22:44 Low 2
2026-09-09 00:04:09 Low 2
2026-09-08 00:18:08 Low 2
2026-09-07 00:30:15 Low 2
2026-09-06 00:17:06 Low 2
2026-09-05 00:16:27 Low 2
2026-09-04 00:03:13 Low 2
2026-09-03 03:52:21 Medium 1
2026-09-03 00:15:47 Low 2
2026-09-02 00:02:31 Low 2
2026-09-01 00:11:19 Low 2
2026-08-31 00:19:57 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