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
3
pkgname=paseo
4
pkgver=0.2.5
5
pkgrel=1
6
pkgdesc="One interface for all your Claude Code, Codex and OpenCode agents (built from source, runs on system Electron)"
7
arch=('x86_64')
8
url="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
13
license=('AGPL-3.0-or-later')
14
depends=("${_electron_pkg}" 'gcc-libs' 'glibc' 'hicolor-icon-theme')
15
makedepends=('nodejs' 'npm' 'python' 'git')
16
optdepends=('git: agent worktree management')
17
conflicts=('paseo-bin' 'paseo-desktop-bin' 'paseo-appimage')
18
options=('!debug')
19
install=paseo.install
20
source=(
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
)
29
sha256sums=('71edd6c0df146b60fcce27557ba9ae1db1c0dff6b5275055e3d4598e7c9f5af3'
30
'5f744a24a3605f78ee30348e1d705f47d803f915e58e076ea6e11f151d678407'
31
'6ae9c520668f639a22f17df7814548056ee46aa99a2886639405297a7b1ef212'
32
'df0d01b98ac405c5c25edbb91d61bb9e05355a57e0e652e00823d6331618d686'
33
'0bd531415e7504c4bbff0ce137a5541a4ba7d0c29281139b29d94ee537fde307'
34
'6be3fbd2634a77faa21fed02abe3d486680cdb880db97f5c1a9fe948a99e1865'
35
'437a8ef0ad31411c6c96dc361718d6de32bb286cc1e0ed1d25c932080290c7d6')
36
37
prepare() {
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
71
build() {
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
98
package() {
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) | Severity | Rules |
|---|---|---|
| 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 |