Keep release files at the archive root and reject product-named directory components before CI packages artifacts.
Use neutral directories for media staging, WebUI uploads, stream storage, and MCP downloads so packaged and runtime layouts remain consistent.
Make line endings deterministic across macOS, Windows, and Linux while preserving the native checkout format required by Windows launchers.
Pin the tested application runtime and Node type baseline, add a shared startup preflight, and keep independently published packages on their existing compatibility ranges.
Align local scripts, pull request validation, complete package builds, dependency metadata, and contributor documentation around the same Node and pnpm contract. The root test command now covers every tested workspace package while a focused Core command remains available for local iteration.
Replace the feature-specific MP3 verification command with a workspace-wide native test entry point.
Keep native regression cases in package-owned test suites so future checks can expand without adding workflow steps.
Use the dedicated audio conversion path for record output so mono QQ voice records produce valid MP3 data.
Add release-target smoke coverage and preserve conversion and cleanup failures for diagnostics.
Fixes#239
Present Windows x64, Linux x64, and Linux arm64 as fully supported release targets in a concise download matrix.
Add quick-start and unattended-consent guidance, link commits and version comparisons, and filter merge and release housekeeping from the change list.
Refresh the adjacent packaging documentation so it matches current platform support.
On push to `dev`, dispatch SnowLuma.Docker.Framework/docker-image.yml to build
and push motricseven7/snowluma:dev (rolling) + :dev-<12sha> (immutable) from
this run's workflow artifact — no GitHub Release involved. also_latest=false so
dev never touches the stable :latest; the downstream job prunes old dev-<sha>
tags (keep newest 5). The dispatch job writes source SHA / run id / downstream
run URL to the job summary.
Supporting changes:
- Bundle production node_modules (npm install --omit=dev) before packaging so
the lite tarball the image bakes is actually runnable — mirrors release.yml.
- Add a deterministic-name hand-off artifact (snowluma-dev-docker-linux-x64,
dev-only) that the cross-repo Docker build downloads by name.
- Concurrency: only `dev` shares a self-cancelling group; every other branch
keeps a unique per-run group, so their behavior is unchanged.
- Age-gate the artifact cleanup (delete >24h, collect-then-delete) so it can't
race-delete an in-flight dev hand-off artifact.
blank_issues_enabled: false only hides the chooser link — the CLI / API /
direct URLs still create template-less issues (e.g. #174 by a CONTRIBUTOR).
This workflow enforces the policy: an issue opened by someone without write
access that carries no template label (bug / enhancement) is commented on and
closed as not-planned. Proper bug reports / feature requests and write-access
users are unaffected.
Takes effect only once on the default branch (main).
The needs-logs workflow tested /\bTRACE\b/i against the raw issue body.
Pasted terminal logs wrap the level in ANSI color codes (\x1b[90mTRACE\x1b[0m);
the trailing 'm' of the color code abuts 'TRACE', so the leading \b never
matches and a log that clearly contains TRACE is wrongly flagged needs-logs
(e.g. #156). Strip ANSI escapes first, and measure the too-short heuristic on
the cleaned text too.
Daily stale sweep over issues still labeled needs-logs: mark stale after
7 days of inactivity, close (not_planned) after another 7. Issues that
get valid logs lose the needs-logs label and are skipped by only-labels.
PRs are excluded.
Form validation can only force a field non-empty, not validate content.
On bug issue opened/edited, parse the TRACE-log section: if empty, missing
a TRACE marker, or too short, label needs-logs + post a one-time guide
comment; auto-remove the label once the reporter edits in valid logs.
- Make the logs textarea required so a bug report can't be submitted empty.
- Document how to enable TRACE: WebUI server log-level switch (+ '开发'
preset so the export actually contains trace lines) or SNOWLUMA_LOG_LEVEL=trace.
- Add a required preflight checkbox attesting TRACE logs are attached.
The repo had no PR test gate, so broken tests landed on dev unnoticed. Add a
pull_request workflow that runs `pnpm -r --no-bail --if-present test` across all
packages on ubuntu-latest (pnpm 10.28.0, Node 22), with per-PR concurrency.
A new published package that exposes every OneBot action's docs + a ready-to-use
JSON Schema to LLM clients over stdio. Tools: list_actions / get_action /
search_actions / list_categories, plus the whole catalog as a resource.
The catalog is a build-time snapshot generated from @snowluma/onebot's live
action specs (collectActionDocs()) — so it auto-tracks action add/remove and the
published package carries zero runtime dependency on the private onebot package.
action-kit enrichment (the data source):
- Field.toJsonSchema() per coercer (uint→integer/minimum:1, messageId→integer/
not-const-0, int→min/max, string→minLength/maxLength, array→items, enum→enum).
- describe() composes a per-action inputSchema; ActionDoc gains inputSchema +
category. action-docs.ts tags each doc with its domain category.
Wiring: onebot exports ./action-kit + ./action-docs; root build:all includes mcp;
mcp-npm-publish.yml mirrors the sdk/ui publish workflows (triggers on changes
under packages/mcp/** or packages/onebot/**, since the catalog derives from it).
onebot typecheck + 318 tests green; mcp typecheck/build/smoke green; the 142
registered OneBot action names are unchanged.
Add a new animated SVG logo at .github/logo.svg and embed it in README.md. Update the README content: refresh badges, simplify and translate the project intro and feature list into Chinese, add concise quickstart steps, adjust links (Releases → 发布版, RoadMap), and replace long/duplicated sections with a shorter overview and contributor badge. Overall this cleans up and modernizes the README and adds a branded logo for the project.
Replaces "runtime npm dependency that gets `npm install`-ed into
dist/" with "TS wrapper that loads the native `.node` from
`dist/native/` like every other native binding in the project".
Why the change
--------------
The previous approach (better-sqlite3 declared in
packages/runtime/package.json, materialized by `npm install
--omit=dev` in dist/) worked but produced an artifact that needed
runtime npm install — a step the rest of SnowLuma's native bindings
don't need (websocket / snowluma-hook / ffmpeg are all standalone
`.node` files copied into `dist/native/` by vite-plugin-cp). The
asymmetry was friction: dev mode required `pnpm dist:install`,
build artifacts carried a `dist/node_modules/` tree the other
modules didn't need, and Docker images had to special-case the
glibc-vs-musl ABI lookup that prebuild-install runs.
The new shape:
- `@snowluma/sqlite` (packages/sqlite/) — TS wrapper. Has
`better-sqlite3` as a devDep (for the JS-layer types + the
actual JS wrapper code that vite inlines). At runtime, calls
`createRequire().require()` against
`<dist|repo>/native/better-sqlite3-v<abi>-<platform>-<arch>.node`
and passes the resolved addon to `new Database(path, {
nativeBinding })`.
- `packages/runtime/native/better-sqlite3-v<abi>-<triplet>.node`
— prebuilt binaries vendored into the repo. Two ABIs ship side-
by-side (v127 = Node 22 LTS used by CI, v137 = Node 24 used by
dev boxes) so `process.versions.modules` picks the matching one
at load time.
- `tools/fetch-sqlite-prebuilts.mjs` — fetches all 5 platforms ×
N ABIs from WiseLibs's GitHub releases. Idempotent: existing
`.node` files skip. Accepts extra ABI args:
`node tools/fetch-sqlite-prebuilts.mjs 12.10.0 v127 v137 v115`.
What was unwound
----------------
- packages/runtime/package.json — dependencies removed (runtime
artifact is now self-contained, no `npm install` step needed).
- root package.json — `dist:install` script removed (no node_modules
to install).
- .github/workflows/dev-build.yml — `Bundle runtime dependencies`
step removed.
- .github/workflows/release.yml — kept the `Bundle runtime
dependencies` step (was a no-op already, but harmless safety net
in case a future runtime dep shows up).
- packages/core/vite.config.ts — `better-sqlite3` no longer
external; vite inlines the JS wrapper (+~33 KB to bundle, ~2.84
MB → 2.87 MB total).
Naming
------
Mirrors the existing `websocket-${triplet}.node` convention (flat
dir under `runtime/native/`, dash-separated `<platform>-<arch>`).
Adds a `v<abi>` segment because better-sqlite3 is NOT N-API — one
binary per Node ABI. Naming:
better-sqlite3-v127-darwin-arm64.node Node 22 / macOS arm
better-sqlite3-v127-darwin-x64.node Node 22 / macOS intel
better-sqlite3-v127-linux-arm64.node Node 22 / Linux arm
better-sqlite3-v127-linux-x64.node Node 22 / Linux x64
better-sqlite3-v127-win32-x64.node Node 22 / Windows x64
better-sqlite3-v137-... (5) Node 24 / same 5 hosts
Total: 10 binaries × ~1.9 MB = ~19 MB committed. Aligned with the
existing native-vendoring footprint (websocket ~2 MB × 5, snowluma-
hook ~10 MB × Windows + Linux, ffmpeg ~10-30 MB × 4).
What changes for consumers
--------------------------
Source-side: nothing. `import Database, { type Database, type
Statement } from '@snowluma/sqlite'` is a drop-in for the previous
`import Database from 'better-sqlite3'`. The wrapper re-exports the
same types and the `Database` callable factory has the same
overload set.
Runtime: `node` finds the binding at
`<dist|repo>/native/better-sqlite3-v${process.versions.modules}-
${process.platform}-${process.arch}.node`. If the ABI doesn't
match a vendored binary, the wrapper throws a clear error pointing
at `tools/fetch-sqlite-prebuilts.mjs` with the missing ABI/triplet.
Bumped better-sqlite3 from 11.10.0 → 12.10.0 because v11 only had
prebuilt up to Node ABI v127 (no v137 = no Node 24). v12.10.0
ships both. Both versions are API-compat (the breaking changes
between v11 and v12 were either internal or in error-handling
paths SnowLuma doesn't exercise).
Verification
------------
- pnpm -r typecheck (12 projects): clean
- @snowluma/core test: 302/302
- @snowluma/onebot test: 250/250 (552/552 combined, unchanged from
the perf-series baseline)
- Bench numbers preserved — wrapper indirection is sub-μs:
storeMeta ~11 μs, storeEvent ~17 μs, findMeta hit ~1.1 μs (all
within noise of the post-RoadMap-#5 measurements).
- Vite build clean, bundle = 2.87 MB / 230 KB gzip
- `dist/index.mjs` no longer contains a `node:sqlite` import (it
did before — media-store hadn't migrated; now neither it nor
message-store reach into the Node builtin).
Bonus side-fix: `packages/onebot/src/media-store.ts` also moved
off `node:sqlite` (caught by the post-build bundle grep — the
file was using `DatabaseSync` + `StatementSync` from the builtin
even though it had already been written to cache its prepared
statements). Its hot paths now go through the same wrapper.
Followup to 0b6541c. That commit added `better-sqlite3` as a
workspace dependency and marked it as a vite external — meaning
the bundled `dist/index.mjs` does `require('better-sqlite3')` at
runtime instead of inlining its JS wrapper. Without the binding
+ wrapper present in the production archive, every shipped
SnowLuma would crash on first SQLite op.
The fix is in three small pieces:
1. `packages/runtime/package.json` — declare `better-sqlite3` as a
runtime dep. `vite-plugin-cp` copies this manifest into
`dist/package.json` during build (see `runtimeDistFiles` in
`packages/core/vite.config.ts`), so the release workflow's
existing `npm install --omit=dev` step inside `dist/` picks it
up and compiles the native binding for the matrix target via
prebuild-install (with node-gyp fallback). This is the same
mechanism release.yml has used since v1.x — it was just empty
until now because the previous vite config bundled everything.
2. `.github/workflows/dev-build.yml` — mirror the
`Bundle runtime dependencies` step from release.yml. Dev-build
was packaging `dist/` straight after vite, which would have
shipped a broken artifact (no `dist/node_modules/`). Added the
`npm install --omit=dev` step before the tar/zip packaging
steps so dev-build archives carry the binding too.
3. `package.json` root — add `dist:install` script (just
`cd dist && npm install --omit=dev`) so local prod-mimic flows
work: `pnpm build && pnpm dist:install && pnpm dev:mode`. Not
chained into `pnpm build` itself to keep the watch-cycle fast
for users who only need the vite build output; the install
step adds ~17s.
Note on dev mode: `pnpm dev` continues to work unchanged — it
runs via tsx against workspace `node_modules/`, which already has
`better-sqlite3` compiled (from the workspace-level pnpm install).
Only the dist/-based prod-mimic path needed the explicit install.
Verification
------------
- `pnpm build` (with stubbed native binary): clean, dist/ has the
updated `dist/package.json` with the dependency declared
- `pnpm dist:install`: installs 38 packages, compiles
`dist/node_modules/better-sqlite3/build/Release/better_sqlite3.node`
- Smoke-test from `dist/`: `node -e "import('better-sqlite3')..."`
prints `OK: [ { id: 42 } ]`, confirming the binding loads + a
basic INSERT/SELECT roundtrip works.
CI matrix coverage: win-x64, linux-x64, linux-arm64 (release.yml +
dev-build.yml share the same matrix). Each builds its own native
binding during the install step — prebuild-install hits
better-sqlite3's prebuilt-binary registry for these three targets
(no source compile needed in the common case, falls back to
node-gyp if a prebuilt isn't available).
Delete the "Bundle runtime dependencies" step from .github/workflows/dev-build.yml. The removed step changed to working-directory: dist and ran npm install --omit=dev, so CI will no longer install runtime deps into dist during the dev build, reducing build time and avoiding bundling node modules into the dev artifacts.
Adds structured YAML issue forms (bug + feature) and a config that
disables blank issues and links to the QQ group / Telegram channels
already in README.
Mirror of sdk-npm-publish.yml for the UI package. Same triggers
(packages/ui/** + lockfile/workspace/tsconfig.base) and same
already-published guard via `npm view`, so reruns are idempotent.
Differences from the SDK workflow:
- Drops the `test` step (UI package has no Vitest suite yet).
- Filters and working-directory point at packages/ui.
Auth uses the same `NPM_TOKEN` secret in the SnowLuma environment.
Publishes with `--provenance` so the npm registry attests the build
came from this exact GitHub Actions run.
Switch default merge_method from 'merge' to 'squash' so dev->main PRs collapse the dev branch's incremental commits into one squash commit on main, keeping main's history linear and release-tag-friendly. Affects: workflow_dispatch input default, decide-step initial value + workflow_dispatch fallback, both push-trigger branches (tag + commit-msg), and the case-statement fallback in the auto-merge step. CONTRIBUTING.md updated to reflect the new default.
- Tag trigger switched from v* to chore.* so the promote workflow no longer collides with release.yml's v* tag handling. v* tags now drive only the release build; chore.* tags drive only dev->main promotion.
- Commit-message detection on dev is now prefix-only: '^[merge]' or '^chore(release):' (case-insensitive). 'fix: stuff [merge]' no longer triggers; the marker must be at the start of the message.
- CONTRIBUTING.md updated: prefix examples, chore.* tag examples, and an explicit 'all required status checks must pass' branch-protection setup that lists the dev-build typecheck/build matrix as required.
Adds .github/workflows/promote-dev-to-main.yml which uses the SnowLuma Bot GitHub App to open (or refresh) a PR from dev into main. Triggered by [merge] or chore(release): commit-msg markers on dev, by v* tag pushes, or via manual workflow_dispatch. Auto-merge is enabled when triggered.
Adds CONTRIBUTING.md describing the dev/main branch model, the promote workflow, the required SNOWLUMA_BOT_APP_ID / SNOWLUMA_BOT_PRIVATE_KEY secrets, and the GitHub branch protection setup needed to forbid direct pushes to main.
Update GitHub Actions release workflows to use the SNOWLUMA_TOKEN secret instead of DOCKER_RELEASE_TOKEN. Changed the github-token input in .github/workflows/release.yml and .github/workflows/dispatch-docker-release.yml for the docker release steps.
Introduce a manual re-dispatch workflow and wire automatic dispatch from releases to the Docker workflow. dispatch-docker-release.yml was converted to a workflow_dispatch-based "Re-dispatch Docker Release" that accepts snowluma_tag, docker_image_override and platforms_override inputs and forwards them (plus source repository) to the downstream docker-image.yml in the Docker release repo. release.yml gains a dispatch-docker job that runs after the release job and uses a PAT to invoke the same downstream workflow for newly published tags. These changes let maintainers rebuild Docker images for existing tags (e.g. to fix Dockerfile issues or rotate credentials) without re-tagging, and ensure the downstream dispatch runs under the configured token.
Switch the release dispatch to call actions.createWorkflowDispatch instead of repos.createDispatchEvent because the target repo only listens for workflow_dispatch on its docker workflow. Add env vars DOCKER_PLATFORMS, DOCKER_WORKFLOW and DOCKER_REF (with sensible defaults) and pass image, tag, push and platforms as inputs. Update log output to include workflow, ref, image, tag and platforms.
Trigger the external Docker release pipeline when a SnowLuma version tag is pushed.
Keep Docker image and release target configuration in the SnowLuma environment.
Change the documented localhost port in .github/workflows/release.yml from 8080 to 5099 so packaged builds reference the correct WebUI endpoint. This updates the startup instructions shown in the release workflow to match the new default port.
Introduce a `typecheck` job to GitHub Actions that sets up pnpm and Node.js (v22), installs dependencies, and runs `pnpm typecheck` on the workspace. Make the `build` job depend on `typecheck`. Also add a `typecheck` script (`tsc --noEmit`) to packages/websocket/package.json to enable package-level type checking. This ensures TypeScript errors are caught before the build runs.
Comment out the linux-arm64 matrix entry in .github/workflows/release.yml so the ubuntu-24.04-arm runner is no longer included in release jobs. This temporarily disables ARM64 releases; re-enable by uncommenting the linux-arm64 lines.
Temporarily comment out the linux-arm64 matrix entry in .github/workflows/dev-build.yml (name, os, target) to prevent the ARM64 job from running. Lines are commented rather than removed so the job can be re-enabled easily later.
Restructure GitHub Actions to build Windows and Linux matrix targets and produce platform-specific artifacts.
- .github/workflows/dev-build.yml: split cleanup/build jobs, add matrix (win-x64, linux-x64), set SNOWLUMA_TARGET for builds, produce full and -lite archives (.zip on Windows, .tar.gz on Linux), unify upload step and ensure errors when artifacts missing.
- .github/workflows/release.yml: convert release build to matrix, produce platform archives, download/collect artifacts, generate multi-platform release notes (bash), and create the GitHub release with both .zip and .tar.gz assets.
- packages/core/vite.config.ts: add fs import and SNOWLUMA_TARGET handling, pick platform-specific runtime files (launcher.bat or launcher.sh), enumerate native files per target, fail CI if expected native binaries are missing, and copy native files into dist/native.
- packages/runtime/launcher.sh: add a portable launcher for Linux that prefers a bundled node binary or falls back to PATH and execs index.mjs.
These changes enable cross-target CI packaging and enforce that native binaries are present before releasing.
Simplify CI by removing job matrices and always building the WebUI flavor. Both dev and release workflows now run build:all, verify the websocket native module, and produce two archives: a zero-install bundle that includes node.exe and a no-node variant (requires Node >=22). Artifact names and upload steps were adjusted (dev uses SHA-based names; release uses tag-based names), and release notes were updated to document the two packages and WebUI defaults.
Restructure the repository into a pnpm workspace under packages/ (core, webui, runtime). Move source files for core and webui into packages/*, add package manifests for @snowluma/core and @snowluma/runtime, and remove the old launcher package.json. Update root package.json to be a monorepo controller (scripts delegate to pnpm filters, set packageManager and Node engine). Configure build outputs to emit into the repo-root dist/ (vite config changes) so the existing release pipeline continues to work. Add .npmrc with mirrors, expand .gitignore for monorepo layout, add tsconfig base and package-level tsconfigs, and add vitest config for the core package. Adjust injector native search paths and update tests import paths to the new package layout. Small CI/workflow comment added to clarify build behavior and README updated with monorepo structure and common commands.
Set checkout fetch-depth to 0 and add a PowerShell step that generates release-notes.md for the current tag (computes previous tag, collects commit messages, and emits localized download/usage notes for Windows x64 builds). Update the GitHub Release step to use body_path: release-notes.md and overwrite_files: true (replacing auto-generated notes) so the release includes the curated changelog and artifact information.