dsh-tui-git
LOW
maintainer HanHaocheng
0 votes
scanned 2026-10-31 05:57:59.662655
Why flagged
The package builds from a public git repository and creates an npm tarball at build time; the only risk is the lack of a checksum, but the source is transparent and the build process is reproducible.
Triggered rules
Low
Few votes, recently uploaded
zero_votes_recent
Uploaded within the last 14 days with 2 or fewer community votes — little peer review so far.
Low
AI review
llm_review
An AI model (qwen/qwen3-235b-a22b-2507) reviewed this and agrees it is LOW (confidence 90%): The package builds from a public git repository and creates an npm tarball at build time; the only risk is the lack of a checksum, but the source is transparent and the build process is reproducible.
PKGBUILD
1
# Maintainer: HanHaocheng <1849397656@qq.com>
2
#
3
# VCS package: tracks upstream main (https://github.com/ccch1mneyyy/dsh-TUI) and
4
# rebuilds the TUI from whatever is at HEAD at build time.
5
#
6
# This is the source counterpart of dsh-tui-bin (AUR, maintainer calmcrow), which
7
# npm-installs the published @deepseek-harness-tui/dsh-tui tarball and then lets
8
# the launcher's own `dsh-tui update` fill the user's dsh profile. Upstream
9
# develops on main and only tags every few releases: HEAD is currently 7 commits
10
# past v0.17.0 (1798 commits in total), including the DSH 0.2.1-rc.5 adapter
11
# changes that no published tarball contains yet. That is the reason this package
12
# exists. dsh-tui-bin and this package install the same /usr/bin names, provide
13
# the same capability and therefore conflict; only one of them may own the
14
# profile dependency.
15
#
16
# ─── Design: ship the release pipeline's tarball, not a /usr tree ────────────
17
#
18
# The payload is exactly what upstream publishes: `npm pack` of the compiled
19
# repository root, i.e. package.json "files" plus the eight bundledDependencies
20
# (@dsh-std/* and @dsh-tui-vendor/mathjax-tex-svg, built from the vendor/
21
# submodules). It is installed as
22
#
23
# /usr/share/dsh-tui/dsh-tui-<pkgver>-<pkgrel>.tgz
24
#
25
# and the .install hook adds it to the user's dsh profile as a *file:* plugin:
26
#
27
# dsh plugin --profile dsh-tui add file:/usr/share/dsh-tui/dsh-tui-....tgz
28
#
29
# The profile's own pnpm then installs that tarball under
30
# $DSH_HOME/profiles/dsh-tui/node_modules/@deepseek-harness-tui/dsh-tui exactly
31
# like an npm release, resolving its 30 runtime dependencies from the registry.
32
# Its 39 @deepseek-ai/* peerDependencies are not installed into the profile at
33
# all: when the app runs, dsh's own process-local module resolution maps those
34
# bare names onto the running harness installation (dsh 0.2.1-rc.4 ships 306 of
35
# them under /usr/lib/node_modules/@deepseek-ai/dsh/node_modules). That is why
36
# the tree must live *inside* the profile and must not be linked from /usr.
37
#
38
# The previous pkgrel shipped the compiled tree at /usr/lib/dsh-tui and linked
39
# the profile at it (`add link:/usr/lib/dsh-tui`). That cannot work: ESM
40
# resolution for /usr/lib/dsh-tui/lib/... walks /usr/lib/dsh-tui/node_modules,
41
# /usr/lib/node_modules, ... and none of them contains the @deepseek-ai/*
42
# packages, while the `link:` install had also pruned the profile's own copies.
43
# `dst` died with ERR_MODULE_NOT_FOUND on @deepseek-ai/dsh-session-persistence-jsonl
44
# (imported by lib/types/dsh-adapter/migrate/index.js). Corollary, and the rule
45
# this package now follows: the full application tree is never installed outside
46
# $DSH_HOME.
47
#
48
# /usr/lib/dsh-tui therefore only holds the launcher's *global (thin shell)*
49
# role: bin/dsh-tui.js + package.json. That copy is what /usr/bin/dst and
50
# /usr/bin/dsh-tui point at; it looks up the profile copy and delegates every
51
# invocation to it (`dst --version` prints `(profile)`), so the code that runs
52
# is always the packaged profile tree, never a /usr copy and never a registry
53
# release. The launcher is written for exactly this split (its bootstrap path is
54
# what `npm i -g` uses), so no file of it is patched.
55
#
56
# ─── Build-time network and disk ────────────────────────────────────────────
57
#
58
# The build is not sandboxed from the network, same as the release pipeline:
59
# * `git submodule update` fetches vendor/dsh-std from GitHub;
60
# * `pnpm install --frozen-lockfile` fetches the whole dev tree (the DSH
61
# 0.2.1-rc.x stack, TypeScript, tsdown, ...) -- roughly 1 GiB on a cold
62
# store. A warm pnpm store (pnpm_config_store_dir, override the variable to
63
# reuse one) turns the install into a hard-link pass of ~40 s.
64
# The resulting package is ~19 MB: the 18.6 MB npm tarball plus the launcher.
65
#
66
# ─── Install-time network (pacman hook) ─────────────────────────────────────
67
#
68
# The profile install is a pnpm install, so *installing this package* needs the
69
# network: pnpm resolves the tarball's dependencies from the configured
70
# registry. This is the same nature as dsh-tui-bin (npm install at install
71
# time). The hook is best effort by design: a failure (offline, proxy, broken
72
# unrelated profile dependency) never aborts the pacman transaction, it prints
73
# the exact command to rerun. A rerun of `pacman -S dsh-tui-git` or of that
74
# command is enough, the hook is idempotent.
75
#
76
# The tarball's file name carries pkgrel on purpose: the profile's dependency
77
# specifier is the file path, and pnpm only re-resolves a file: dependency when
78
# its specifier changes. Same pkgver with a new pkgrel (a rebuild) must still
79
# refresh the profile.
80
#
81
# ─── dsh compatibility gate: why the tarball and not the registry ────────────
82
#
83
# `dsh plugin add` refuses a plugin whose declared @deepseek-ai/* peer ranges do
84
# not include the running harness. For a registry spec dsh validates the
85
# *published* manifest: published 0.17.0 tops out at dsh 0.2.1-rc.3, so on
86
# 0.2.1-rc.4 it is refused with `incompatible-version` unless the user grants an
87
# exact-version exemption first. This package needs no exemption: the tarball is
88
# our compiled master manifest, which already lists 0.2.1-rc.2/rc.3/rc.4/rc.5
89
# (and 0.2.0-rc.x) -- the profile install passes the gate on its own. If a
90
# future dsh line is newer than the tree's ranges, the hook reports the refusal
91
# and offers the explicit `allow-version` (mode = accept-risk) escape hatch.
92
#
93
# ─── Build chain (mirrors .github/workflows/publish.yml) ────────────────────
94
# pnpm install --frozen-lockfile # root `prepare` already runs the compile
95
# pnpm compile # build-vendor -> clean -> tsc -> settings
96
# pnpm verify:package # upstream tarball gate (files/files list)
97
# node scripts/with-publish-manifest.mjs npm pack --ignore-scripts
98
# `pnpm verify:build` (the release job's runtime gate) is deliberately not run:
99
# it is a full test suite, not a packaging check.
100
#
101
# ─── vendor/dsh-std is a submodule, and building without it cannot work ────
102
# .gitmodules pins vendor/dsh-std -> https://github.com/T-Auto/dsh-std.git
103
# (currently 614dfa1ac168db79fcf4577cf0ebb34e2e3b944b). Upstream's publish
104
# workflow comments that a checkout without it produces dangling workspace
105
# links and TS2307 across the whole tsc run. prepare() checks it out. The
106
# submodule commit is fixed by the superproject tree, so the checkout stays
107
# reproducible even though it is fetched at build time.
108
#
109
# ─── Why npm packs, and why the manifest wrapper ───────────────────────────
110
# @dsh-std/* are *workspace* packages used as bundleDependencies; the repo
111
# depends on them as `workspace:*`, which a published manifest cannot carry and
112
# which pnpm refuses to pack under its isolated linker. scripts/with-publish-
113
# manifest.mjs (upstream's own publish wrapper) rewrites those entries to exact
114
# optionalDependencies for the duration of the npm command and restores the
115
# manifest afterwards, so npm packs the physical copies out of
116
# node_modules/@dsh-std/* (symlinks into vendor/dsh-std/packages/*) into the
117
# tarball. --ignore-scripts matches `npm publish --ignore-scripts` in
118
# publish.yml: lib/ is already built above.
119
#
120
# ─── pnpm version ───────────────────────────────────────────────────────────
121
# package.json pins packageManager: pnpm@11.21.0. Arch ships pnpm 12.x and the
122
# /etc/npmrc-driven global prefix (/usr/local/lib/pnpm-global) is not writable
123
# during a build, which makes pnpm's package-manager self-management abort the
124
# install with "create the package-manager env directory ... Permission denied".
125
# pnpm 12.15.0 installs the (lockfileVersion 9.0) lockfile correctly and does
126
# not rewrite it, so the build disables only that self-management step
127
# (pnpm_config_manage_package_manager_versions=false) and uses the distro pnpm.
128
# Verified: `pnpm install --frozen-lockfile` completes in ~40 s and the lockfile
129
# is byte-identical afterwards. If a future lockfile needs the pinned pnpm, add
130
# `corepack` to makedepends and run the same commands through
131
# `corepack pnpm@11.21.0` -- no other change is required.
132
133
pkgname=dsh-tui-git
134
pkgver=0.17.0.r1798.g83fcf89
135
pkgrel=2
136
pkgdesc='Claude Code style fullscreen TUI launcher for DeepSeek Harness (dsh), built from the main branch'
137
# No compiled artifact of our own ships (the payload is a portable npm tarball
138
# of JavaScript plus assets, and the launcher is JS), so the package is 'any'.
139
# The arch-specific pieces of the closure (sharp, sixel, ...) are optional
140
# dependencies that the profile's pnpm fetches for the user's own platform.
141
arch=('any')
142
url='https://github.com/ccch1mneyyy/dsh-TUI'
143
license=('MIT')
144
# Same runtime deps as dsh-tui-bin: the harness provides /usr/bin/dsh (and the
145
# @deepseek-ai/* packages the app resolves at runtime), node runs the launcher,
146
# pnpm is what the profile's plugin installs are driven with.
147
depends=('deepseek-harness' 'nodejs' 'pnpm')
148
# git: VCS source + submodule; npm: the root `prepare` script shells out to
149
# `npm run compile`, and the payload is produced by `npm pack`.
150
# nodejs/pnpm are not repeated here -- they are already runtime dependencies and
151
# makepkg installs depends for the build too.
152
makedepends=('git' 'npm')
153
install="$pkgname.install"
154
# The payload is an npm tarball plus the launcher JS; stripping is pointless
155
# there, and the tarball has to stay byte-identical to be a valid npm artifact.
156
options=('!strip' '!debug')
157
provides=('dsh-tui')
158
# dsh-tui-bin installs the same launcher and the same /usr/bin names; dsh-tui is
159
# the base name both provide, dsh-git is the convention used by the sibling
160
# harness packages. Only one of them may own the profile dependency.
161
conflicts=('dsh-tui' 'dsh-tui-bin' 'dsh-git')
162
163
source=("$pkgname::git+https://github.com/ccch1mneyyy/dsh-TUI.git#branch=main")
164
sha256sums=('SKIP')
165
166
prepare() {
167
cd "$pkgname"
168
# Required before anything compiles: the @dsh-std/* workspace packages the
169
# tsc run imports live in this submodule, and an empty vendor/dsh-std gives
170
# a dangling-link + TS2307 avalanche (see upstream publish.yml). The commit
171
# is pinned by the superproject, so this is reproducible.
172
git submodule update --init --recursive
173
}
174
175
pkgver() {
176
cd "$pkgname"
177
local _ver _rev _sha
178
# package.json is the upstream release version; the commit count keeps the
179
# AUR version monotonic between releases, and the sha pins what was built.
180
_ver=$(sed -n 's/^[[:space:]]*"version":[[:space:]]*"\([^"]*\)".*/\1/p' package.json | head -n1)
181
[ -n "$_ver" ] || { error "cannot read version from package.json"; return 1; }
182
_rev=$(git rev-list --count HEAD)
183
_sha=$(git rev-parse --short=7 HEAD)
184
printf '%s.r%s.g%s' "$_ver" "$_rev" "$_sha"
185
}
186
187
build() {
188
cd "$pkgname"
189
190
# Keep the package-manager store/cache inside $srcdir so a clean build is
191
# self-contained (a clean chroot has no useful cache either). Override the
192
# variable to reuse a warm store on the same filesystem.
193
export pnpm_config_store_dir="${pnpm_config_store_dir:-$srcdir/pnpm-store}"
194
export npm_config_cache="${npm_config_cache:-$srcdir/npm-cache}"
195
# See the pnpm note in the header: only the self-management step is disabled,
196
# the lockfile is still installed frozen.
197
export pnpm_config_manage_package_manager_versions=false
198
199
# CI recipe. The root `prepare` script runs the compile as part of this
200
# install; the explicit `pnpm compile` afterwards is what publish.yml does.
201
pnpm install --frozen-lockfile
202
pnpm compile
203
204
# Same existence checks the release workflow runs before publishing.
205
test -f lib/types/index.js
206
test -f lib/types/dsh-adapter/invariant.js
207
test -f lib/settings.json
208
209
# Upstream's tarball gate: every manifest entry point, the packaged preset,
210
# the user guide, the first-party feed, and no CLI test fixtures.
211
pnpm verify:package
212
213
# The tarball the release pipeline publishes. npm, not pnpm: see the header.
214
node scripts/with-publish-manifest.mjs npm pack --ignore-scripts
215
216
local _tgz
217
_tgz=$(ls -1 deepseek-harness-tui-dsh-tui-*.tgz)
218
[ -n "$_tgz" ] || { error "npm pack produced no tarball"; return 1; }
219
# Fail the build instead of shipping a payload that cannot start: the runtime
220
# entry points must be in the tarball and all eight bundled workspace
221
# packages must have been dereferenced into node_modules/. A missing bundle is
222
# exactly the kind of "packed fine, dies at runtime" payload this package must
223
# never publish again.
224
local _f
225
for _f in package/lib/types/index.js package/lib/types/dsh-adapter/invariant.js \
226
package/lib/settings.json package/bin/dsh-tui.js package/package.json \
227
package/cordis.yml package/cordis.patch.yml package/tui-profile/feed/first-party.json; do
228
tar -tzf "$_tgz" "$_f" > /dev/null || { error "tarball is missing $_f"; return 1; }
229
done
230
local _bundled
231
_bundled=$(tar -tzf "$_tgz" |
232
grep -cE '^package/node_modules/(@dsh-std/[a-z]+|@dsh-tui-vendor/mathjax-tex-svg)/package\.json$')
233
[ "$_bundled" -eq 8 ] || { error "tarball carries $_bundled/8 bundled packages"; return 1; }
234
}
235
236
package() {
237
cd "$pkgname"
238
239
local _tgz
240
_tgz=$(ls -1 deepseek-harness-tui-dsh-tui-*.tgz)
241
[ -n "$_tgz" ] || { error "npm pack produced no tarball"; return 1; }
242
243
# The one artifact the profile installs. pkgrel is part of the name so an
244
# upgrade always changes the profile's file: specifier (see the header).
245
install -Dm644 "$_tgz" \
246
"$pkgdir/usr/share/dsh-tui/dsh-tui-$pkgver-$pkgrel.tgz"
247
248
# Global copy on PATH: the launcher's thin-shell role, and nothing else. It
249
# reads its own package.json (name/version) and delegates to
250
# $DSH_HOME/profiles/dsh-tui/node_modules/@deepseek-harness-tui/dsh-tui.
251
# Shipping the application tree here would put lib/ back on the plain-node
252
# ESM path outside the profile, which is what used to crash (see the header).
253
install -d "$pkgdir/usr/lib/dsh-tui/bin"
254
install -m755 bin/dsh-tui.js "$pkgdir/usr/lib/dsh-tui/bin/dsh-tui.js"
255
install -m644 package.json LICENSE README.md "$pkgdir/usr/lib/dsh-tui/"
256
257
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
258
install -Dm644 THIRD_PARTY_LICENSES "$pkgdir/usr/share/licenses/$pkgname/THIRD_PARTY_LICENSES"
259
260
# Both names are the same entry point (package.json "bin"); upstream's
261
# launcher, docs and /usr/bin/dsh-tui-bin use them interchangeably.
262
install -d "$pkgdir/usr/bin"
263
ln -s ../lib/dsh-tui/bin/dsh-tui.js "$pkgdir/usr/bin/dsh-tui"
264
ln -s ../lib/dsh-tui/bin/dsh-tui.js "$pkgdir/usr/bin/dst"
265
}
266
Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-10-31 05:57:59 | Low | 2 |