lw0129a/dsh-app-packager

dsh-app-packager

uni-app x 项目打包流水线:读取本机 HBuilderX 版本,按版本推荐并一键配置对应的 iOS / Android / HarmonyOS 离线 SDK(面板卡片附官方下载入口),再按项目配置调用 HBuilderX CLI 打出、签名并上传;引擎同时以 list / doctor / check / build 四个工具暴露给 agent。

‍ 开发与运行时androidapp-packagerdeepseek-harness

English | 简体中文

dsh-app-packager

DeepSeek Harness bundle for AppPackager: list your uni-app x projects, check the local toolchain, and build iOS IPA / Android APK / HarmonyOS HAP without leaving a Harness session — from the agent (four tools) or from a panel in the web GUI.

Install

Search for AppPackager in the Harness plugin market, or:

dsh plugin --profile desktop add dsh-app-packager

Restart the profile afterwards. The plugin depends on app-packager (the CLI and the packaging engine), which is installed with it.

Panel in the web GUI

The bundle ships a client half (./src/client.ts), so the web GUI gains an App packaging entry in the sidebar's own panel list, with its page in the centre column:

  • Engine — engine directory, engine version, whether it is materialized,

and which bash bridge was found (macOS/Linux bash, Windows Git Bash or WSL). *Init engine* materializes a missing engine in one click.

  • Environment check (Node) — the same report as app_packager_doctor, for

