@iamdangavin/claude-skill-vitepress-docs 1.9.0 → 3.0.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.
@@ -1,7 +1,7 @@
1
1
  ---
2
- name: vitepress:docs
3
- description: VitePress documentation suite — setup GitHub Pages deployment, generate docs from a codebase, capture screenshots of any running app, and sync docs as code changes.
4
- argument-hint: [mode: setup|generate|screenshot|sync] or omit to be prompted
2
+ name: vitedocs:init
3
+ description: VitePress documentation suite — prompts for which mode to run and proceeds directly.
4
+ argument-hint: [setup|generate|screenshot|sync|brand|update] or omit to be prompted
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Write
@@ -12,17 +12,21 @@ allowed-tools:
12
12
  - AskUserQuestion
13
13
  ---
14
14
 
15
- # Skill: vitepress:docs
15
+ # vitedocs:init
16
16
 
17
- Four modes for full VitePress documentation lifecycle. If no mode is given as an argument, use AskUserQuestion to prompt for one:
17
+ If a mode was passed as an argument, proceed directly to that mode's instructions below. Otherwise use AskUserQuestion:
18
18
 
19
- - header: "vitepress:docs"
19
+ - header: "vitedocs"
20
20
  - question: "Which mode do you need?"
21
21
  - options:
22
22
  - "setup — Wire up VitePress + GitHub Actions for Pages deployment"
23
23
  - "generate — Analyze the codebase and write documentation pages"
24
24
  - "screenshot — Capture real screenshots and replace placeholders"
25
25
  - "sync — Detect code drift and update docs that are out of date"
26
+ - "brand — Configure colors, fonts, logo, and visual identity"
27
+ - "update — Retrofit an existing docs setup with the latest components"
28
+
29
+ Once a mode is selected, execute that mode's full instructions inline — do not ask the user to run a different command. The complete instructions for every mode follow below.
26
30
 
27
31
  ---
28
32
 
@@ -159,7 +163,7 @@ Present the relevant checklist as plain text, then use AskUserQuestion to confir
159
163
  - "Not yet — I need more time"
160
164
  - "I have a question"
161
165
 
162
- If "Not yet": tell the user to run `/vitepress:docs setup` again when ready and exit.
166
+ If "Not yet": tell the user to run `/vitedocs:setup` again when ready and exit.
163
167
  If "I have a question": answer it, then re-ask this question.
164
168
 
165
169
  The checklist to present (tailor to their answers):
@@ -588,13 +592,13 @@ If `apiBase` was collected in Q1b, write the following files before updating the
588
592
  @click="activeTab = tab"
589
593
  >{{ tab }}</button>
590
594
  </div>
591
- <pre class="api-ep__code"><code>{{ currentSample }}</code></pre>
595
+ <pre class="api-ep__code"><code v-html="highlightedSample"></code></pre>
592
596
  <p v-if="activeTab === 'Fetch'" class="api-ep__note">
593
597
  Must be called from an authenticated browser session — cookies are sent automatically.
594
598
  </p>
595
599
  <template v-if="response">
596
600
  <div class="api-ep__section-label">Sample Response</div>
597
- <pre class="api-ep__code"><code>{{ formattedResponse }}</code></pre>
601
+ <pre class="api-ep__code"><code v-html="highlightedResponse"></code></pre>
598
602
  </template>
599
603
  </div>
600
604
  </div>
@@ -603,6 +607,19 @@ If `apiBase` was collected in Q1b, write the following files before updating the
603
607
  <script setup>
604
608
  import { ref, computed } from 'vue'
605
609
  import { useData } from 'vitepress'
610
+ import hljs from 'highlight.js/lib/core'
611
+ import javascript from 'highlight.js/lib/languages/javascript'
612
+ import bash from 'highlight.js/lib/languages/bash'
613
+ import json from 'highlight.js/lib/languages/json'
614
+ // ADD THESE ONLY IF THE CORRESPONDING TAB WAS SELECTED IN Q1b:
615
+ // import php from 'highlight.js/lib/languages/php'
616
+ // import python from 'highlight.js/lib/languages/python'
617
+
618
+ hljs.registerLanguage('javascript', javascript) // Fetch + Axios
619
+ hljs.registerLanguage('bash', bash) // cURL
620
+ hljs.registerLanguage('json', json) // response bodies
621
+ // hljs.registerLanguage('php', php)
622
+ // hljs.registerLanguage('python', python)
606
623
 
