wyvrnpm 2.21.0 → 2.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/bin/wyvrnpm.js +2 -2
- package/claude/agents/README.md +159 -0
- package/claude/agents/wyvrnpm-onboarding.md +131 -0
- package/package.json +2 -1
- package/src/commands/install-skill.js +90 -8
package/README.md
CHANGED
|
@@ -773,10 +773,13 @@ Useful for: auditing consumer uploads (who pushed this artefact, from which comm
|
|
|
773
773
|
|
|
774
774
|
### `wyvrnpm install-skill`
|
|
775
775
|
|
|
776
|
-
Installs the bundled
|
|
776
|
+
Installs the bundled Claude Code assets that ship inside the npm package:
|
|
777
|
+
|
|
778
|
+
- The **wyvrnpm Agent Skill** — the authoring guide Claude uses when it sees a `wyvrn.json` in the workspace. Ships as a `.skill` zip (`claude/skills/wyvrnpm.skill`), extracted into `~/.claude/skills/wyvrnpm/`.
|
|
779
|
+
- The **onboarding agent(s)** — e.g. `wyvrnpm-onboarding`, which sets up a project to consume wyvrnpm deps or converts an existing CMake project into a wyvrnpm package. Ships as Markdown (`claude/agents/*.md`), copied into `~/.claude/agents/`.
|
|
777
780
|
|
|
778
781
|
```bash
|
|
779
|
-
# One-shot: install the bundled skill for Claude Code
|
|
782
|
+
# One-shot: install the bundled skill + agent(s) for Claude Code
|
|
780
783
|
wyvrnpm install-skill --claude
|
|
781
784
|
|
|
782
785
|
# Overwrite an existing installation (e.g. after upgrading wyvrnpm)
|
|
@@ -786,7 +789,7 @@ wyvrnpm install-skill --claude --force
|
|
|
786
789
|
wyvrnpm install-skill --claude --dry-run
|
|
787
790
|
```
|
|
788
791
|
|
|
789
|
-
You only need this if you want Claude Code to pick up the skill. The CLI itself works without it.
|
|
792
|
+
You only need this if you want Claude Code to pick up the skill + agent. The CLI itself works without it.
|
|
790
793
|
|
|
791
794
|
**Options**
|
|
792
795
|
|
package/bin/wyvrnpm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -1127,7 +1127,7 @@ yargs
|
|
|
1127
1127
|
// ── install-skill ─────────────────────────────────────────────────────────
|
|
1128
1128
|
.command(
|
|
1129
1129
|
'install-skill',
|
|
1130
|
-
'Install the bundled wyvrnpm Agent Skill into Claude Code (~/.claude/skills/
|
|
1130
|
+
'Install the bundled wyvrnpm Agent Skill + onboarding agent(s) into Claude Code (~/.claude/skills/ + ~/.claude/agents/)',
|
|
1131
1131
|
(y) => {
|
|
1132
1132
|
y
|
|
1133
1133
|
.option('claude', { type: 'boolean', description: 'Install for Claude Code', default: false })
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# wyvrnpm Agents
|
|
2
|
+
|
|
3
|
+
Claude Code **subagents** that ship with wyvrnpm. A subagent is a separate
|
|
4
|
+
Claude worker with its own context window, tool access, and a clean return
|
|
5
|
+
boundary — you delegate a self-contained task to it and get back a result,
|
|
6
|
+
without the back-and-forth cluttering your main conversation.
|
|
7
|
+
|
|
8
|
+
These are distributed the same way as the wyvrnpm **skill**: the source lives
|
|
9
|
+
here under `claude/agents/`, and an active copy is placed in your user-global
|
|
10
|
+
`~/.claude/agents/` so Claude Code picks it up in every project.
|
|
11
|
+
|
|
12
|
+
> Skill vs. agent: the **skill** (`claude/skills/wyvrnpm/`) is *knowledge* — it
|
|
13
|
+
> teaches Claude how wyvrnpm works. An **agent** is an *execution context* that
|
|
14
|
+
> does a job, loading the skill for reference. The onboarding agent below uses
|
|
15
|
+
> the skill; it does not replace it.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## `wyvrnpm-onboarding`
|
|
20
|
+
|
|
21
|
+
### What it is
|
|
22
|
+
|
|
23
|
+
A guided agent that gets a C++ developer who is **new to wyvrnpm** productive in
|
|
24
|
+
one shot. It handles two distinct goals and figures out which one you want:
|
|
25
|
+
|
|
26
|
+
| Mode | Goal | What it does |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| **A — Consume** | "I want to *use* libraries from our team registry in this project." | Configures the install source + profile, writes `wyvrn.json`, runs `wyvrnpm install`, wires your `CMakeLists.txt` (`wyvrnpm_find_dependencies()`, `wyvrn::<dep>` links, runtime-DLL copy), and confirms the build configures. |
|
|
29
|
+
| **B — Convert / publish** | "I want to turn *this* library into a wyvrnpm package others can depend on." | Reads your `CMakeLists.txt`, picks `kind` / `options` / a `build` recipe, writes `wyvrn.json` + `.wyvrnignore`, then **verifies** by running `wyvrnpm install` and `wyvrnpm build --install --all-configs` across all four configs. Hands you a ready-to-run `publish` command — it never publishes itself. |
|
|
30
|
+
|
|
31
|
+
### Why it exists
|
|
32
|
+
|
|
33
|
+
wyvrnpm has no central registry and a few first-day gotchas (4-part versions,
|
|
34
|
+
profile hashes, per-config install trees, `.wyvrnignore`). This agent removes
|
|
35
|
+
the "I don't know where to start" barrier so teammates can adopt the tool
|
|
36
|
+
without reading the full docs first.
|
|
37
|
+
|
|
38
|
+
### Prerequisites
|
|
39
|
+
|
|
40
|
+
- **wyvrnpm installed:** `npm i -g wyvrnpm` (Node.js ≥ 18). The agent checks
|
|
41
|
+
this first and stops if it's missing.
|
|
42
|
+
- **For Mode A (consume):** your team's install source URL (an S3 bucket, HTTPS
|
|
43
|
+
endpoint, or file/SMB share). The agent will configure it for you if it isn't
|
|
44
|
+
already — wyvrnpm has no default registry, so this is required to fetch
|
|
45
|
+
anything.
|
|
46
|
+
- **Claude Code**, with the agent installed (see below).
|
|
47
|
+
|
|
48
|
+
### Install / make it active
|
|
49
|
+
|
|
50
|
+
The agent file is a single Markdown file with YAML frontmatter. Put a copy where
|
|
51
|
+
Claude Code looks for agents:
|
|
52
|
+
|
|
53
|
+
The supported path is the wyvrnpm CLI — `install-skill` installs the bundled
|
|
54
|
+
agent(s) alongside the skill:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm i -g wyvrnpm
|
|
58
|
+
wyvrnpm install-skill --claude # installs skill -> ~/.claude/skills/
|
|
59
|
+
# AND agent(s) -> ~/.claude/agents/
|
|
60
|
+
wyvrnpm install-skill --claude --force # overwrite after upgrading wyvrnpm
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or copy the file by hand:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Personal — available in every project on your machine:
|
|
67
|
+
mkdir -p ~/.claude/agents
|
|
68
|
+
cp claude/agents/wyvrnpm-onboarding.md ~/.claude/agents/
|
|
69
|
+
|
|
70
|
+
# OR project-local — shared with everyone who clones that repo:
|
|
71
|
+
mkdir -p <your-repo>/.claude/agents
|
|
72
|
+
cp claude/agents/wyvrnpm-onboarding.md <your-repo>/.claude/agents/
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Claude Code picks it up on the next session start.
|
|
76
|
+
|
|
77
|
+
### How to use it
|
|
78
|
+
|
|
79
|
+
**Implicitly** — just describe an onboarding task while you're in a C++ repo and
|
|
80
|
+
Claude routes to the agent:
|
|
81
|
+
|
|
82
|
+
- "Set up wyvrnpm in this project."
|
|
83
|
+
- "Add wyvrnpm and pull in `fmt` and `spdlog`."
|
|
84
|
+
- "Convert this library into a wyvrnpm package."
|
|
85
|
+
- "Make this repo publishable on our registry."
|
|
86
|
+
- "How do I start with wyvrnpm here?"
|
|
87
|
+
|
|
88
|
+
**Explicitly** — name it: *"Use the wyvrnpm-onboarding agent to set this up."*
|
|
89
|
+
|
|
90
|
+
If it can't tell whether you want Mode A or Mode B, it asks one short question
|
|
91
|
+
rather than guessing.
|
|
92
|
+
|
|
93
|
+
### What you get back
|
|
94
|
+
|
|
95
|
+
Every run ends with:
|
|
96
|
+
|
|
97
|
+
1. A summary — which mode it ran, the files it created/changed, and what it
|
|
98
|
+
**verified** (e.g. "install OK; all 4 configs built + installed").
|
|
99
|
+
2. The single next command to run yourself — for Mode B that's the exact
|
|
100
|
+
`wyvrnpm publish …` line plus the pre-publish checklist; for Mode A it's
|
|
101
|
+
"you're ready to build."
|
|
102
|
+
3. If something failed: the specific error and how it was fixed, or what's still
|
|
103
|
+
blocked. It won't claim success on an unvalidated manifest.
|
|
104
|
+
|
|
105
|
+
### Safety — it never writes to your team's registry
|
|
106
|
+
|
|
107
|
+
Onboarding is meant to be safe to run. The agent will **not** run any command
|
|
108
|
+
that writes to shared team state without your explicit confirmation:
|
|
109
|
+
|
|
110
|
+
- `wyvrnpm publish` / `publish --force` — it always stops here and hands the
|
|
111
|
+
command back to you.
|
|
112
|
+
- `wyvrnpm install --upload-built` — also a registry write.
|
|
113
|
+
- `wyvrnpm configure remove-source`.
|
|
114
|
+
|
|
115
|
+
Everything else it runs is local and reversible (`install`, `build`, `clean`,
|
|
116
|
+
`init`, `bootstrap`, `show`, `link`, profile/source *reads*). For
|
|
117
|
+
`configure add-source` it shows you the URL/credentials before writing them.
|
|
118
|
+
|
|
119
|
+
### Example
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
You (in an app repo): "set up wyvrnpm here and add fmt"
|
|
123
|
+
|
|
124
|
+
Agent:
|
|
125
|
+
• wyvrnpm --version → 2.21.0 ✓
|
|
126
|
+
• No install source configured — what's your team's registry URL?
|
|
127
|
+
You: https://pkg.example.com/cpp
|
|
128
|
+
Agent:
|
|
129
|
+
• configure add-source --kind install --name primary --url https://pkg.example.com/cpp
|
|
130
|
+
• profile detect → saved "default" (Windows / x86_64 / msvc 193 / C++20)
|
|
131
|
+
• wyvrnpm init → wyvrn.json (kind: ConsoleApp)
|
|
132
|
+
• wyvrnpm add fmt → "^10.x"
|
|
133
|
+
• wyvrnpm install → downloaded fmt, generated toolchain + CMakePresets.json
|
|
134
|
+
• patched CMakeLists.txt: wyvrnpm_find_dependencies();
|
|
135
|
+
target_link_libraries(MyApp PRIVATE wyvrn::fmt); wyvrnpm_finalize_targets()
|
|
136
|
+
• cmake --preset wyvrn-default → configured OK
|
|
137
|
+
|
|
138
|
+
Summary: consuming mode. fmt wired in and the build configures.
|
|
139
|
+
Next: wyvrnpm build
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Customizing
|
|
143
|
+
|
|
144
|
+
The agent is just `wyvrnpm-onboarding.md`. Edit the frontmatter to change:
|
|
145
|
+
|
|
146
|
+
- `model:` — defaults to `sonnet` (cheap/fast for procedural work); bump to
|
|
147
|
+
`opus` for trickier conversions.
|
|
148
|
+
- `tools:` — the allowlist (`Read, Grep, Glob, Edit, Write, Bash, Skill`).
|
|
149
|
+
|
|
150
|
+
The body is the system prompt; it loads the `wyvrnpm` skill for authoritative
|
|
151
|
+
command and manifest detail, so keep the two in sync.
|
|
152
|
+
|
|
153
|
+
### Out of scope
|
|
154
|
+
|
|
155
|
+
It deliberately does **not**: publish for you, set up CI pipelines, or handle
|
|
156
|
+
cross-compilation / recipe revisions (features not yet shipped). For deep
|
|
157
|
+
manifest, command, or diagnostic questions it defers to the `wyvrnpm` skill and
|
|
158
|
+
the user docs (README / the Confluence "Wyvrn Package Manager" and "WyvrnPM
|
|
159
|
+
Cmake Utils" pages).
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wyvrnpm-onboarding
|
|
3
|
+
description: >-
|
|
4
|
+
Onboard a C++ project onto wyvrnpm. Use this agent when someone wants to adopt
|
|
5
|
+
wyvrnpm and is not yet familiar with it — either (A) SET UP a new or existing
|
|
6
|
+
project to CONSUME wyvrnpm dependencies, or (B) CONVERT an existing CMake
|
|
7
|
+
project into a publishable wyvrnpm package. Triggers on "set up wyvrnpm here",
|
|
8
|
+
"add wyvrnpm to my project", "use wyvrnpm for my deps", "convert this to
|
|
9
|
+
wyvrnpm", "make this a wyvrnpm package", "how do I start with wyvrnpm", or a
|
|
10
|
+
teammate opening a C++ repo that has no wyvrn.json yet and asking to get going.
|
|
11
|
+
Drives the end-to-end flow — manifest, install, CMake wiring, and per-config
|
|
12
|
+
build verification — and STOPS before any registry-writing publish.
|
|
13
|
+
tools: Read, Grep, Glob, Edit, Write, Bash, Skill
|
|
14
|
+
model: sonnet
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
You are the wyvrnpm onboarding guide. Your job is to get a C++ developer who is
|
|
18
|
+
**new to wyvrnpm** productive: either consuming dependencies through it, or
|
|
19
|
+
turning their project into a publishable wyvrnpm package. Assume the person does
|
|
20
|
+
not know wyvrnpm yet — explain briefly as you go, and prefer running the safe
|
|
21
|
+
commands for them over telling them to run things.
|
|
22
|
+
|
|
23
|
+
wyvrnpm is a private, registry-less C++ package manager (a Node.js CLI,
|
|
24
|
+
`npm i -g wyvrnpm`). It publishes/consumes prebuilt C++ artefacts through static
|
|
25
|
+
hosting (S3 / HTTP / local dir / SMB). Every artefact is addressed by
|
|
26
|
+
`(name, version, profileHash)` where the hash encodes the toolchain profile +
|
|
27
|
+
package options, so ABI compatibility is explicit. Versions are 4-part
|
|
28
|
+
`major.minor.patch.build`.
|
|
29
|
+
|
|
30
|
+
## First, always
|
|
31
|
+
|
|
32
|
+
1. **Load the `wyvrnpm` skill** (invoke it via the Skill tool). It is the
|
|
33
|
+
authoritative reference for manifest fields, commands, and diagnostics. This
|
|
34
|
+
prompt is the orchestration; the skill is the detail. When the skill and this
|
|
35
|
+
prompt disagree, trust the skill, then the live tool output.
|
|
36
|
+
2. **Check the tool is installed:** run `wyvrnpm --version`. If it's missing,
|
|
37
|
+
tell them to `npm i -g wyvrnpm` (Node ≥ 18) and stop until it's available.
|
|
38
|
+
3. **Detect the mode** (see below). If it's genuinely ambiguous, ask one short
|
|
39
|
+
question — do not guess.
|
|
40
|
+
|
|
41
|
+
## Pick the mode
|
|
42
|
+
|
|
43
|
+
There are two distinct goals. Figure out which one applies before doing anything:
|
|
44
|
+
|
|
45
|
+
- **A — CONSUME** (most common for app/teammate onboarding): "I want to *use*
|
|
46
|
+
C++ libraries from our team registry in this project." → you'll add
|
|
47
|
+
`dependencies`, run `install`, and wire CMake so `find_package` works.
|
|
48
|
+
- **B — CONVERT/PUBLISH**: "I want to turn *this* library into a wyvrnpm package
|
|
49
|
+
others can depend on." → you'll write a `kind` + `build` recipe + options,
|
|
50
|
+
build all configs, and hand back a ready-to-run `publish` (you never publish).
|
|
51
|
+
|
|
52
|
+
Signals: a project with `add_executable` that wants third-party libs → usually A.
|
|
53
|
+
An existing OSS/library repo (`add_library`, has a public `include/`) they want
|
|
54
|
+
to share → usually B. If both could apply, ask.
|
|
55
|
+
|
|
56
|
+
## Mode A — set up a project to consume wyvrnpm deps
|
|
57
|
+
|
|
58
|
+
1. **Install source.** Run `wyvrnpm configure list`. If no install source is
|
|
59
|
+
configured, explain that wyvrnpm has no default registry and ask them for the
|
|
60
|
+
team's source URL, then `wyvrnpm configure add-source --kind install --name
|
|
61
|
+
<name> --url <url>` (show the URL/credentials before writing). Without a
|
|
62
|
+
source, `install` can't fetch anything.
|
|
63
|
+
2. **Profile.** Run `wyvrnpm configure profile show`. If none is saved, run
|
|
64
|
+
`wyvrnpm configure profile detect` (saves "default") so artefacts resolve to
|
|
65
|
+
their machine's toolchain.
|
|
66
|
+
3. **Manifest.** If there's no `wyvrn.json`, run `wyvrnpm init` (or copy a
|
|
67
|
+
per-kind template from the skill's `templates/`). Set `name`, a 4-part
|
|
68
|
+
`version`, and `kind` (usually `ConsoleApp`).
|
|
69
|
+
4. **Add deps.** For each library they want, `wyvrnpm add <name>` (resolves
|
|
70
|
+
latest, writes a caret range) or `wyvrnpm add <name>@<version>`.
|
|
71
|
+
5. **Install.** `wyvrnpm install`. This downloads to `wyvrn_internal/`, writes
|
|
72
|
+
`wyvrn.lock`, and generates the CMake toolchain + `CMakePresets.json`.
|
|
73
|
+
6. **Wire CMake.** In their top-level `CMakeLists.txt`, after `project()`:
|
|
74
|
+
call `wyvrnpm_find_dependencies()`, then `target_link_libraries(<tgt> PRIVATE
|
|
75
|
+
wyvrn::<dep> ...)`, and `wyvrnpm_finalize_targets()` at the end (copies
|
|
76
|
+
runtime DLLs on Windows). Configure via the generated preset:
|
|
77
|
+
`cmake --preset wyvrn-default` then `wyvrnpm build`. For the full toolchain
|
|
78
|
+
model and the `WYVRN_*` variables/macros, point them at the team's
|
|
79
|
+
"WyvrnPM Cmake Utils" doc.
|
|
80
|
+
7. **gitignore.** Ensure `wyvrn_internal/`, `wyvrn.lock`, `wyvrn.local.json`,
|
|
81
|
+
`build/`, `*.zip` are ignored.
|
|
82
|
+
8. **Verify** the build configures and links, then summarize.
|
|
83
|
+
|
|
84
|
+
## Mode B — convert an existing CMake project into a wyvrnpm package
|
|
85
|
+
|
|
86
|
+
Follow the skill's "convert-a-project flow" exactly. The deliverable is a
|
|
87
|
+
**validated** package, not just a `wyvrn.json`:
|
|
88
|
+
|
|
89
|
+
1. **Read the existing `CMakeLists.txt`** to choose `kind`
|
|
90
|
+
(`HeaderOnlyLib` / `StaticLib` / `DynamicLib`), declare `options` only for
|
|
91
|
+
real ABI-affecting toggles, and write a `build` recipe. For known OSS,
|
|
92
|
+
`wyvrnpm bootstrap <git-url>` drafts a first-pass manifest (clones, detects
|
|
93
|
+
kind, applies cookbook flags) — review and correct it.
|
|
94
|
+
2. **`build.configs` defaults to all four:**
|
|
95
|
+
`["Debug","Release","RelWithDebInfo","MinSizeRel"]` (note the spelling —
|
|
96
|
+
`RelWithDebInfo`). Restrict only with a concrete reason.
|
|
97
|
+
3. **Write `.wyvrnignore`** next to `wyvrn.json` — `publish` zips the whole
|
|
98
|
+
project tree, so exclude tests/examples/docs/`build/`/CI. A HeaderOnlyLib zip
|
|
99
|
+
should be well under 1 MB.
|
|
100
|
+
4. **`wyvrnpm install`** in the project root — surfaces manifest errors fast.
|
|
101
|
+
5. **`wyvrnpm build --install --all-configs`** — `--install` is mandatory; plain
|
|
102
|
+
build doesn't populate the install tree (headers + libs + `*Config.cmake`)
|
|
103
|
+
that consumers' `find_package` needs. All four configs must complete.
|
|
104
|
+
6. **Diagnose any failure** (skill's diagnostics reference) and fix the manifest
|
|
105
|
+
— don't paper over a broken config.
|
|
106
|
+
7. **STOP before `wyvrnpm publish`.** Hand back the exact `publish` command plus
|
|
107
|
+
the pre-publish checklist (changes committed, branch pushed, right profile,
|
|
108
|
+
`--source` explicit). The human runs it.
|
|
109
|
+
|
|
110
|
+
## Hard safety rails (never violate)
|
|
111
|
+
|
|
112
|
+
These write to **shared team state** and need the human's explicit yes — never
|
|
113
|
+
run them yourself as part of onboarding:
|
|
114
|
+
|
|
115
|
+
- `wyvrnpm publish` / `publish --force` — registry writes other teammates see.
|
|
116
|
+
- `wyvrnpm install --upload-built` — also a registry write.
|
|
117
|
+
- `wyvrnpm configure remove-source` — confirm first.
|
|
118
|
+
|
|
119
|
+
Safe to run without asking (local, reversible): `install` (no `--upload-built`),
|
|
120
|
+
`build`, `clean`, `show`, `link`/`unlink`, `init`, `bootstrap`, `configure list`
|
|
121
|
+
/ `profile show` / `profile detect`. For `configure add-source`, show the URL +
|
|
122
|
+
any credentials before writing.
|
|
123
|
+
|
|
124
|
+
## Finish every run with
|
|
125
|
+
|
|
126
|
+
- A short summary: which mode you ran, the files you created/changed, and what
|
|
127
|
+
you verified (e.g. "install OK; all 4 configs built + installed").
|
|
128
|
+
- The single exact next command the human should run (for Mode B, the
|
|
129
|
+
`wyvrnpm publish ...` line), or "you're ready to build" for Mode A.
|
|
130
|
+
- If anything failed, the specific error and what you changed to fix it (or what
|
|
131
|
+
remains blocked). Be honest — an unvalidated manifest is worth less than none.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wyvrnpm",
|
|
3
|
-
"version": "2.21.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"description": "A simple, static-hosting-compatible C++ package manager",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"c++",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"src/",
|
|
22
22
|
"cmake/",
|
|
23
23
|
"claude/skills/wyvrnpm.skill",
|
|
24
|
+
"claude/agents/",
|
|
24
25
|
"README.md"
|
|
25
26
|
],
|
|
26
27
|
"scripts": {
|
|
@@ -11,16 +11,19 @@ const log = require('../logger');
|
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
// `wyvrnpm install-skill --claude`
|
|
13
13
|
//
|
|
14
|
-
// Copies the bundled wyvrnpm Agent Skill (claude/skills/wyvrnpm.skill)
|
|
15
|
-
// the user's Claude Code
|
|
14
|
+
// Copies the bundled wyvrnpm Agent Skill (claude/skills/wyvrnpm.skill) AND the
|
|
15
|
+
// bundled onboarding agents (claude/agents/*.md) into the user's Claude Code
|
|
16
|
+
// directories so Claude picks them up automatically.
|
|
16
17
|
//
|
|
17
18
|
// Works for both install shapes:
|
|
18
|
-
// - `npm i -g wyvrnpm` →
|
|
19
|
+
// - `npm i -g wyvrnpm` → assets ship under <pkg>/claude/
|
|
19
20
|
// - `git clone` of this repo → same path, just not from node_modules
|
|
20
21
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
22
|
+
// Destinations, per target (--claude):
|
|
23
|
+
// skill → %USERPROFILE%\.claude\skills\wyvrnpm\ (Windows)
|
|
24
|
+
// ~/.claude/skills/wyvrnpm/ (macOS / Linux)
|
|
25
|
+
// agents → %USERPROFILE%\.claude\agents\ (Windows)
|
|
26
|
+
// ~/.claude/agents/ (macOS / Linux)
|
|
24
27
|
// ---------------------------------------------------------------------------
|
|
25
28
|
|
|
26
29
|
const SKILL_NAME = 'wyvrnpm';
|
|
@@ -31,18 +34,94 @@ function bundledSkillPath() {
|
|
|
31
34
|
return path.resolve(__dirname, '..', '..', 'claude', 'skills', `${SKILL_NAME}.skill`);
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
function bundledAgentsDir() {
|
|
38
|
+
// __dirname = <pkg>/src/commands; agent definitions live at
|
|
39
|
+
// <pkg>/claude/agents/*.md (README.md excluded — it's docs, not an agent).
|
|
40
|
+
return path.resolve(__dirname, '..', '..', 'claude', 'agents');
|
|
41
|
+
}
|
|
42
|
+
|
|
34
43
|
function claudeSkillsDir() {
|
|
35
44
|
const home = os.homedir();
|
|
36
45
|
if (!home) throw new Error('cannot resolve user home directory');
|
|
37
46
|
return path.join(home, '.claude', 'skills');
|
|
38
47
|
}
|
|
39
48
|
|
|
49
|
+
function claudeAgentsDir() {
|
|
50
|
+
const home = os.homedir();
|
|
51
|
+
if (!home) throw new Error('cannot resolve user home directory');
|
|
52
|
+
return path.join(home, '.claude', 'agents');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Bundled agent-definition files to install — every `*.md` under
|
|
57
|
+
* `claude/agents/` except `README.md` (which is human docs, not an agent
|
|
58
|
+
* definition and would parse as a nameless agent). Returns absolute paths.
|
|
59
|
+
*
|
|
60
|
+
* @returns {string[]}
|
|
61
|
+
*/
|
|
62
|
+
function bundledAgentFiles() {
|
|
63
|
+
const dir = bundledAgentsDir();
|
|
64
|
+
if (!fs.existsSync(dir)) return [];
|
|
65
|
+
return fs.readdirSync(dir)
|
|
66
|
+
.filter((f) => f.endsWith('.md') && f.toLowerCase() !== 'readme.md')
|
|
67
|
+
.sort()
|
|
68
|
+
.map((f) => path.join(dir, f));
|
|
69
|
+
}
|
|
70
|
+
|
|
40
71
|
function rmrf(target) {
|
|
41
72
|
if (!fs.existsSync(target)) return;
|
|
42
73
|
fs.rmSync(target, { recursive: true, force: true });
|
|
43
74
|
}
|
|
44
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Install the bundled onboarding agents into ~/.claude/agents/. Unlike the
|
|
78
|
+
* skill, agents are independent plain-Markdown files, so this never aborts
|
|
79
|
+
* the run: an already-present agent is skipped (with a hint) unless --force,
|
|
80
|
+
* and the rest still install. Dry-run reports without writing.
|
|
81
|
+
*
|
|
82
|
+
* @param {{ force: boolean, dryRun: boolean }} opts
|
|
83
|
+
*/
|
|
84
|
+
function installAgentsForClaude({ force, dryRun }) {
|
|
85
|
+
const agentFiles = bundledAgentFiles();
|
|
86
|
+
if (agentFiles.length === 0) {
|
|
87
|
+
log.info('No bundled agents to install.');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const destDir = claudeAgentsDir();
|
|
92
|
+
log.info(`Agents : ${destDir}`);
|
|
93
|
+
|
|
94
|
+
if (dryRun) {
|
|
95
|
+
for (const src of agentFiles) {
|
|
96
|
+
log.info(`(--dry-run) would install agent ${path.basename(src)} → ${destDir}`);
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
102
|
+
let installed = 0;
|
|
103
|
+
for (const src of agentFiles) {
|
|
104
|
+
const name = path.basename(src);
|
|
105
|
+
const dest = path.join(destDir, name);
|
|
106
|
+
if (fs.existsSync(dest) && !force) {
|
|
107
|
+
log.warn(`agent ${name} already installed — re-run with --force to overwrite`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
fs.copyFileSync(src, dest);
|
|
111
|
+
installed += 1;
|
|
112
|
+
log.success(`Installed agent ${name} → ${dest}`);
|
|
113
|
+
}
|
|
114
|
+
if (installed > 0) {
|
|
115
|
+
log.info('Claude Code will pick up the agent(s) on next session start.');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
45
119
|
function installForClaude({ force, dryRun }) {
|
|
120
|
+
installSkillForClaude({ force, dryRun });
|
|
121
|
+
installAgentsForClaude({ force, dryRun });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function installSkillForClaude({ force, dryRun }) {
|
|
46
125
|
const zipPath = bundledSkillPath();
|
|
47
126
|
if (!fs.existsSync(zipPath)) {
|
|
48
127
|
log.error(`bundled skill not found at ${zipPath}`);
|
|
@@ -111,5 +190,8 @@ async function installSkill(argv) {
|
|
|
111
190
|
}
|
|
112
191
|
|
|
113
192
|
module.exports = installSkill;
|
|
114
|
-
module.exports.bundledSkillPath
|
|
115
|
-
module.exports.claudeSkillsDir
|
|
193
|
+
module.exports.bundledSkillPath = bundledSkillPath;
|
|
194
|
+
module.exports.claudeSkillsDir = claudeSkillsDir;
|
|
195
|
+
module.exports.bundledAgentsDir = bundledAgentsDir;
|
|
196
|
+
module.exports.claudeAgentsDir = claudeAgentsDir;
|
|
197
|
+
module.exports.bundledAgentFiles = bundledAgentFiles;
|