@skill-map/cli 0.30.0 → 0.31.0
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/dist/cli/tutorial/sm-master/references/fixture-templates.md +206 -0
- package/dist/cli/tutorial/sm-master/references/tour-authoring.md +296 -0
- package/dist/cli/tutorial/sm-master/references/tour-plugins.md +209 -0
- package/dist/cli/tutorial/sm-master/references/tour-settings.md +170 -0
- package/dist/cli.js +71 -69
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.js +1 -1
- package/dist/kernel/index.js.map +1 -1
- package/dist/ui/{chunk-HOJFYUH4.js → chunk-PVKIT7DW.js} +4 -4
- package/dist/ui/index.html +1 -1
- package/dist/ui/{main-X5YGJFU6.js → main-N23S66NJ.js} +1 -1
- package/package.json +1 -1
- /package/dist/cli/tutorial/{sm-master.md → sm-master/SKILL.md} +0 -0
- /package/dist/cli/tutorial/{sm-tutorial.md → sm-tutorial/SKILL.md} +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Tour: plugins-tour
|
|
2
|
+
|
|
3
|
+
Guided tour of the **built-in plugins** that ship with `sm`. Three
|
|
4
|
+
steps: a quick mental model of what bundles are plus a peek at
|
|
5
|
+
the catalogue, then the six extension kinds rounded off by opening
|
|
6
|
+
one bundle to see them in the wild, and finally a deeper drill
|
|
7
|
+
into a single extension (detail view, diagnostic, disable/enable
|
|
8
|
+
toggle). By the end the tester has the mental model and knows
|
|
9
|
+
which verbs reach which surface.
|
|
10
|
+
|
|
11
|
+
## Precondition check
|
|
12
|
+
|
|
13
|
+
Before announcing the first step, verify the fixture is initialised
|
|
14
|
+
(the cwd has `.claude/agents/master-agent.md`,
|
|
15
|
+
`.claude/skills/master-skill/SKILL.md`, AND `.skill-map/` with
|
|
16
|
+
`settings.json` and `skill-map.db`). Pre-flight already ran
|
|
17
|
+
`sm init --no-scan` and appended the master entries to
|
|
18
|
+
`.skillmapignore`. If any of that is missing, surface the
|
|
19
|
+
bootstrap mismatch ("master-state.yml says we are running, but
|
|
20
|
+
the bootstrap is missing. Run `sm-master` from an empty dir or
|
|
21
|
+
restore the files.") and stop.
|
|
22
|
+
|
|
23
|
+
## Step `tour-1-intro` — how plugins work (~4 min)
|
|
24
|
+
|
|
25
|
+
**Context**: A short tour of what a plugin is, how they're
|
|
26
|
+
packaged into bundles, and a peek at the four bundles that ship
|
|
27
|
+
pre-installed.
|
|
28
|
+
|
|
29
|
+
> Plugins are how skill-map gets extended. A **plugin** groups one
|
|
30
|
+
> or more **extensions**, the actual code units that run inside
|
|
31
|
+
> the kernel. So when we say "skill-map has a plugin for Claude",
|
|
32
|
+
> what we really mean is "there is a plugin called `claude` that
|
|
33
|
+
> contains one extension (a provider) which knows how to walk
|
|
34
|
+
> `.claude/`".
|
|
35
|
+
>
|
|
36
|
+
> Plugins ship as **bundles**. A bundle is the deployable unit,
|
|
37
|
+
> one directory with a `plugin.json` manifest and the extension
|
|
38
|
+
> code. Two ways they reach your project:
|
|
39
|
+
>
|
|
40
|
+
> 📦 **Built-in bundles**
|
|
41
|
+
> Travel inside the CLI itself. Available the moment you
|
|
42
|
+
> `npm install -g @skill-map/cli`.
|
|
43
|
+
>
|
|
44
|
+
> 📥 **Drop-in bundles**
|
|
45
|
+
> You (your company, or someone else) drop them by hand under
|
|
46
|
+
> `<cwd>/.skill-map/plugins/`. The directory lives inside the
|
|
47
|
+
> project, so a bundle committed here travels with the repo
|
|
48
|
+
> and the rest of the team picks it up on the next pull.
|
|
49
|
+
|
|
50
|
+
> Now let's look at what's actually installed. `sm plugins list`
|
|
51
|
+
> shows every bundle the CLI shipped with. Run it in your second
|
|
52
|
+
> terminal:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
sm plugins list
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> There are the four bundles. The next step zooms into the six
|
|
59
|
+
> kinds of extension that bundles can carry, you'll see at least
|
|
60
|
+
> one of each living inside `core`.
|
|
61
|
+
|
|
62
|
+
Mark `tour-1-intro: done`.
|
|
63
|
+
|
|
64
|
+
## Step `tour-2-kinds` — the six extension kinds (~5 min)
|
|
65
|
+
|
|
66
|
+
> An extension has a **kind**. The kind tells the kernel where it
|
|
67
|
+
> plugs into the pipeline. There are exactly six kinds:
|
|
68
|
+
>
|
|
69
|
+
> 🗂️ **provider**
|
|
70
|
+
> Decides what kind each `.md` file is. The `claude` provider,
|
|
71
|
+
> for instance, walks `.claude/` and types each file it finds
|
|
72
|
+
> (agent, command, or skill).
|
|
73
|
+
> Examples: `claude`, `gemini`, `agent-skills`.
|
|
74
|
+
>
|
|
75
|
+
> 🔍 **extractor**
|
|
76
|
+
> Reads a node's body and emits structured findings (links,
|
|
77
|
+
> counts, annotations).
|
|
78
|
+
> Example: `markdown-link`, `external-url-counter`, `tools-count`.
|
|
79
|
+
>
|
|
80
|
+
> 🩺 **analyzer**
|
|
81
|
+
> Cross-checks the scan and emits issues plus various
|
|
82
|
+
> detections (errors, warnings, informational signals: broken
|
|
83
|
+
> refs, stale annotations, schema drift, and more).
|
|
84
|
+
> Example: `broken-ref`, `stability`, `unknown-field`.
|
|
85
|
+
>
|
|
86
|
+
> ⚡ **action**
|
|
87
|
+
> Performs a write operation on a node, the graph, or the
|
|
88
|
+
> filesystem. May modify your `.md` files (frontmatter, body)
|
|
89
|
+
> ONLY with your explicit permission.
|
|
90
|
+
> Examples: `bump`, `mark-superseded`.
|
|
91
|
+
>
|
|
92
|
+
> 🎨 **formatter**
|
|
93
|
+
> Renders a result in a specific shape (`sm export --format md`
|
|
94
|
+
> and `--format json`).
|
|
95
|
+
> Example: `ascii`, `json`.
|
|
96
|
+
>
|
|
97
|
+
> 🎣 **hook**
|
|
98
|
+
> Fires on one of 10 lifecycle events (`boot`, `scan.started`,
|
|
99
|
+
> `shutdown`, etc.). `update-check`, for instance, listens on
|
|
100
|
+
> `boot` (throttled to once a day) and prints a banner if a
|
|
101
|
+
> newer skill-map is available on npm.
|
|
102
|
+
> Example: `update-check`.
|
|
103
|
+
>
|
|
104
|
+
> Putting it together: a **bundle** packages one or more
|
|
105
|
+
> **extensions**, each extension has a **kind**, the kind decides
|
|
106
|
+
> where it plugs into the kernel.
|
|
107
|
+
>
|
|
108
|
+
> Heads up: every `sm plugins` verb you'll run in this tour is
|
|
109
|
+
> also available from the UI. From any `sm serve` session, open
|
|
110
|
+
> the **gear icon → Plugins** tab to browse and toggle plugins
|
|
111
|
+
> from there. CLI and UI use the same store, so a change in one
|
|
112
|
+
> is reflected in the other.
|
|
113
|
+
|
|
114
|
+
> Now let's see those six kinds inside a real bundle. Open `core`
|
|
115
|
+
> in your second terminal:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
sm plugins show core
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Expected: a table with 24 rows, each carrying `kind/id@version`.
|
|
122
|
+
You can spot at least one of each of the six kinds you just read
|
|
123
|
+
about, all packed into a single bundle.
|
|
124
|
+
|
|
125
|
+
Mark `tour-2-kinds: done`.
|
|
126
|
+
|
|
127
|
+
## Step `tour-3-explore` — explore one extension up close (~4 min)
|
|
128
|
+
|
|
129
|
+
**Context**: Drill into a single extension to see its detail,
|
|
130
|
+
run the diagnostic, then toggle one off and back on so you see
|
|
131
|
+
the change persists.
|
|
132
|
+
|
|
133
|
+
> Pick one extension and look at its details. We'll use
|
|
134
|
+
> `core/external-url-counter`, an extractor that counts how many
|
|
135
|
+
> external URLs each node body contains:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
sm plugins show core/external-url-counter
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Expected: a focused detail block for that one extension (header,
|
|
142
|
+
Kind, Version, Stability, Description, Preconditions, Entry).
|
|
143
|
+
|
|
144
|
+
> Now run the diagnostic. The `doctor` verb reports every plugin
|
|
145
|
+
> and extension status in one go: enabled, disabled, load errors,
|
|
146
|
+
> spec compatibility, manifest validity.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
sm plugins doctor
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Expected on a clean machine: `27 enabled · 0 issues · 0 warnings`.
|
|
153
|
+
If any plugin reports a load error, manifest validity issue, or
|
|
154
|
+
spec-compatibility mismatch, `doctor` is the verb that flags it.
|
|
155
|
+
|
|
156
|
+
> Last, toggle one extension off and back on so you see the state
|
|
157
|
+
> persists across CLI invocations. We'll use the same one you
|
|
158
|
+
> inspected above:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
sm plugins disable core/external-url-counter
|
|
162
|
+
sm plugins doctor
|
|
163
|
+
sm plugins enable core/external-url-counter
|
|
164
|
+
sm plugins doctor
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Expected: between the two `doctor` calls, the
|
|
168
|
+
`core/external-url-counter` row flips from `enabled` to
|
|
169
|
+
`disabled` and back. The change persists in the project DB; if
|
|
170
|
+
you restarted `sm`, the disabled state would still be there.
|
|
171
|
+
|
|
172
|
+
Mark `tour-3-explore: done`.
|
|
173
|
+
|
|
174
|
+
## Tour wrap-up
|
|
175
|
+
|
|
176
|
+
> All set. You now know:
|
|
177
|
+
>
|
|
178
|
+
> - What plugins, extensions, bundles, and the six kinds are.
|
|
179
|
+
> - Four bundles ship pre-installed (`claude`, `gemini`,
|
|
180
|
+
> `agent-skills`, `core`).
|
|
181
|
+
> - How to list, inspect, diagnose, and toggle extensions from
|
|
182
|
+
> the CLI (and the same lives in the UI).
|
|
183
|
+
>
|
|
184
|
+
> If you want to dig deeper, the next menu option takes you into
|
|
185
|
+
> authoring your own plugin and into settings + view-slots. Or
|
|
186
|
+
> if you've seen enough, "I'm done for today" closes us out.
|
|
187
|
+
>
|
|
188
|
+
> Anything weird worth logging? If not, back to the menu.
|
|
189
|
+
|
|
190
|
+
Mark tour `plugins-tour: done` in `master-state.yml`, update the
|
|
191
|
+
matching harness task, return to the menu in `SKILL.md`.
|
|
192
|
+
|
|
193
|
+
## Reference: how `sm` decides what to load
|
|
194
|
+
|
|
195
|
+
Not for the tester unless they ask. Cheat sheet for the agent:
|
|
196
|
+
|
|
197
|
+
- Built-in plugins live inside the CLI bundle and are always
|
|
198
|
+
discovered first.
|
|
199
|
+
- Project plugins live under `<cwd>/.skill-map/plugins/`; the
|
|
200
|
+
authoring tour uses this path. There is no user / global
|
|
201
|
+
scope, `-g/--global` and `~/.skill-map/plugins/` were removed
|
|
202
|
+
in v0.27.x.
|
|
203
|
+
- Load order: built-in → project (project ids that collide with
|
|
204
|
+
built-in are surfaced by `doctor`).
|
|
205
|
+
- `disable`/`enable` writes the state into the project DB; it
|
|
206
|
+
survives restarts.
|
|
207
|
+
- Escape hatch for one-off probing without committing a plugin to
|
|
208
|
+
the project: pass `--plugin-dir <path>` on the `sm plugins …`
|
|
209
|
+
verb family.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Tour: settings + slots (step library, `settings-*` ids)
|
|
2
|
+
|
|
3
|
+
Step bodies for two tours: option 2 (`settings-and-consent`,
|
|
4
|
+
runs `settings-1-project` and `settings-2-local`) and the
|
|
5
|
+
single shared step `settings-6-contributions` borrowed by
|
|
6
|
+
option 3 (`build-and-configure`). The SKILL.md orchestrator
|
|
7
|
+
dispatches each `settings-*` id here; `authoring-*` ids it
|
|
8
|
+
dispatches to `tour-authoring.md`.
|
|
9
|
+
|
|
10
|
+
## Precondition check
|
|
11
|
+
|
|
12
|
+
Same as the authoring step library: `.skill-map/` must exist in
|
|
13
|
+
the cwd (pre-flight step 4 of `SKILL.md` ran `sm init --no-scan`
|
|
14
|
+
and appended the master-tutorial's internal entries to
|
|
15
|
+
`.skillmapignore`, so this is the expected state). If
|
|
16
|
+
`.skill-map/` is missing, surface the bootstrap mismatch and
|
|
17
|
+
stop, do not try to re-init mid-tour.
|
|
18
|
+
|
|
19
|
+
## Step `settings-1-project` — project settings (~2 min)
|
|
20
|
+
|
|
21
|
+
> Every project that runs `sm init` gets a `.skill-map/`
|
|
22
|
+
> directory with two settings files. The first one is
|
|
23
|
+
> `settings.json`, this is the **public** project settings, the
|
|
24
|
+
> file you commit to git.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cat .skill-map/settings.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Expected output on a fresh init:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"schemaVersion": 1
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
> Minimal on purpose. The CLI keeps the file lean and only adds
|
|
39
|
+
> keys when you change a setting. Schema version is there so the
|
|
40
|
+
> CLI can migrate the shape forward without surprising you.
|
|
41
|
+
>
|
|
42
|
+
> The settings UI in the browser (the `Settings` tab when `sm` is
|
|
43
|
+
> running) writes back into this file. Anything you change in
|
|
44
|
+
> there ends up here, commit it to share the choice with the
|
|
45
|
+
> team.
|
|
46
|
+
|
|
47
|
+
Mark `settings-1-project: done`.
|
|
48
|
+
|
|
49
|
+
## Step `settings-2-local` — per-user overrides (~3 min)
|
|
50
|
+
|
|
51
|
+
> The second file is `settings.local.json`, which is **gitignored
|
|
52
|
+
> by default**. It exists for choices that should NOT travel
|
|
53
|
+
> across the team:
|
|
54
|
+
>
|
|
55
|
+
> - Whether you allowed `sm` to create `.sm` companion files in
|
|
56
|
+
> this project (the consent gate from the basic tutorial).
|
|
57
|
+
> - Personal token paths or credentials you do not want to
|
|
58
|
+
> commit.
|
|
59
|
+
> - Local preferences that depend on your dev environment.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cat .skill-map/settings.local.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Expected on a fresh init:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> Empty until something writes to it. The first thing that
|
|
72
|
+
> typically lands is `allowEditSmFiles: true` after you accept
|
|
73
|
+
> the `.sm` prompt (the consent gate is a per-user, per-project
|
|
74
|
+
> choice, that's why it goes here).
|
|
75
|
+
|
|
76
|
+
Before the demo, give the tester one sentence of context about
|
|
77
|
+
what a `.sm` file actually is (the basic tutorial introduces it
|
|
78
|
+
in passing, here we anchor the concept):
|
|
79
|
+
|
|
80
|
+
> Every `.md` skill-map tracks gets a sibling `.sm` file (e.g.
|
|
81
|
+
> `notes/ideas.sm` next to `notes/ideas.md`) that carries **all
|
|
82
|
+
> of the tool's metadata about that markdown, so your `.md`
|
|
83
|
+
> stays clean and uncluttered**. Version, history, tags,
|
|
84
|
+
> annotations, anything that does not belong in the
|
|
85
|
+
> human-authored body lives in the `.sm`. The `.md` is content
|
|
86
|
+
> you write for Claude or humans, the `.sm` is bookkeeping the
|
|
87
|
+
> tool writes. They are ordinary source files, committed to git,
|
|
88
|
+
> and you'll see them often once you start using `sm bump` /
|
|
89
|
+
> `sm sidecar annotate` day to day.
|
|
90
|
+
|
|
91
|
+
If the tester wants to see it in action: ask them to run
|
|
92
|
+
`sm sidecar annotate notes/ideas.md`, accept the `[Y/n]` prompt
|
|
93
|
+
with `y`, and re-check the file:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
sm sidecar annotate notes/ideas.md
|
|
97
|
+
cat .skill-map/settings.local.json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Expected: now contains `{"allowEditSmFiles": true}` (plus a
|
|
101
|
+
`notes/ideas.sm` file landed next to the markdown).
|
|
102
|
+
|
|
103
|
+
> The choice stuck. Next time `sm` wants to write a `.sm` in this
|
|
104
|
+
> project, it skips the prompt because your consent is on
|
|
105
|
+
> record. If you delete the file or move to a different project,
|
|
106
|
+
> the prompt comes back.
|
|
107
|
+
|
|
108
|
+
Mark `settings-2-local: done`.
|
|
109
|
+
|
|
110
|
+
## Step `settings-6-contributions` — watch contributions land (~2 min)
|
|
111
|
+
|
|
112
|
+
> Last step. Let's see a contribution land in the inspector
|
|
113
|
+
> live. The fixture's `master-agent` declares `tools: [Read,
|
|
114
|
+
> Bash, Edit]`, which the `core/tools-count` extractor picks up.
|
|
115
|
+
|
|
116
|
+
If the tester does not have `sm` running, ask them to launch it
|
|
117
|
+
in their second terminal (same drill as the basic tutorial:
|
|
118
|
+
`sm`, copy the link from the output, open the browser, arrange
|
|
119
|
+
the screen). If `sm` is still running, leave it.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
sm
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Once the UI is open, ask the tester to:
|
|
126
|
+
|
|
127
|
+
> Click the `master-agent` node. The inspector opens on the
|
|
128
|
+
> right side. Look at the **header badge cluster** (just under
|
|
129
|
+
> the title): you should see a small chip from `tools-count`
|
|
130
|
+
> showing the value `3`.
|
|
131
|
+
>
|
|
132
|
+
> That chip is a plugin contribution. It landed in the slot
|
|
133
|
+
> `inspector.header.badge.counter`, the renderer is `NodeCounter`
|
|
134
|
+
> (same one your scaffold uses), the payload was `{ value: 3 }`.
|
|
135
|
+
|
|
136
|
+
If the `demo-highlight` plugin from the earlier authoring steps
|
|
137
|
+
of this tour is still installed, point the tester at the
|
|
138
|
+
contribution it emits too:
|
|
139
|
+
|
|
140
|
+
> The `demo-highlight` you scaffolded earlier in this tour also
|
|
141
|
+
> shows up: its chip lands on every node that has a TODO / FIXME
|
|
142
|
+
> / XXX in its body. Click `notes/ideas` to find it.
|
|
143
|
+
|
|
144
|
+
Have the tester change `master-agent`'s `tools` array (add or
|
|
145
|
+
remove one tool), save, and watch the chip refresh.
|
|
146
|
+
|
|
147
|
+
> Same flow as the basic tutorial's live UI: edit the markdown,
|
|
148
|
+
> watch the UI refresh. The difference is that the value flowed
|
|
149
|
+
> through a plugin (`core/tools-count`) and landed in a specific
|
|
150
|
+
> slot (`inspector.header.badge.counter`). You now know the full
|
|
151
|
+
> path from `.md` to UI chip.
|
|
152
|
+
|
|
153
|
+
Have them Ctrl+C the server when done.
|
|
154
|
+
|
|
155
|
+
Mark `settings-6-contributions: done`.
|
|
156
|
+
|
|
157
|
+
## Reference: where each catalogue lives in the repo
|
|
158
|
+
|
|
159
|
+
Not for the tester unless they ask. Cheat sheet for the agent:
|
|
160
|
+
|
|
161
|
+
- **Slot catalogue (normative)**:
|
|
162
|
+
`spec/schemas/view-slots.schema.json` (enum + payload schemas).
|
|
163
|
+
- **Slot catalogue (UI mirror)**: `ui/src/app/slots/slot-config.ts`
|
|
164
|
+
(layout) and `ui/src/app/slots/slot-renderer-map.ts` (renderer
|
|
165
|
+
binding).
|
|
166
|
+
- **Input-types catalogue (normative)**: `spec/input-types.md`.
|
|
167
|
+
- **Plugin manifest schema**:
|
|
168
|
+
`spec/schemas/plugin-manifest.schema.json`.
|
|
169
|
+
- **Author tutorial**: `spec/plugin-author-guide.md`.
|
|
170
|
+
- **Slot annex for agents**: `context/view-slots.md`.
|
package/dist/cli.js
CHANGED
|
@@ -2963,7 +2963,7 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
2963
2963
|
// package.json
|
|
2964
2964
|
var package_default = {
|
|
2965
2965
|
name: "@skill-map/cli",
|
|
2966
|
-
version: "0.
|
|
2966
|
+
version: "0.31.0",
|
|
2967
2967
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
2968
2968
|
license: "MIT",
|
|
2969
2969
|
type: "module",
|
|
@@ -8081,9 +8081,9 @@ function providerKindFailure(opts, status, fileName, errDescription) {
|
|
|
8081
8081
|
}
|
|
8082
8082
|
};
|
|
8083
8083
|
}
|
|
8084
|
-
function isDirectorySafe(path,
|
|
8084
|
+
function isDirectorySafe(path, statSync12) {
|
|
8085
8085
|
try {
|
|
8086
|
-
return
|
|
8086
|
+
return statSync12(path).isDirectory();
|
|
8087
8087
|
} catch {
|
|
8088
8088
|
return false;
|
|
8089
8089
|
}
|
|
@@ -23748,43 +23748,37 @@ var STUB_COMMANDS = [
|
|
|
23748
23748
|
];
|
|
23749
23749
|
|
|
23750
23750
|
// cli/commands/tutorial.ts
|
|
23751
|
-
import { existsSync as existsSync29,
|
|
23752
|
-
import { writeFile as writeFile2 } from "fs/promises";
|
|
23751
|
+
import { cpSync as cpSync2, existsSync as existsSync29, mkdirSync as mkdirSync7, rmSync as rmSync2, statSync as statSync11 } from "fs";
|
|
23753
23752
|
import { dirname as dirname19, join as join19, resolve as resolve36 } from "path";
|
|
23754
23753
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
23755
23754
|
import { Command as Command37, Option as Option35 } from "clipanion";
|
|
23756
23755
|
|
|
23757
23756
|
// cli/i18n/tutorial.texts.ts
|
|
23758
23757
|
var TUTORIAL_TEXTS = {
|
|
23759
|
-
// Success, written to stdout after `<cwd>/{{
|
|
23760
|
-
//
|
|
23761
|
-
//
|
|
23762
|
-
//
|
|
23763
|
-
//
|
|
23764
|
-
//
|
|
23765
|
-
|
|
23766
|
-
|
|
23767
|
-
* renders relative to the user's cwd when it sits underneath. The
|
|
23768
|
-
* `English` / `Español` labels print dim, the eye lands on the
|
|
23769
|
-
* trigger phrases the user is going to copy / paste.
|
|
23770
|
-
*/
|
|
23771
|
-
written: " {{glyph}} {{filename}} created at {{cwd}}\n\n Open Claude Code in this directory. Your first message sets\n the tutorial language for the rest of the session:\n\n {{enLabel}} run @{{filename}}\n {{esLabel}} ejecut\xE1 @{{filename}}\n",
|
|
23758
|
+
// Success, written to stdout after `<cwd>/{{target}}` is created.
|
|
23759
|
+
// The skill now lives at `.claude/skills/<slug>/`; Claude Code
|
|
23760
|
+
// auto-discovers it on the next boot, so the tester invokes by
|
|
23761
|
+
// speaking a trigger phrase rather than referencing the file path.
|
|
23762
|
+
// English / Spanish triggers are surfaced side by side and the
|
|
23763
|
+
// first phrase the tester types sets the tutorial language for the
|
|
23764
|
+
// rest of the session.
|
|
23765
|
+
written: " {{glyph}} Skill `{{slug}}` materialized at {{target}} (under {{cwd}})\n\n Open Claude Code in this directory. The skill is auto-\n discovered; invoke it with one of its trigger phrases. The\n first message you type sets the tutorial language for the\n rest of the session:\n\n {{enLabel}} {{enTrigger}}\n {{esLabel}} {{esTrigger}}\n",
|
|
23772
23766
|
writtenLabelEn: "English",
|
|
23773
23767
|
writtenLabelEs: "Espa\xF1ol",
|
|
23774
|
-
// Refusal, `{{
|
|
23768
|
+
// Refusal, `{{target}}` already exists and `--force` was not set.
|
|
23775
23769
|
// Goes to stderr, exit code 2 (operational error per spec § Exit codes).
|
|
23776
23770
|
// Mirrors the success body shape: glyph + headline, then a dim hint
|
|
23777
23771
|
// line spelling the fix.
|
|
23778
|
-
alreadyExists: "{{glyph}} {{
|
|
23779
|
-
alreadyExistsHint: "Pass `--force` to overwrite.",
|
|
23772
|
+
alreadyExists: "{{glyph}} {{target}} already exists under {{cwd}}\n {{hint}}\n",
|
|
23773
|
+
alreadyExistsHint: "Pass `--force` to overwrite (deletes the existing folder first).",
|
|
23780
23774
|
// Invalid `variant` positional argument. Goes to stderr, exit code 2.
|
|
23781
23775
|
// Mirrors `alreadyExists`: glyph + headline + dim hint enumerating the
|
|
23782
23776
|
// valid values.
|
|
23783
23777
|
invalidVariant: "{{glyph}} sm tutorial: unknown variant '{{variant}}'\n {{hint}}\n",
|
|
23784
23778
|
invalidVariantHint: "Valid values: tutorial (default), master.",
|
|
23785
|
-
// I/O failure on write or on reading the bundled
|
|
23786
|
-
writeFailed: "{{glyph}} sm tutorial: failed to write {{
|
|
23787
|
-
sourceMissing: "{{glyph}} sm tutorial: could not read the bundled
|
|
23779
|
+
// I/O failure on write or on reading the bundled skill source.
|
|
23780
|
+
writeFailed: "{{glyph}} sm tutorial: failed to write {{target}}: {{message}}\n",
|
|
23781
|
+
sourceMissing: "{{glyph}} sm tutorial: could not read the bundled skill payload for {{target}} from the install.\n {{hint}}\n",
|
|
23788
23782
|
sourceMissingHint: "Reinstall @skill-map/cli or report the bug."
|
|
23789
23783
|
};
|
|
23790
23784
|
|
|
@@ -23793,41 +23787,45 @@ var VALID_VARIANTS = ["tutorial", "master"];
|
|
|
23793
23787
|
var DEFAULT_VARIANT = "tutorial";
|
|
23794
23788
|
var VARIANT_SPECS = {
|
|
23795
23789
|
tutorial: {
|
|
23796
|
-
|
|
23797
|
-
|
|
23798
|
-
|
|
23790
|
+
slug: "sm-tutorial",
|
|
23791
|
+
sourceDir: ".claude/skills/sm-tutorial",
|
|
23792
|
+
triggerEn: "start the tutorial",
|
|
23793
|
+
triggerEs: "arranquemos el tutorial"
|
|
23799
23794
|
},
|
|
23800
23795
|
master: {
|
|
23801
|
-
|
|
23802
|
-
|
|
23803
|
-
|
|
23796
|
+
slug: "sm-master",
|
|
23797
|
+
sourceDir: ".claude/skills/sm-master",
|
|
23798
|
+
triggerEn: "advanced tutorial",
|
|
23799
|
+
triggerEs: "tutorial maestro"
|
|
23804
23800
|
}
|
|
23805
23801
|
};
|
|
23806
23802
|
var TutorialCommand = class extends SmCommand {
|
|
23807
23803
|
static paths = [["tutorial"]];
|
|
23808
23804
|
static usage = Command37.Usage({
|
|
23809
23805
|
category: "Setup",
|
|
23810
|
-
description: "Materialize an interactive tester tutorial
|
|
23806
|
+
description: "Materialize an interactive tester tutorial as a Claude Code skill folder under `<cwd>/.claude/skills/`.",
|
|
23811
23807
|
details: `
|
|
23812
|
-
Drops the canonical SKILL.md
|
|
23813
|
-
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
23808
|
+
Drops the canonical skill directory (SKILL.md + any references/
|
|
23809
|
+
sub-folder) under \`<cwd>/.claude/skills/sm-tutorial/\` (default)
|
|
23810
|
+
or \`<cwd>/.claude/skills/sm-master/\` (when invoked as \`sm
|
|
23811
|
+
tutorial master\`). Claude Code auto-discovers the skill the
|
|
23812
|
+
next time it boots in this directory; the tester invokes it by
|
|
23813
|
+
speaking one of its trigger phrases.
|
|
23817
23814
|
|
|
23818
23815
|
Does NOT require an initialized .skill-map/ project. Refuses to
|
|
23819
|
-
overwrite the target
|
|
23820
|
-
for the positional argument are: tutorial (default),
|
|
23816
|
+
overwrite the target directory unless --force is passed. Valid
|
|
23817
|
+
values for the positional argument are: tutorial (default),
|
|
23818
|
+
master.
|
|
23821
23819
|
`,
|
|
23822
23820
|
examples: [
|
|
23823
|
-
["Materialize the basic tutorial in the cwd", "$0 tutorial"],
|
|
23824
|
-
["Materialize the advanced tutorial in the cwd", "$0 tutorial master"],
|
|
23825
|
-
["Overwrite an existing target
|
|
23821
|
+
["Materialize the basic tutorial skill in the cwd", "$0 tutorial"],
|
|
23822
|
+
["Materialize the advanced tutorial skill in the cwd", "$0 tutorial master"],
|
|
23823
|
+
["Overwrite an existing target directory", "$0 tutorial --force"]
|
|
23826
23824
|
]
|
|
23827
23825
|
});
|
|
23828
23826
|
variant = Option35.String({ required: false });
|
|
23829
23827
|
force = Option35.Boolean("--force", false, {
|
|
23830
|
-
description: "Overwrite an existing target
|
|
23828
|
+
description: "Overwrite an existing target directory without prompting."
|
|
23831
23829
|
});
|
|
23832
23830
|
async run() {
|
|
23833
23831
|
const ctx = defaultRuntimeContext();
|
|
@@ -23847,38 +23845,41 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23847
23845
|
}
|
|
23848
23846
|
const variant = rawVariant ?? DEFAULT_VARIANT;
|
|
23849
23847
|
const spec = VARIANT_SPECS[variant];
|
|
23850
|
-
const
|
|
23851
|
-
|
|
23848
|
+
const targetDir = join19(ctx.cwd, ".claude", "skills", spec.slug);
|
|
23849
|
+
const targetDisplay = `.claude/skills/${spec.slug}/`;
|
|
23850
|
+
if (existsSync29(targetDir) && !this.force) {
|
|
23852
23851
|
this.printer.error(
|
|
23853
23852
|
tx(TUTORIAL_TEXTS.alreadyExists, {
|
|
23854
23853
|
glyph: errGlyph,
|
|
23855
|
-
|
|
23854
|
+
target: targetDisplay,
|
|
23856
23855
|
cwd: stderrAnsi.dim(displayCwd(ctx.cwd)),
|
|
23857
23856
|
hint: stderrAnsi.dim(TUTORIAL_TEXTS.alreadyExistsHint)
|
|
23858
23857
|
})
|
|
23859
23858
|
);
|
|
23860
23859
|
return ExitCode.Error;
|
|
23861
23860
|
}
|
|
23862
|
-
let
|
|
23861
|
+
let sourceDir;
|
|
23863
23862
|
try {
|
|
23864
|
-
|
|
23863
|
+
sourceDir = resolveSkillSourceDir(variant);
|
|
23865
23864
|
} catch {
|
|
23866
23865
|
this.printer.error(
|
|
23867
23866
|
tx(TUTORIAL_TEXTS.sourceMissing, {
|
|
23868
23867
|
glyph: errGlyph,
|
|
23869
|
-
|
|
23868
|
+
target: targetDisplay,
|
|
23870
23869
|
hint: stderrAnsi.dim(TUTORIAL_TEXTS.sourceMissingHint)
|
|
23871
23870
|
})
|
|
23872
23871
|
);
|
|
23873
23872
|
return ExitCode.Error;
|
|
23874
23873
|
}
|
|
23875
23874
|
try {
|
|
23876
|
-
|
|
23875
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
23876
|
+
mkdirSync7(dirname19(targetDir), { recursive: true });
|
|
23877
|
+
cpSync2(sourceDir, targetDir, { recursive: true });
|
|
23877
23878
|
} catch (err) {
|
|
23878
23879
|
this.printer.error(
|
|
23879
23880
|
tx(TUTORIAL_TEXTS.writeFailed, {
|
|
23880
23881
|
glyph: errGlyph,
|
|
23881
|
-
|
|
23882
|
+
target: targetDisplay,
|
|
23882
23883
|
message: formatErrorMessage(err)
|
|
23883
23884
|
})
|
|
23884
23885
|
);
|
|
@@ -23894,10 +23895,13 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23894
23895
|
this.printer.data(
|
|
23895
23896
|
tx(TUTORIAL_TEXTS.written, {
|
|
23896
23897
|
glyph: ansi.green("\u2713"),
|
|
23897
|
-
|
|
23898
|
+
slug: spec.slug,
|
|
23899
|
+
target: targetDisplay,
|
|
23898
23900
|
cwd: ansi.dim(displayCwd(ctx.cwd)),
|
|
23899
23901
|
enLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEn),
|
|
23900
|
-
esLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEs)
|
|
23902
|
+
esLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEs),
|
|
23903
|
+
enTrigger: spec.triggerEn,
|
|
23904
|
+
esTrigger: spec.triggerEs
|
|
23901
23905
|
})
|
|
23902
23906
|
);
|
|
23903
23907
|
return ExitCode.Ok;
|
|
@@ -23911,31 +23915,29 @@ function displayCwd(cwd) {
|
|
|
23911
23915
|
if (segments.length === 0) return "./";
|
|
23912
23916
|
return `./${segments[segments.length - 1]}/`;
|
|
23913
23917
|
}
|
|
23914
|
-
var
|
|
23915
|
-
function
|
|
23916
|
-
const cached =
|
|
23918
|
+
var cachedSourceDirs = /* @__PURE__ */ new Map();
|
|
23919
|
+
function resolveSkillSourceDir(variant) {
|
|
23920
|
+
const cached = cachedSourceDirs.get(variant);
|
|
23917
23921
|
if (cached !== void 0) return cached;
|
|
23918
|
-
const body = readTutorialFromDisk(variant);
|
|
23919
|
-
cachedTutorials.set(variant, body);
|
|
23920
|
-
return body;
|
|
23921
|
-
}
|
|
23922
|
-
function readTutorialFromDisk(variant) {
|
|
23923
23922
|
const spec = VARIANT_SPECS[variant];
|
|
23924
23923
|
const here = dirname19(fileURLToPath6(import.meta.url));
|
|
23925
23924
|
const candidates = [
|
|
23926
|
-
// dev: src/cli/commands/ → repo-root .claude/skills/<slug>/
|
|
23927
|
-
resolve36(here, "../../..", spec.
|
|
23928
|
-
// bundled: dist/cli.js → dist/cli/tutorial/<
|
|
23929
|
-
resolve36(here, "cli/tutorial", spec.
|
|
23930
|
-
// bundled fallback: any-depth → cli/tutorial/<
|
|
23931
|
-
resolve36(here, "../cli/tutorial", spec.
|
|
23925
|
+
// dev: src/cli/commands/ → repo-root .claude/skills/<slug>/
|
|
23926
|
+
resolve36(here, "../../..", spec.sourceDir),
|
|
23927
|
+
// bundled: dist/cli.js → dist/cli/tutorial/<slug> (sibling)
|
|
23928
|
+
resolve36(here, "cli/tutorial", spec.slug),
|
|
23929
|
+
// bundled fallback: any-depth → cli/tutorial/<slug>
|
|
23930
|
+
resolve36(here, "../cli/tutorial", spec.slug)
|
|
23932
23931
|
];
|
|
23933
23932
|
for (const candidate of candidates) {
|
|
23934
|
-
if (existsSync29(candidate)) {
|
|
23935
|
-
|
|
23933
|
+
if (existsSync29(candidate) && statSync11(candidate).isDirectory()) {
|
|
23934
|
+
cachedSourceDirs.set(variant, candidate);
|
|
23935
|
+
return candidate;
|
|
23936
23936
|
}
|
|
23937
23937
|
}
|
|
23938
|
-
throw new Error(
|
|
23938
|
+
throw new Error(
|
|
23939
|
+
`skill source directory not found in any candidate location (last tried: ${candidates[candidates.length - 1]})`
|
|
23940
|
+
);
|
|
23939
23941
|
}
|
|
23940
23942
|
|
|
23941
23943
|
// cli/commands/version.ts
|