one platform or all of them, with hints for every failed item. It runs by itself as soon as the panel has the engine state (you never sit on *Loading…*), re-runs when you switch the platform in that card, and a failure is written into the card so *Run check* can retry.

  • Folding — every section (Engine / Environment check / SDK / Projects /

Build options & scope / Upload / Job) starts collapsed; click its title to open. The fold state lives with the component, so refreshing state or polling a job never loses where the user left it.

  • Projects — every config/projects/*.env, its source directory (flagging

a missing one), the platforms it enables, and per-project *Env check* / *Build* buttons; the whole list folds under the Project list header, and each row keeps its own *Remove* button. The Choose folder… button opens the host's own folder dialog and *Add project* registers the picked directory through the engine's register subcommand, so a project anywhere on disk gets the same config/projects/.env the wizard would write. The field is the folder that holds your projects (e.g. /Users/you/work/projects) — the engine scans one level below it and registers every uni-app x project it finds, so picking projects one by one is unnecessary (several picked folders are joined into that one field).

  • Build options & scope — one card for both halves of "how to build" and

"what to build": the version override, the *Upload after build* row, the *Advanced* fold, and underneath the boxed scope block — any set of platforms (tick *All* for the three) and any subset of projects (none ticked = every project that platform enables), with the one *Env check* / *Build* pair. The engine CLI takes a single platform and a single project per run, so a selection becomes several engine runs executed back to back inside one job, each marked ▶ i/n in the log; the job succeeds only if every run did, keeping the first failing exit code. A build can still upload what it just produced: the Upload after build row ticks the distribution platforms (the same selection the Upload card's *Distribution* row edits, sent as one comma separated --upload), and ticking none sends noUpload, so uploading without a rebuild stays the Upload card's job. *HarmonyOS debug HAP* and *Keep work dir* live in that *Advanced* fold, each with a one-line explanation.

  • Upload — the installers the engine has already archived, straight from

state.artifacts (listArtifacts reads packages/iOS|Android|HarmonyOS/ -latest.json): display name, version, file size (or a *no installer archived* tag when the JSON outlived the file) and build time, each with an *Upload* button that starts a kind: 'upload' job for that one artifact — the engine's upload --to action, which never rebuilds and fails the job when the engine skipped rather than uploaded. The card also holds the distribution targets (the usable uploaders from config/upload.env, ticked ones sent as one comma separated --to) and the credential rows: an uploader that declares UPLOAD_PLATFORM__API_KEY_VAR (pgyer declares PGYER_API_KEY) or _USER_KEY_VAR (PGYER_USER_KEY, pgyer's optional API 1.0 uKey) gets a masked row each, with a Configured / Not set chip next to its *Save* button. *Save* writes only the field you typed into, so storing one never clears the other: POST /api/app-packager/upload/credential updates config/upload.local.env (mode 600, the file lib/init.sh sources), and the key only ever travels engine-ward — GET state carries the booleans credentialConfigured / userKeyConfigured, never a secret. The card also reports whether the official CLI is installed (with its package and version once it is).

  • SDK — the detected HBuilderX app/CLI and its version series, and each

platform's SDK directory with its state (ready / mismatch / missing). *One-click setup* asks the engine to download and unpack the matching SDK for the ticked platforms, *Process downloaded SDKs* imports archives already in sdk/, and each row links to DCloud's official download page — plus the direct iOS archive URL, which follows from the version series alone.

  • Upgrade plugin — reinstalls dsh-app-packager@latest into the current

profile. The engine directory is renamed out of the way for the duration, so an upgrade can never delete your downloaded SDKs, certificates or registered projects; the button is hidden when the plugin does not run from a profile's node_modules. Once the upgrade job succeeds the card tells you to restart DeepSeek Harness and deliberately offers no *Reload page* button: the browser asks for client modules by the revision from its boot-time manifest, and after an upgrade that revision no longer exists on the server (plugins/??/src/client.ts&rev= answers 404), so a reload takes the sidebar entry away instead of bringing it back. Restarting DSH rebuilds the manifest.

  • Job — the running check/build/upload with its live engine log, its verdict

([FAIL] or a non-zero exit code counts as failed) and a *Stop* button. Engine [FAIL] … / [WARN] … lines are also lifted into their own box above the log together with the totals, so a missing profile, p12 or SDK is readable without scrolling the raw output. The job lives in the host process, not in the browser tab: switching to another DeepSeek Harness tab (or reloading the panel) re-adopts the newest job from GET state, so a build that is still running comes back with its log, verdict and *Stop* button, and a finished one stays on screen until you start another build or press *Clear* (settled jobs only — a running one is never dropped, or there would be nothing left to stop).

The panel only calls same-origin routes registered by this plugin (/api/app-packager/state|init|doctor|pick|project|project/remove|job|job/log|job/kill|job/clear|upload/credential) — no build logic runs in the browser. It needs a profile that ships the web app (@deepseek-ai/dsh-web-app, as the desktop and web profiles do); in a headless profile the panel is simply absent and the four tools keep working.

Tools

app_packager_list

Lists the projects configured in the engine directory (config/projects/*.env): project id, app name, whether the source directory exists, enabled platforms.

AppPackager 引擎目录:<plugin>/home
引擎版本:0.6.2
项目(1):
- shop(商城)
  平台: iOS (IPA), Android (APK)
  源码: /Users/me/work/shop

Pure Node, so it also works on Windows. The first call materializes the engine.

app_packager_doctor

Reports whether this machine can build: Node version, the bash bridge, Xcode / signing tools, HBuilderX CLI, JDK, Android SDK, DevEco Studio, the HarmonyOS signing directory and the project config. platform: ios / android / harmony / all (default all). Also pure Node.

app_packager_check

Runs the engine's check subcommand for one platform (certificates, SDK directories, HBuilderX CLI) and returns the tail of its output plus a verdict. Parameters: platform (default all), project (project id, omit for all), home.

app_packager_build

Runs a real build; minutes per platform (iOS especially), timeout 90 minutes.

Parameter · Description platform · required, ios / android / harmony / all project · project id; optional with platform=all (means every project) upload · upload after building, e.g. pgyer noUpload · skip the upload stage version · override the artifact version harmonyDebug · emit a HarmonyOS debug side-load HAP keepWork · keep the intermediate work directory home · engine directory (usually omitted, see below)

When unsure, run app_packager_check first.

Configuration

The bundle patch provides the config; override it in your own profile cordis.patch.yml by re-inserting id: app-packager:

- insert:
    - id: app-packager
      name: 'dsh-app-packager'
      config:
        home: ''                 # engine dir; empty = <plugin>/home or APP_PACKAGER_HOME
        searchRoots: []          # extra project scan roots (outside the engine's parent)
        checkTimeoutMs: 600000   # check timeout (ms)
        buildTimeoutMs: 5400000  # build timeout (ms)
        outputLimit: 12000       # engine output kept in a tool result (tail)

The same values are editable in Harness under Settings → Plugins → Plugin config.

Engine directory and first use

The engine directory lives inside the plugin (/home), so it travels with the plugin; APP_PACKAGER_HOME or the home config key points it somewhere else. An existing ~/AppPackager from an earlier version is renamed into place on first use — a rename, never a copy, so multi-GB SDKs and registered projects move instantly.

The first tool call (or the panel's *Init engine*) releases the bundled engine there; later upgrades refresh the engine files (when the .engine-version in the directory differs from the package version, the next tool call or panel button refreshes it in place, and until then that panel row reads "the directory holds X — needs a refresh") but never overwrite your own config, certificates, SDKs or artifacts. *Upgrade plugin* in the panel goes one step further and reinstalls the npm package, keeping the engine directory stashed until the install finishes.

Do not reinstall this package around the panel. /home sits inside
the package directory, so any pnpm command that really reinstalls it —
pnpm install --force, adding another version, changing the file: spec —
deletes the engine directory along with it, SDKs, certificates and registered
projects included. Use *Upgrade plugin* in the panel, or
node /upgrade.ts, which stashes the engine directory first; both
also refuse to move you onto an older release than the one installed.
When the sidebar entry disappears. The host composes the plugin list once at
startup and silently skips a plugin whose package directory is missing. Check in
order: (1) ls (i.e. /node_modules/dsh-app-packager); (2) if it
is gone, read /.plugin-manager/logs/*/pnpm.log — a failed install leaves
Command failed with exit code 1, and pnpm removes the old package directory
first, taking the SDKs, certificates and projects in home with it; (3) install it
back (plugin market, or dsh plugin --profile add dsh-app-packager) and
restart DSH — the list is composed at startup only.

For the interactive wizard (register uni-app x projects found next to the engine, pick platforms, configure signing), use the CLI:

npx app-packager init
npx app-packager register ~/work/shop   # or register a directory directly

Platform support

list / doctor work anywhere. check / build need bash: built in on macOS/Linux, and on Windows through Git for Windows (recommended) or WSL. iOS packaging is macOS only — elsewhere doctor reports iOS as failed rather than pretending otherwise.

Licence

MIT