Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .agents/skills/nodejs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
name: nodejs
description: 'Node.js and npm via system packages (RPM/DEB) with global npm prefix.

Use when working with Node.js, npm, or JavaScript/TypeScript tooling.'
---

# nodejs -- Node.js and npm runtime

## Candy Properties

| Property | Value |
|----------|-------|
| Install files | `charly.yml`, `task:` |

## Environment Variables

| Variable | Value |
|----------|-------|
| `NPM_CONFIG_PREFIX` | `~/.npm-global` |
| `npm_config_cache` | `~/.cache/npm` |

PATH additions: `~/.npm-global/bin`

## Packages

RPM: `nodejs`, `npm`
DEB: `nodejs` (NodeSource node 22.x on Ubuntu + Debian; npm is bundled
by NodeSource, not the separate apt `npm` package)
PAC: `nodejs`, `npm`

## pnpm (standalone binary)

The candy installs the **pnpm** standalone binary (self-contained — it bundles
its own node) to `/usr/local/bin/pnpm` via a `task:` download. It is deliberately
NOT a `package.json` dependency: a `package.json` would trigger the npm
multi-stage builder on this candy, and the builder images that COMPOSE nodejs
(`arch-builder` / `fedora-builder`) cannot self-provide the npm builder. The
binary on `/usr/local/bin` is on the default system PATH for every user (incl.
root — Immich runs its pnpm build as root). Immich and other pnpm consumers use
this pnpm to drive their build.

### The pin and a consumer's `allowBuilds` KEY FORM are a COUPLED PAIR

pnpm >= 10 blocks a dependency's build/install scripts unless it is allowlisted,
and for a **git-specifier** dependency the KEY FORM of that allowlist entry is
version-coupled: the two forms fail on each other's pin, so no single form works
at both. MEASURED in the real build image (Fedora 43, node 22.22.2) against
pod-dsh's `dsh-web` profile — `opencharly/layer-nodejs#5`:

| `allowBuilds` key form | pnpm `10.33.4` | pnpm `10.34.6` |
|---|---|---|
| bare name — `"@perrylink/dsh-github": true` | PASS | `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` |
| fully-qualified URL key — `"@perrylink/dsh-github@https://codeload.github.com/<owner>/<repo>/.git": true` | `ERR_PNPM_INVALID_VERSION_UNION` | PASS |

A wrong pair hard-fails the consumer's profile install at IMAGE BUILD time. So
`PNPM_VERSION`, `PNPM_ALLOWBUILDS_GIT_KEY_FORM` and the two PROBED_* constants move
together, and the candy's own
`check: the pinned pnpm version's allowBuilds git-key form matches the recorded measurement`
makes a bump that forgets them RED instead of a hard-failed consumer build. Only the
two probed versions are accepted: a bump to any other pin must RE-MEASURE the form and
record it. (pod-dsh vendored its git-hosted plugins as prebuilt `file:` tarballs in
pod-dsh#28, so no git dep remains there today — the rule still binds any consumer
that pins one.)

## Usage

```yaml
# charly.yml
my-image:
candy:
- nodejs
```

## Used In Boxes

- `/charly-distros:fedora-builder`
- `/charly-distros:arch-builder`
- Transitive dependency for `openclaw`, `pre-commit`, and other candies

## Related Candies

- `/charly-coder:pre-commit` -- depends on nodejs
- `/charly-immich:immich-layer` -- uses the candy's pnpm to build Immich

## When to Use This Skill

Use when the user asks about:

- Node.js or npm setup in containers
- Global npm package installation
- The `nodejs` candy or npm configuration

## Related

- `/charly-image:layer` — candy authoring reference (`charly.yml` schema, task verbs, service declarations)
- `/charly-check:check` — declarative testing (`check:` block, `charly check box`, `charly check live`)
91 changes: 0 additions & 91 deletions charly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,94 +192,3 @@ nodejs-skill:
description: |-
Node.js and npm via system packages (RPM/DEB) with global npm prefix.
Use when working with Node.js, npm, or JavaScript/TypeScript tooling.
content: |-
# nodejs -- Node.js and npm runtime

## Candy Properties

| Property | Value |
|----------|-------|
| Install files | `charly.yml`, `task:` |

## Environment Variables

| Variable | Value |
|----------|-------|
| `NPM_CONFIG_PREFIX` | `~/.npm-global` |
| `npm_config_cache` | `~/.cache/npm` |

PATH additions: `~/.npm-global/bin`

## Packages

RPM: `nodejs`, `npm`
DEB: `nodejs` (NodeSource node 22.x on Ubuntu + Debian; npm is bundled
by NodeSource, not the separate apt `npm` package)
PAC: `nodejs`, `npm`

## pnpm (standalone binary)

The candy installs the **pnpm** standalone binary (self-contained — it bundles
its own node) to `/usr/local/bin/pnpm` via a `task:` download. It is deliberately
NOT a `package.json` dependency: a `package.json` would trigger the npm
multi-stage builder on this candy, and the builder images that COMPOSE nodejs
(`arch-builder` / `fedora-builder`) cannot self-provide the npm builder. The
binary on `/usr/local/bin` is on the default system PATH for every user (incl.
root — Immich runs its pnpm build as root). Immich and other pnpm consumers use
this pnpm to drive their build.

### The pin and a consumer's `allowBuilds` KEY FORM are a COUPLED PAIR

pnpm >= 10 blocks a dependency's build/install scripts unless it is allowlisted,
and for a **git-specifier** dependency the KEY FORM of that allowlist entry is
version-coupled: the two forms fail on each other's pin, so no single form works
at both. MEASURED in the real build image (Fedora 43, node 22.22.2) against
pod-dsh's `dsh-web` profile — `opencharly/layer-nodejs#5`:

| `allowBuilds` key form | pnpm `10.33.4` | pnpm `10.34.6` |
|---|---|---|
| bare name — `"@perrylink/dsh-github": true` | PASS | `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` |
| fully-qualified URL key — `"@perrylink/dsh-github@https://codeload.github.com/<owner>/<repo>/.git": true` | `ERR_PNPM_INVALID_VERSION_UNION` | PASS |

A wrong pair hard-fails the consumer's profile install at IMAGE BUILD time. So
`PNPM_VERSION`, `PNPM_ALLOWBUILDS_GIT_KEY_FORM` and the two PROBED_* constants move
together, and the candy's own
`check: the pinned pnpm version's allowBuilds git-key form matches the recorded measurement`
makes a bump that forgets them RED instead of a hard-failed consumer build. Only the
two probed versions are accepted: a bump to any other pin must RE-MEASURE the form and
record it. (pod-dsh vendored its git-hosted plugins as prebuilt `file:` tarballs in
pod-dsh#28, so no git dep remains there today — the rule still binds any consumer
that pins one.)

## Usage

```yaml
# charly.yml
my-image:
candy:
- nodejs
```

## Used In Boxes

- `/charly-distros:fedora-builder`
- `/charly-distros:arch-builder`
- Transitive dependency for `openclaw`, `pre-commit`, and other candies

## Related Candies

- `/charly-coder:pre-commit` -- depends on nodejs
- `/charly-immich:immich-layer` -- uses the candy's pnpm to build Immich

## When to Use This Skill

Use when the user asks about:

- Node.js or npm setup in containers
- Global npm package installation
- The `nodejs` candy or npm configuration

## Related

- `/charly-image:layer` — candy authoring reference (`charly.yml` schema, task verbs, service declarations)
- `/charly-check:check` — declarative testing (`check:` block, `charly check box`, `charly check live`)
Loading