mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
116 lines
5.6 KiB
Markdown
116 lines
5.6 KiB
Markdown
# difyctl — build
|
|
|
|
How to build, package, and ship `difyctl` from the dify monorepo.
|
|
|
|
> Spec authority for distribution: [`docs/specs/README.md`]. This file documents the **mechanics** — commands, define knobs, tarball production.
|
|
|
|
## Toolchain
|
|
|
|
| Tool | Version | Source |
|
|
| ---------------- | ----------- | -------------------------------------------- |
|
|
| Node | `^22.22.1` | `package.json#engines` |
|
|
| pnpm | `10.33.0` | `package.json#packageManager` |
|
|
| TypeScript | catalog pin | `pnpm catalog` |
|
|
| vite-plus (`vp`) | catalog pin | `pnpm catalog` — wraps Vite for tests + pack |
|
|
| oclif | catalog pin | command discovery, manifest, tarball builder |
|
|
|
|
Versions above are what the build pipeline targets. Install Node + pnpm via whatever method works for your environment.
|
|
|
|
## Quick start
|
|
|
|
```sh
|
|
# inside dify/ monorepo root
|
|
pnpm install
|
|
pnpm --filter @langgenius/difyctl build
|
|
```
|
|
|
|
This produces:
|
|
|
|
- `cli/dist/` — TypeScript output (commands, source map, .d.ts)
|
|
- `cli/oclif.manifest.json` — oclif command index (used at runtime to skip filesystem scan)
|
|
|
|
## Scripts
|
|
|
|
| Script | What it does |
|
|
| ------------------------------------------------- | ------------------------------------------------------------------- |
|
|
| `pnpm --filter @langgenius/difyctl build` | `vp pack && oclif manifest` — production bundle + manifest refresh |
|
|
| `pnpm --filter @langgenius/difyctl dev` | `tsx bin/dev.js` — runs CLI from TS source, no build step |
|
|
| `pnpm --filter @langgenius/difyctl test` | `vp test` — vitest suite (40+ files, ~400+ behavior tests) |
|
|
| `pnpm --filter @langgenius/difyctl lint` | eslint — antfu config + perfectionist sort + unicorn rules |
|
|
| `pnpm --filter @langgenius/difyctl type-check` | `tsc` — strict mode, `noUncheckedIndexedAccess` |
|
|
| `pnpm --filter @langgenius/difyctl manifest` | `oclif manifest` — refresh `oclif.manifest.json` only |
|
|
| `pnpm --filter @langgenius/difyctl readme` | `oclif readme` — regenerate command reference in `cli/README.md` |
|
|
| `pnpm --filter @langgenius/difyctl pack:tarballs` | `oclif pack tarballs --xz --parallel` — multi-target tarball matrix |
|
|
|
|
## Build-time defines (vite-plus)
|
|
|
|
`vite.config.ts` injects a small set of constants at pack time. These replace what the Go port did via `-ldflags -X`:
|
|
|
|
| Define | Source | Read from |
|
|
| ------------------------ | ----------------------------------------------------------------------------- | ------------------------- |
|
|
| `__DIFYCTL_VERSION__` | `DIFYCTL_VERSION` env var (else `package.json#version`) | `cli/src/version/info.ts` |
|
|
| `__DIFYCTL_COMMIT__` | `DIFYCTL_COMMIT` env var (else `git rev-parse HEAD`) | `cli/src/version/info.ts` |
|
|
| `__DIFYCTL_BUILD_DATE__` | `DIFYCTL_BUILD_DATE` env var (else `new Date().toISOString()`) | `cli/src/version/info.ts` |
|
|
| `__DIFYCTL_CHANNEL__` | `DIFYCTL_CHANNEL` env var (default `stable`; values: `stable`, `beta`, `dev`) | `cli/src/version/info.ts` |
|
|
|
|
In dev (`bin/dev.js`), `globalThis.__DIFYCTL_*__` are set from the same env vars at startup, so `difyctl version` reflects the local checkout without a rebuild.
|
|
|
|
## Tarball production
|
|
|
|
```sh
|
|
# default — every supported (os, arch) target
|
|
pnpm --filter @langgenius/difyctl pack:tarballs
|
|
|
|
# subset — single target
|
|
pnpm --filter @langgenius/difyctl exec \
|
|
oclif pack tarballs --xz --targets=darwin-arm64
|
|
```
|
|
|
|
Outputs land in `cli/dist/`. Each tarball bundles the Node binary for that target (oclif fetches from `nodejs.org`), the compiled JS, and the prebuild for `@napi-rs/keyring` matching that target.
|
|
|
|
Supported targets (matches `auth-storage.md` matrix):
|
|
|
|
- `darwin-arm64`
|
|
- `darwin-x64`
|
|
- `linux-x64-gnu`
|
|
- `linux-arm64-gnu`
|
|
- `win32-x64`
|
|
|
|
## Container image
|
|
|
|
```sh
|
|
docker build \
|
|
--build-arg VERSION=$(node -p "require('./cli/package.json').version") \
|
|
-f cli/Dockerfile \
|
|
-t ghcr.io/langgenius/difyctl:dev cli/
|
|
```
|
|
|
|
The Dockerfile uses `node:22-alpine` and `npm install -g @langgenius/difyctl@${VERSION}` so the CI release pipeline does not need to ship multi-arch tarballs separately for container users — it just publishes to npm and rebuilds the image.
|
|
|
|
## Release flow
|
|
|
|
The dify release workflow ships a `release-cli` job that fans out from the dify version tag:
|
|
|
|
1. `pnpm --filter @langgenius/difyctl build`
|
|
1. `oclif manifest` (already part of build)
|
|
1. `oclif pack tarballs --xz --parallel`
|
|
1. `pnpm publish --access public --tag latest` (requires `NPM_TOKEN`)
|
|
1. `softprops/action-gh-release` attaches tarballs + install scripts to the GitHub release
|
|
1. `docker buildx build --push` for the container image
|
|
|
|
CLI version equals dify version; parity enforced at tag time.
|
|
|
|
## Local install for smoke testing
|
|
|
|
```sh
|
|
# from a fresh clone — verify the build works end to end
|
|
pnpm install
|
|
pnpm --filter @langgenius/difyctl build
|
|
pnpm --filter @langgenius/difyctl exec oclif pack tarballs --targets=$(uname -s | tr 'A-Z' 'a-z')-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/')
|
|
ls cli/dist/*.tar.xz
|
|
```
|
|
|
|
The resulting tarball is a self-contained Node + difyctl bundle — extract anywhere, point `$PATH` at `bin/`, and `difyctl --version` works without the host having Node installed.
|
|
|
|
[`docs/specs/README.md`]: specs/README.md
|