607
624
  const props = defineProps({
608
625
  method: { type: String, required: true },
@@ -658,9 +675,32 @@ const currentSample = computed(() => {
658
675
  return ''
659
676
  })
660
677
 
678
+ const tabLang = {
679
+ 'Fetch': 'javascript',
680
+ 'Axios': 'javascript',
681
+ 'cURL': 'bash',
682
+ 'PHP': 'php',
683
+ 'Python': 'python',
684
+ }
685
+
686
+ const highlight = (code, lang) => {
687
+ const registered = hljs.getLanguage(lang)
688
+ return registered
689
+ ? hljs.highlight(code, { language: lang }).value
690
+ : hljs.highlightAuto(code).value
691
+ }
692
+
693
+ const highlightedSample = computed(() =>
694
+ highlight(currentSample.value, tabLang[activeTab.value] ?? 'bash')
695
+ )
696
+
661
697
  const formattedResponse = computed(() =>
662
698
  props.response ? JSON.stringify(props.response, null, 2) : ''
663
699
  )
700
+
701
+ const highlightedResponse = computed(() =>
702
+ formattedResponse.value ? highlight(formattedResponse.value, 'json') : ''
703
+ )
664
704
  </script>
665
705
 
666
706
  <style scoped>
@@ -686,10 +726,10 @@ const formattedResponse = computed(() =>
686
726
  </style>
687
727
  ```
688
728
 
689
- **Install `medium-zoom`** in the docs folder:
729
+ **Install dependencies** in the docs folder:
690
730
 
691
731
  ```bash
692
- cd DOCS_FOLDER && npm install medium-zoom
732
+ cd DOCS_FOLDER && npm install medium-zoom highlight.js
693
733
  ```
694
734
 
695
735
  **`.vitepress/theme/index.css`** — create if it doesn't exist, otherwise append:
@@ -753,7 +793,7 @@ Add `docs-manifest.json` to `.vitepress/` entry in `.gitignore`.
753
793
 
754
794
  ```
755
795
  Generated X pages (Y user-facing, Z developer).
756
- Created N placeholder screenshots — run /vitepress:docs screenshot when ready to capture real images.
796
+ Created N placeholder screenshots — run /vitedocs:screenshot when ready to capture real images.
757
797
  Filled M of P gaps — X remaining gap comments left in files for manual review.
758
798
  ```
759
799
 
@@ -785,8 +825,8 @@ const OUTPUT = 'FILL_IN_OUTPUT_PATH';
785
825
  const scanlines = [];
786
826
  for (let y = 0; y < H; y++) {
787
827
  const row = Buffer.alloc(1 + W * 3);
788
- row[0] = 0; // filter type: None
789
- row.fill(0x88, 1); // grey RGB pixels
828
+ row[0] = 0;
829
+ row.fill(0x88, 1);
790
830
  scanlines.push(row);
791
831
  }
792
832
  const raw = Buffer.concat(scanlines);
@@ -813,7 +853,7 @@ function makeChunk(type, data) {
813
853
  const sig = Buffer.from([137,80,78,71,13,10,26,10]);
814
854
  const ihdr = Buffer.alloc(13);
815
855
  ihdr.writeUInt32BE(W, 0); ihdr.writeUInt32BE(H, 4);
816
- ihdr[8] = 8; ihdr[9] = 2; // 8-bit RGB
856
+ ihdr[8] = 8; ihdr[9] = 2;
817
857
 
818
858
  mkdirSync(dirname(OUTPUT), { recursive: true });
819
859
  writeFileSync(OUTPUT, Buffer.concat([
@@ -896,7 +936,7 @@ import { chromium } from '/opt/homebrew/lib/node_modules/playwright/index.mjs';
896
936
 
897
937
  **⛔ Credential rule — NEVER write credentials to any file.** Do not write them to a script file, `.env`, the manifest, or anywhere on disk. All Playwright scripts run as inline bash heredocs — credentials are passed directly as inline values to `page.fill()` calls within the heredoc and exist only in memory for the duration of the command. If Playwright needs credentials in a reusable way, use a saved storage state file — but prompt the user for credentials fresh each time rather than caching them.
898
938
 
899
- **For pages requiring auth:** if credentials were provided, drive a login flow before navigating to the target URL. If no credentials were given, skip auth-gated pages and list them in the final summary so the user can run screenshot mode again with credentials.
939
+ **For pages requiring auth:** if credentials were provided, drive a login flow before navigating to the target URL. If no credentials were given, skip auth-gated pages and list them in the final summary so the user can run `/vitedocs:screenshot` again with credentials.
900
940
 
901
941
  **Standard capture script template:**
902
942
 
@@ -916,9 +956,7 @@ SCRIPT
916
956
 
917
957
  Adjust `SETTLE_MS` based on stack type: WordPress/non-SPA → `500`, Next.js/SPA → `2000`–`4000`.
918
958
 
919
- Never write the script to a file — always use the heredoc form above. This applies to auth flows too: inline all credential usage directly in the heredoc, never in a file.
920
-
921
- After each capture, display the image inline with the Read tool so the user can verify it before moving on.
959
+ Never write the script to a file — always use the heredoc form above.
922
960
 
923
961
  ### Step 4 — Rewrite prose around captured images
924
962
 
@@ -938,7 +976,7 @@ Captured X of Y screenshots.
938
976
 
939
977
  Rewrote prose in X doc pages.
940
978
 
941
- Run /vitepress:docs sync after future code changes to keep docs current.
979
+ Run /vitedocs:sync after future code changes to keep docs current.
942
980
  ```
943
981
 
944
982
  ---
@@ -1021,7 +1059,276 @@ Update `lastSynced` and `syncHash` for all updated pages. Update the top-level `
1021
1059
  ```
1022
1060
  Updated X of N drifted pages.
1023
1061
  X gap comments added for manual review.
1024
- Y screenshots flagged for recapture — run /vitepress:docs screenshot when ready.
1062
+ Y screenshots flagged for recapture — run /vitedocs:screenshot when ready.
1063
+ ```
1064
+
1065
+ ---
1066
+
1067
+ ## Mode: brand
1068
+
1069
+ ### Step 1 — Locate docs paths
1070
+
1071
+ Check the manifest(s) to find all configured docs folders. If no manifest exists, scan for `.vitepress/config.mjs` files across the known focus paths. Present what was found so the user can confirm before proceeding.
1072
+
1073
+ ### Step 2 — Shared or per-path branding
1074
+
1075
+ If more than one docs path is found, ask:
1076
+
1077
+ - header: "Branding scope"
1078
+ - question: "How should branding be applied across your docs?"
1079
+ - options:
1080
+ - "Same brand across all docs"
1081
+ - "Different brand per path — I'll configure each one separately"
1082
+
1083
+ If per-path: complete all brand questions for path 1 before moving to path 2 — never ask about two paths simultaneously.
1084
+
1085
+ ### Step 3 — Brand questions
1086
+
1087
+ Ask these once (shared) or once per path (per-path). Always label the header with the path name when in per-path mode so the user knows which repo they're configuring.
1088
+
1089
+ **B-Q1 — Primary brand color** (plain text): Ask — "What is the primary brand color? (hex, e.g. `#E63946`). This becomes the link, button, and accent color throughout the docs."
1090
+
1091
+ From this single hex value, derive the full VitePress brand palette automatically:
1092
+ - `--vp-c-brand-1`: the base hex
1093
+ - `--vp-c-brand-2`: 15% lighter
1094
+ - `--vp-c-brand-3`: 30% lighter
1095
+ - `--vp-c-brand-soft`: the hex at 12% opacity (for backgrounds)
1096
+
1097
+ Also derive dark mode variants — slightly brighter versions of each to account for dark backgrounds. Present the derived palette to the user before writing anything.
1098
+
1099
+ **B-Q2 — Logo:**
1100
+ - header: "Logo"
1101
+ - question: "Do you have a logo to use in the docs nav?"
1102
+ - options:
1103
+ - "Yes — I'll provide the path to the file"
1104
+ - "Text only — use the site title"
1105
+ - "Skip for now"
1106
+
1107
+ If yes: ask as plain text — "What is the path to the logo file? (SVG or PNG recommended, e.g. `public/logo.svg`)"
1108
+
1109
+ **B-Q3 — Favicon:**
1110
+ - header: "Favicon"
1111
+ - question: "Do you have a favicon?"
1112
+ - options:
1113
+ - "Yes — I'll provide the path"
1114
+ - "Use the logo as favicon"
1115
+ - "Skip for now"
1116
+
1117
+ If yes: ask as plain text — "Path to favicon? (e.g. `public/favicon.ico` or `public/favicon.svg`)"
1118
+
1119
+ **B-Q4 — Font:**
1120
+ - header: "Font"
1121
+ - question: "What font should the docs use?"
1122
+ - options:
1123
+ - "VitePress default (Inter)"
1124
+ - "System font stack (no external load)"
1125
+ - "Google Font — I'll tell you which"
1126
+ - "Custom — I'll provide the CSS import"
1127
+
1128
+ If Google Font: ask as plain text — "Which Google Font family? (e.g. `Outfit`, `DM Sans`)"
1129
+ If custom: ask as plain text — "Paste your @import or @font-face CSS."
1130
+
1131
+ **B-Q5 — Dark mode:**
1132
+ - header: "Dark mode"
1133
+ - question: "How should dark mode colors work?"
1134
+ - options:
1135
+ - "Auto-derive from brand color (recommended)"
1136
+ - "I want to set a custom dark mode accent color"
1137
+ - "Use VitePress default dark mode"
1138
+
1139
+ If custom: ask as plain text — "What hex color for dark mode accent?"
1140
+
1141
+ ### Step 4 — Preview palette
1142
+
1143
+ Before writing any files, present the full derived palette as a table:
1144
+
1145
+ ```
1146
+ Light mode
1147
+ --vp-c-brand-1: #E63946
1148
+ --vp-c-brand-2: #EB5E6A
1149
+ --vp-c-brand-3: #F28B93
1150
+ --vp-c-brand-soft: #E6394620
1151
+
1152
+ Dark mode
1153
+ --vp-c-brand-1: #F05A64
1154
+ --vp-c-brand-2: #F47980
1155
+ --vp-c-brand-3: #F7A0A5
1156
+ --vp-c-brand-soft: #F05A6420
1157
+ ```
1158
+
1159
+ Then ask:
1160
+
1161
+ - header: "Palette"
1162
+ - question: "Does this palette look right?"
1163
+ - options:
1164
+ - "Yes — apply it"
1165
+ - "Adjust the base color — I'll give you a new hex"
1166
+ - "Manually tweak individual values"
1167
+
1168
+ If adjust: take the new hex and re-derive. If manual: ask as plain text for each value to change.
1169
+
1170
+ ### Step 5 — Write brand files
1171
+
1172
+ For each docs path being branded:
1173
+
1174
+ **`.vitepress/theme/index.css`** — append the brand variables block. Do not remove existing entries — only add or update the brand vars:
1175
+
1176
+ ```css
1177
+ :root {
1178
+ --vp-c-brand-1: HEX1;
1179
+ --vp-c-brand-2: HEX2;
1180
+ --vp-c-brand-3: HEX3;
1181
+ --vp-c-brand-soft: HEXSOFT;
1182
+ /* FONT_VARS if custom font selected */
1183
+ }
1184
+
1185
+ .dark {
1186
+ --vp-c-brand-1: DARK_HEX1;
1187
+ --vp-c-brand-2: DARK_HEX2;
1188
+ --vp-c-brand-3: DARK_HEX3;
1189
+ --vp-c-brand-soft: DARK_HEXSOFT;
1190
+ }
1191
+ ```
1192
+
1193
+ If a Google Font was selected, add the `@import` at the top of the CSS file and set `--vp-font-family-base`.
1194
+
1195
+ **`.vitepress/config.mjs`** — add to `themeConfig`:
1196
+ - `logo` field if a logo was provided
1197
+ - `favicon` via `head` entry if a favicon was provided
1198
+
1199
+ Read the existing config before editing. Make only targeted additions — do not rewrite unrelated sections.
1200
+
1201
+ ### Step 6 — Summary
1202
+
1203
+ ```
1204
+ Branded X docs path(s).
1205
+
1206
+ Files updated:
1207
+ PATH/.vitepress/theme/index.css — brand palette + font
1208
+ PATH/.vitepress/config.mjs — logo, favicon
1209
+
1210
+ Run the local dev server to preview: npm run dev
1211
+ ```
1212
+
1213
+ ---
1214
+
1215
+ ## Mode: update
1216
+
1217
+ Retrofits an existing VitePress docs setup with the latest components, dependencies, and theme wiring. Does not re-run setup or regenerate pages.
1218
+
1219
+ ### Step 1 — Locate docs paths
1220
+
1221
+ Scan the current working directory and any known focus paths for `.vitepress/config.mjs` (or `.ts`) files. List what was found and ask the user to confirm which paths to update.
1222
+
1223
+ ### Step 2 — Inventory current state
1224
+
1225
+ For each confirmed docs path, check what is already present:
1226
+
1227
+ - `.vitepress/components/ApiEndpoint.vue` — exists?
1228
+ - `.vitepress/theme/index.js` — exists? includes `medium-zoom`? includes `ApiEndpoint`?
1229
+ - `.vitepress/theme/index.css` — exists? includes `.medium-zoom-overlay` z-index rules?
1230
+ - `package.json` — are `medium-zoom` and `highlight.js` listed in dependencies?
1231
+
1232
+ Report findings as a checklist:
1233
+ ```
1234
+ Path: docs/
1235
+ [x] ApiEndpoint.vue — found (needs update)
1236
+ [ ] medium-zoom installed
1237
+ [x] highlight.js installed
1238
+ [x] theme/index.js — found (missing medium-zoom wiring)
1239
+ [x] theme/index.css — found (missing z-index rules)
1240
+ ```
1241
+
1242
+ Then ask:
1243
+
1244
+ - header: "Update"
1245
+ - question: "What would you like to update?"
1246
+ - options:
1247
+ - "Everything that's missing or outdated"
1248
+ - "Let me choose item by item"
1249
+
1250
+ ### Step 3 — Gather inputs (only if needed)
1251
+
1252
+ If `ApiEndpoint.vue` is being written or updated and no existing `apiBase` is in the VitePress config, ask:
1253
+
1254
+ **U-Q1 — API base URL** (plain text): "What is the API base URL? (e.g. `https://api.example.com/wp-json/my-plugin/v1`)"
1255
+
1256
+ **U-Q2 — Code sample tabs:**
1257
+ - header: "Code tabs"
1258
+ - question: "Which code sample tabs should the ApiEndpoint component show?"
1259
+ - options:
1260
+ - "Fetch + cURL (default)"
1261
+ - "Fetch + cURL + PHP"
1262
+ - "Fetch + cURL + Python"
1263
+ - "Fetch + cURL + Axios"
1264
+ - "All of the above"
1265
+ - "Custom — I'll list them"
1266
+
1267
+ Skip U-Q1 and U-Q2 if `apiBase` already exists in `.vitepress/config.mjs` `themeConfig` — infer `apiBase` and existing tabs from the config and the current `ApiEndpoint.vue`.
1268
+
1269
+ ### Step 4 — Apply updates
1270
+
1271
+ Apply only the items selected (or all missing/outdated items if "Everything" was chosen). Always read existing files before editing — never overwrite unrelated content.
1272
+
1273
+ **`ApiEndpoint.vue`** — write the full component from the template in generate Step 6, substituting the correct tab list. If the file already exists, replace it entirely (it is a generated component, not hand-edited).
1274
+
1275
+ **`medium-zoom` + `highlight.js`** — if either is missing from `package.json` dependencies, run:
1276
+ ```bash
1277
+ cd DOCS_FOLDER && npm install medium-zoom highlight.js
1278
+ ```
1279
+
1280
+ **`.vitepress/theme/index.css`** — if `.medium-zoom-overlay` z-index block is missing, append:
1281
+ ```css
1282
+ .medium-zoom-overlay {
1283
+ z-index: 100;
1284
+ }
1285
+
1286
+ .medium-zoom-image--opened {
1287
+ z-index: 101;
1288
+ }
1289
+ ```
1290
+ Do not remove or overwrite existing entries.
1291
+
1292
+ **`.vitepress/theme/index.js`** — merge only what is missing:
1293
+ - If `medium-zoom` wiring is absent, add the `onMounted`/`watch` setup block
1294
+ - If `ApiEndpoint` registration is absent (and `apiBase` is configured), add the import and `app.component()` call
1295
+ - Never remove existing registrations or setup logic
1296
+
1297
+ Reference template for the full correct state:
1298
+ ```js
1299
+ import DefaultTheme from 'vitepress/theme'
1300
+ import { onMounted, watch, nextTick } from 'vue'
1301
+ import { useRoute } from 'vitepress'
1302
+ import mediumZoom from 'medium-zoom'
1303
+ import './index.css'
1304
+ import ApiEndpoint from '../components/ApiEndpoint.vue'
1305
+
1306
+ export default {
1307
+ extends: DefaultTheme,
1308
+ setup() {
1309
+ const route = useRoute()
1310
+ const initZoom = () => mediumZoom('.main img', { background: 'var(--vp-c-bg)' })
1311
+ onMounted(initZoom)
1312
+ watch(() => route.path, () => nextTick(initZoom))
1313
+ },
1314
+ enhanceApp({ app }) {
1315
+ app.component('ApiEndpoint', ApiEndpoint)
1316
+ }
1317
+ }
1318
+ ```
1319
+
1320
+ **`.vitepress/config.mjs`** — if `apiBase` was collected and is not already in `themeConfig`, add it.
1321
+
1322
+ ### Step 5 — Summary
1323
+
1324
+ ```
1325
+ Updated X of Y docs path(s).
1326
+
1327
+ Changes applied:
1328
+ PATH/.vitepress/components/ApiEndpoint.vue — written
1329
+ PATH/.vitepress/theme/index.js — merged medium-zoom + ApiEndpoint
1330
+ PATH/.vitepress/theme/index.css — added z-index rules
1331
+ PATH/package.json — installed medium-zoom, highlight.js
1025
1332
  ```
1026
1333
 
1027
1334
  ---
package/install.js CHANGED
@@ -1,17 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import { mkdirSync, copyFileSync } from 'fs';
2
+ import { mkdirSync, copyFileSync, readdirSync } from 'fs';
3
3
  import { join, dirname } from 'path';
4
4
  import { homedir } from 'os';
5
5
  import { fileURLToPath } from 'url';
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
 
9
- const skillName = 'vitepress-docs';
10
- const dest = join(homedir(), '.claude', 'skills', skillName);
9
+ const src = join(__dirname, 'commands', 'vitedocs');
10
+ const dest = join(homedir(), '.claude', 'commands', 'vitedocs');
11
11
 
12
12
  mkdirSync(dest, { recursive: true });
13
- copyFileSync(join(__dirname, 'skill', 'SKILL.md'), join(dest, 'SKILL.md'));
13
+
14
+ const files = readdirSync(src).filter(f => f.endsWith('.md'));
15
+ for (const file of files) {
16
+ copyFileSync(join(src, file), join(dest, file));
17
+ }
14
18
 
15
19
  console.log(`✓ Installed @iamdangavin/claude-skill-vitepress-docs`);
16
- console.log(` → ${dest}/SKILL.md`);
17
- console.log(` Invoke with: /vitepress-docs in Claude Code`);
20
+ console.log(` → ${dest}/`);
21
+ console.log(` Invoke with: /vitedocs:init in Claude Code`);
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@iamdangavin/claude-skill-vitepress-docs",
3
- "version": "1.9.0",
4
- "description": "Installs the vitepress:docs Claude Code skill — VitePress docs setup, generation, screenshots, and sync.",
3
+ "version": "3.0.0",
4
+ "description": "Installs the vitedocs: Claude Code skill suite — VitePress docs setup, generate, screenshot, sync, brand, and update.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "claude-skill-vitepress-docs": "./install.js"
8
8
  },
9
9
  "files": [
10
10
  "install.js",
11
- "skill/"
11
+ "commands/"
12
12
  ],
13
13
  "keywords": [
14
14
  "claude",