feat: make the app template package-manager-aware (pnpm-first + npm artifacts + detection) - #593
Conversation
There was a problem hiding this comment.
Note
Copilot was unable to run its full agentic suite in this review.
Copilot review overview
Review effort: Lite
Findings: 2
Open (5)
This regex is unlikely to match commonpnpm-lock.yamllayout whereresolution:is followed by a… · Newnew RegExp(key, "g")will throw for keys like{{.projectName}}because{/}are regex… · New Enabling pre/post scripts changes lifecycle script execution behavior for consumers of the template… · New The comment says “hidden directories”, but this condition skips hidden files too (e.g.,… · New The phrase “a custom.npmrcor.npmrc” is duplicated and reads like a typo. Replace the second… · New
What changed in this PR
Adds tooling and CI to validate the committed app template in a pnpm-based workflow and prevent lockfiles from referencing non-public registries.
Changes:
- Introduces a template scaffold “smoke test” script and CI job that installs with
pnpm --frozen-lockfileand builds outputs. - Updates registry-validation tooling to support both npm and pnpm lockfile formats and defaults to the committed pnpm lock.
- Migrates the template from npm to pnpm (scripts/docs/config), including workspace settings like overrides and supported architectures.
| File | Description |
|---|---|
| tools/smoke-test-template.ts | New script to scaffold and minimally render the template into a scratch dir for CI smoke testing. |
| tools/check-template-lock-registry.ts | Extends lockfile registry validation to pnpm and adds format detection and better UX errors. |
| template/pnpm-workspace.yaml | Adds pnpm workspace config with overrides, allowBuilds, and supportedArchitectures. |
| template/package.json | Switches template scripts to pnpm and records pnpm as the package manager. |
| template/app.yaml.tmpl | Updates runtime command to use pnpm. |
| template/README.md | Updates developer instructions from npm to pnpm. |
| template/.npmrc | Adds pnpm/npm config for lifecycle scripts behavior. |
| .oxlintrc.json | Ignores the smoke-test scratch directory from linting. |
| .oxfmtrc.json | Ignores the smoke-test scratch directory from formatting. |
| .gitignore | Ignores the smoke-test scratch directory. |
| .github/workflows/ci.yml | Adds a CI job to scaffold, install (frozen lockfile), verify native optional dep materialization, and build. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
🤖 AppKit PR bot🔬 Run evalsStart an eval for this PR from the evals-monitor app: Go to Evals Monitor → 📦 Try this PR's app templateScaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh run download 36860786137 -R databricks/appkit -n appkit-template-0.81.0-pr.176a437-pnpm-template-1-pnpm-first-593 -D appkit-pr-593 \
&& unzip -o "appkit-pr-593/appkit-template-0.81.0-pr.176a437-pnpm-template-1-pnpm-first-593.zip" -d "appkit-pr-593" \
&& databricks apps init --template "appkit-pr-593"The template pins |
b086dcc to
6b2d0c4
Compare
📦 Bundle size reportCompared against ✅ No size changes vs the baseline.
|
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 1.2 MB | 428 KB |
| Type declarations | 446 KB | 162 KB |
| Source maps | 2.4 MB | 802 KB |
| Other | 11 KB | 3.7 KB |
| Total | 4.0 MB | 1.4 MB |
Per-entry composition (own code — deps external (as shipped))
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
. |
96 KB | 2.5 KB | 99 KB | external | 316 KB |
./beta |
93 KB | 478 B | 94 KB | external | 282 KB |
./testing |
38 KB | 31 KB | 69 KB | external | 202 KB |
./tsdown |
520 B | 0 B | 520 B | external | 813 B |
./type-generator |
23 KB | 0 B | 23 KB | external | 65 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
. |
index.js |
initial | 92 KB |
. |
utils.js |
initial | 4.6 KB |
. |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./beta |
beta.js |
initial | 77 KB |
./beta |
stream-manager.js |
initial | 5.8 KB |
./beta |
databricks.js |
initial | 3.3 KB |
./beta |
wide-event-emitter.js |
initial | 3.2 KB |
./beta |
configuration.js |
initial | 2.3 KB |
./beta |
service-context.js |
initial | 1.3 KB |
./beta |
client.js |
initial | 434 B |
./beta |
client-options.js |
initial | 219 B |
./beta |
supervisor-api.js |
lazy | 192 B |
./beta |
databricks.js |
lazy | 164 B |
./beta |
index.js |
lazy | 122 B |
./testing |
manifest.js |
initial | 26 KB |
./testing |
index.js |
initial | 10.0 KB |
./testing |
wide-event-emitter.js |
initial | 2.9 KB |
./testing |
index.js |
lazy | 27 KB |
./testing |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./testing |
utils.js |
lazy | 1.8 KB |
./tsdown |
index.js |
initial | 520 B |
./type-generator |
index.js |
initial | 23 KB |
@databricks/appkit-ui
npm tarball (packed): 350 KB — gzipped download (dist + bin; excludes release-only docs/NOTICE).
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 395 KB | 132 KB |
| Type declarations | 229 KB | 84 KB |
| Source maps | 766 KB | 253 KB |
| CSS | 16 KB | 3.2 KB |
| Total | 1.4 MB | 472 KB |
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
./js |
5.3 KB | 49 KB | 55 KB | 208 KB | 14 KB |
./js/beta |
20 B | 0 B | 20 B | 0 B | 0 B |
./react |
432 KB | 49 KB | 481 KB | 1.3 MB | 177 KB |
./react/beta |
1.0 KB | 0 B | 1.0 KB | 0 B | 1.9 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
./js |
index.js |
initial | 5.2 KB |
./js |
chunk |
initial | 120 B |
./js |
apache-arrow |
lazy | 49 KB |
./js/beta |
beta.js |
initial | 20 B |
./react |
index.js |
initial | 430 KB |
./react |
tslib |
initial | 2.1 KB |
./react |
apache-arrow |
lazy | 49 KB |
./react/beta |
beta.js |
initial | 1.0 KB |
Flip the `databricks apps init` app template from npm to pnpm as the default package manager so scaffolds deploy to Databricks Apps with native deps intact. - ship template/pnpm-lock.yaml (pnpm@11.0.8) plus a single-app pnpm-workspace.yaml carrying the migrated overrides, allowBuilds (esbuild, @ast-grep/napi, ...) and supportedArchitectures for linux/x64/glibc, so @ast-grep/napi-linux-x64-gnu materializes on install - set packageManager to pnpm@11.0.8 and make every script sibling call an explicit `pnpm run <script>` (pnpm 11 shadows bare `pnpm <script>`) - enable pre/post scripts via template/.npmrc so prebuild (typegen) fires - render app.yaml `command: ['pnpm', 'run', 'start']`; template README to pnpm - validate template/pnpm-lock.yaml in the leak validator (format-dispatch by filename) and drop the npm package-lock.json (returns in Phase 2) Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Guard the deploy shape the pnpm-first template depends on: a fresh `pnpm install --frozen-lockfile` on the scaffolded app must materialize the linux native dep and run its build. - tools/smoke-test-template.ts scaffolds the committed template into .smoke-test/app (renders the mustache placeholders, no tarball rewrite) so the frozen install runs against the committed pnpm-lock - new `template-deploy-shape` CI job installs --frozen-lockfile on linux-x64, asserts @ast-grep/napi-linux-x64-gnu materialized, and runs build:client/build:server (typegen/boot need a live workspace, so are out of CI scope) - gitignore the .smoke-test scratch dir and exclude it from oxlint/oxfmt This closes the long-standing deploy-shape CI gap; it caught the allowBuilds mis-encoding fixed in the previous commit. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
Bring back first-class npm support in the pnpm-first app template so a scaffold selected as npm (`databricks apps init --package-manager npm`) installs and deploys with native deps intact. The committed default stays pnpm-shaped. - ship template/package-lock.json (lockfileVersion 3, public registry only) - re-add top-level npm `overrides` in template/package.json, mirroring the pnpm-workspace.yaml overrides - pin @ast-grep/napi-linux-x64-gnu as a root optionalDependency (os/cpu guarded by the package itself) as a defensive edge against npm/cli#4828 style lock regeneration dropping the linux binary; regenerate pnpm-lock.yaml for the new edge - check-template-deps: fail when the npm and pnpm override placements drift, or when the linux pin is missing or skews from @ast-grep/napi Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
- check-template-lock-registry validates template/pnpm-lock.yaml and template/package-lock.json by default, fail-closed if either is missing - parse pnpm-lock.yaml with `yaml` instead of a URL regex so tarball, git, directory and missing resolutions fail closed, at parity with the npm handler; the npm handler now fails on non-root/link/bundled entries with no `resolved`; each .npmrc is checked once - add template-deploy-shape-npm: bare `npm install` from the committed lock on linux-x64, assert @ast-grep/napi-linux-x64-gnu materializes and loads, build client and server - load @ast-grep/napi at runtime in the pnpm deploy-shape job too - smoke-test-template: --package-manager selects which lock the scaffold keeps - pr-template-artifact regenerates both locks against the PR tarballs (npm install, then pnpm install --lockfile-only) and rewrites and validates both before zipping, so the artifact no longer ships a stale pnpm-lock.yaml Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu>
`appkit plugin create` previously hardcoded pnpm in its guidance. Detect the developer's package manager and render the right commands instead — with no CLI flag, since the command runs inside a project whose manager is already decided. - New shared module `cli/package-manager.ts`: `detectPackageManager` (order: `npm_config_user_agent` -> lockfile in cwd, including `package-lock.json` -> npm -> pnpm fallback) and a `PM_COMMANDS` capability map (install/build/add/exec) that always uses an explicit `run` form, e.g. `pnpm run build` (pnpm 11 shadows bare script names). - `printNextSteps` (isolated-placement branch) and the generated plugin README now render install/build/add for the detected manager. - `registry add` consolidated onto the shared detector (its local lockfile-only copy removed) for a single source of truth. Covers pnpm, npm, yarn, and bun. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu>
6b2d0c4 to
718265f
Compare



Summary
Makes the AppKit app template package-manager-aware, consolidating what was
previously a 3-PR stack into a single PR against
main.This covers the full scope:
packageManager: pnpm@11.0.8,pnpm-workspace.yaml(overrides, build allowlist,
supportedArchitectures),.npmrc(
enable-pre-post-scripts), committedpnpm-lock.yaml, and a CITemplate Deploy-Shape smoke test that scaffolds the template, runs
pnpm install --frozen-lockfile, verifies the native@ast-grep/napibinary loads, and builds client + server.
validates both lockfiles;
check-template-lock-registry.tswas reworkedto validate npm and pnpm locks (and reject malformed lockfiles) so both get
real fail-closed registry coverage.
plugin create— scaffolder output adaptsto the project's detected package manager, preserving it during detection.
Consolidation note
Previously stacked as #593 → #598 → #600. Folded into this single PR
(11 commits, phase 1 → 2 → 3) and rebased onto latest
main. #598 and #600are closed as superseded by this PR.
This pull request and its description were written by Isaac.