dsh-tui-git

LOW
maintainer HanHaocheng 0 votes scanned 2026-10-31 05:57:59.662655
View on AUR
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
133pkgname=dsh-tui-git
134pkgver=0.17.0.r1798.g83fcf89
135pkgrel=2
136pkgdesc='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.
141arch=('any')
142url='https://github.com/ccch1mneyyy/dsh-TUI'
143license=('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.
147depends=('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.
152makedepends=('git' 'npm')
153install="$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.
156options=('!strip' '!debug')
157provides=('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.
161conflicts=('dsh-tui' 'dsh-tui-bin' 'dsh-git')
162
163source=("$pkgname::git+https://github.com/ccch1mneyyy/dsh-TUI.git#branch=main")
164sha256sums=('SKIP')
165
166prepare() {
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
175pkgver() {
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
187build() {
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
236package() {
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)SeverityRules
2026-10-31 05:57:59 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