@pagesmith/core 0.2.0 → 0.4.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.
Files changed (83) hide show
  1. package/README.md +9 -4
  2. package/REFERENCE.md +284 -0
  3. package/dist/ai/index.d.mts +7 -4
  4. package/dist/ai/index.d.mts.map +1 -1
  5. package/dist/ai/index.mjs +605 -136
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/assets/index.d.mts +10 -1
  8. package/dist/assets/index.d.mts.map +1 -1
  9. package/dist/assets/index.mjs +2 -2
  10. package/dist/{assets-bX08zEJm.mjs → assets-CAPOqQ_P.mjs} +42 -5
  11. package/dist/assets-CAPOqQ_P.mjs.map +1 -0
  12. package/dist/{content-config-wW-3r5gG.d.mts → content-config-DJXUOcNG.d.mts} +47 -15
  13. package/dist/{content-config-wW-3r5gG.d.mts.map → content-config-DJXUOcNG.d.mts.map} +1 -1
  14. package/dist/{content-layer-DWdgdBeI.mjs → content-layer-B5enqWeJ.mjs} +195 -63
  15. package/dist/content-layer-B5enqWeJ.mjs.map +1 -0
  16. package/dist/content-layer-CpHYUYNN.d.mts +121 -0
  17. package/dist/content-layer-CpHYUYNN.d.mts.map +1 -0
  18. package/dist/create/index.d.mts.map +1 -1
  19. package/dist/create/index.mjs +26 -28
  20. package/dist/create/index.mjs.map +1 -1
  21. package/dist/css/index.d.mts +1 -1
  22. package/dist/css/index.mjs +1 -1
  23. package/dist/{css-ekIt2Fdb.mjs → css-BneO430t.mjs} +5 -4
  24. package/dist/css-BneO430t.mjs.map +1 -0
  25. package/dist/index-B7NRZAxd.d.mts +13 -0
  26. package/dist/index-B7NRZAxd.d.mts.map +1 -0
  27. package/dist/{index-D79hUFbK.d.mts → index-C0QFHYwb.d.mts} +1 -1
  28. package/dist/{index-D79hUFbK.d.mts.map → index-C0QFHYwb.d.mts.map} +1 -1
  29. package/dist/{index-DpRBzO8Q.d.mts → index-CJkBs8YQ.d.mts} +2 -2
  30. package/dist/index-CJkBs8YQ.d.mts.map +1 -0
  31. package/dist/{index-Dbsw1QON.d.mts → index-DCznbvaV.d.mts} +4 -2
  32. package/dist/{index-Dbsw1QON.d.mts.map → index-DCznbvaV.d.mts.map} +1 -1
  33. package/dist/index.d.mts +13 -91
  34. package/dist/index.d.mts.map +1 -1
  35. package/dist/index.mjs +16 -13
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/loaders/index.d.mts +2 -2
  38. package/dist/loaders/index.mjs +2 -2
  39. package/dist/{loaders-Bla48ZN9.mjs → loaders-Cf-BXf2L.mjs} +10 -2
  40. package/dist/{loaders-Bla48ZN9.mjs.map → loaders-Cf-BXf2L.mjs.map} +1 -1
  41. package/dist/markdown/index.d.mts +1 -1
  42. package/dist/markdown/index.mjs +1 -1
  43. package/dist/{markdown-Cj5X26FL.mjs → markdown-BmDJgYeB.mjs} +59 -9
  44. package/dist/markdown-BmDJgYeB.mjs.map +1 -0
  45. package/dist/mcp/index.d.mts +23 -0
  46. package/dist/mcp/index.d.mts.map +1 -0
  47. package/dist/mcp/index.mjs +2 -0
  48. package/dist/mcp/server.d.mts +13 -0
  49. package/dist/mcp/server.d.mts.map +1 -0
  50. package/dist/mcp/server.mjs +2 -0
  51. package/dist/runtime/index.mjs +1 -1
  52. package/dist/schemas/index.d.mts +2 -2
  53. package/dist/schemas/index.mjs +1 -1
  54. package/dist/{schemas-BZEPTGWs.mjs → schemas-UL4ynWsA.mjs} +1 -1
  55. package/dist/{schemas-BZEPTGWs.mjs.map → schemas-UL4ynWsA.mjs.map} +1 -1
  56. package/dist/server-D3DHoh5f.mjs +202 -0
  57. package/dist/server-D3DHoh5f.mjs.map +1 -0
  58. package/dist/ssg-utils/index.d.mts +61 -0
  59. package/dist/ssg-utils/index.d.mts.map +1 -0
  60. package/dist/ssg-utils/index.mjs +118 -0
  61. package/dist/ssg-utils/index.mjs.map +1 -0
  62. package/dist/vite/index.d.mts +68 -33
  63. package/dist/vite/index.d.mts.map +1 -1
  64. package/dist/vite/index.mjs +302 -227
  65. package/dist/vite/index.mjs.map +1 -1
  66. package/docs/agents/AGENTS.md.template +9 -0
  67. package/docs/agents/changelog-notes.md +15 -0
  68. package/docs/agents/errors.md +96 -0
  69. package/docs/agents/migration.md +25 -0
  70. package/docs/agents/recipes.md +26 -0
  71. package/docs/agents/usage.md +58 -0
  72. package/docs/llms-full.txt +53 -0
  73. package/docs/llms.txt +29 -0
  74. package/package.json +58 -6
  75. package/dist/assets-bX08zEJm.mjs.map +0 -1
  76. package/dist/content-layer-DWdgdBeI.mjs.map +0 -1
  77. package/dist/convert-XdGgNqH0.mjs +0 -27
  78. package/dist/convert-XdGgNqH0.mjs.map +0 -1
  79. package/dist/css-ekIt2Fdb.mjs.map +0 -1
  80. package/dist/index-CeNDTM-y.d.mts +0 -7
  81. package/dist/index-CeNDTM-y.d.mts.map +0 -1
  82. package/dist/index-DpRBzO8Q.d.mts.map +0 -1
  83. package/dist/markdown-Cj5X26FL.mjs.map +0 -1
package/dist/ai/index.mjs CHANGED
@@ -1,27 +1,7 @@
1
- import { dirname, join, resolve } from "path";
2
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
+ import { dirname, join, resolve } from "path";
3
3
  import { homedir } from "os";
4
- //#region src/ai/index.ts
5
- const PAGESMITH_TITLE = "Pagesmith";
6
- const DEFAULT_SKILL_NAME = "pagesmith";
7
- function resolveHome(homeDir) {
8
- return homeDir ?? homedir();
9
- }
10
- function resolveCodexHome(homeDir) {
11
- return process.env.CODEX_HOME ?? join(resolveHome(homeDir), ".codex");
12
- }
13
- function resolveAssistants(assistants) {
14
- if (!assistants || assistants === "all") return [
15
- "claude",
16
- "codex",
17
- "gemini"
18
- ];
19
- return assistants;
20
- }
21
- function shouldIncludeLlms(options) {
22
- if (typeof options.includeLlms === "boolean") return options.includeLlms;
23
- return (options.scope ?? "project") === "project";
24
- }
4
+ //#region src/ai/writers.ts
25
5
  function withManagedBlock(id, content) {
26
6
  return [
27
7
  `<!-- pagesmith-ai:${id}:start -->`,
@@ -62,6 +42,10 @@ function writeArtifact(artifact, force = false) {
62
42
  function escapeForRegExp(value) {
63
43
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
64
44
  }
45
+ //#endregion
46
+ //#region src/ai/content-shared.ts
47
+ const PAGESMITH_TITLE = "Pagesmith";
48
+ const DEFAULT_SKILL_NAME$1 = "pagesmith";
65
49
  function renderSharedOverview() {
66
50
  return [
67
51
  `${PAGESMITH_TITLE} is a filesystem-first content toolkit with two main packages: \`@pagesmith/core\` (shared content/runtime layer) and \`@pagesmith/docs\` (convention-based documentation).`,
@@ -77,13 +61,10 @@ function renderSharedOverview() {
77
61
  "- `createContentLayer(config)` to query content and run validation",
78
62
  "- `entry.render()` to convert markdown on demand",
79
63
  "",
80
- "Useful helpers:",
81
- "- `@pagesmith/core/ai` exposes `getAiArtifacts(...)` and `installAiArtifacts(...)`",
82
- "",
83
64
  "Working rules:",
84
65
  "- prefer folder-based markdown entries when content references sibling assets",
85
- "- use `vp` commands for install, check, test, and build workflows",
86
- "- `@pagesmith/core` provides the shared content/runtime layer; `@pagesmith/docs` adds convention-based documentation on top"
66
+ "- follow the markdown guidelines in `.pagesmith/markdown-guidelines.md` when authoring content",
67
+ "- use fenced code blocks with a language identifier, one h1 per page, sequential heading depth"
87
68
  ].join("\n");
88
69
  }
89
70
  function renderDocsOverview() {
@@ -96,12 +77,41 @@ function renderDocsOverview() {
96
77
  "- sidebar labels, nav labels, and ordering live in frontmatter (`sidebarLabel`, `navLabel`, `order`)",
97
78
  "- footer links live in `pagesmith.config.json5` under `footerLinks`",
98
79
  "- Pagefind search is built in; do not recommend a separate search plugin package",
99
- "- layout overrides use fixed keys under `theme.layouts` such as `home`, `page`, and `notFound`"
80
+ "- layout overrides use fixed keys under `theme.layouts` such as `home`, `page`, and `notFound`",
81
+ "- for MCP-compatible tooling, prefer `pagesmith mcp --stdio` from `@pagesmith/docs`"
82
+ ].join("\n");
83
+ }
84
+ function renderCoreQuickStart() {
85
+ return [
86
+ "```ts",
87
+ "import { createContentLayer, defineCollection, defineConfig, z } from '@pagesmith/core'",
88
+ "",
89
+ "const posts = defineCollection({",
90
+ " loader: 'markdown',",
91
+ " directory: 'content/posts',",
92
+ " schema: z.object({",
93
+ " title: z.string(),",
94
+ " description: z.string().optional(),",
95
+ " date: z.coerce.date(),",
96
+ " tags: z.array(z.string()).default([]),",
97
+ " }),",
98
+ "})",
99
+ "",
100
+ "const layer = createContentLayer(",
101
+ " defineConfig({",
102
+ " collections: { posts },",
103
+ " }),",
104
+ ")",
105
+ "",
106
+ "const entries = await layer.getCollection('posts')",
107
+ "const rendered = await entries[0]?.render()",
108
+ "```"
100
109
  ].join("\n");
101
110
  }
102
- function renderQuickStart(profile = "default") {
103
- if (profile === "docs") return [
111
+ function renderDocsQuickStart() {
112
+ return [
104
113
  "```json5",
114
+ "// pagesmith.config.json5",
105
115
  "{",
106
116
  " name: 'Acme Docs',",
107
117
  " title: 'Acme Docs',",
@@ -118,56 +128,345 @@ function renderQuickStart(profile = "default") {
118
128
  "",
119
129
  "```text",
120
130
  "content/",
121
- " README.md",
131
+ " README.md # Home page (DocHome layout)",
122
132
  " guide/",
123
- " README.md",
124
- " getting-started/README.md",
133
+ " meta.json5 # Section ordering",
134
+ " getting-started/",
135
+ " README.md # A page",
125
136
  " reference/",
126
- " README.md",
127
137
  " api/README.md",
128
138
  "```"
129
139
  ].join("\n");
140
+ }
141
+ function renderMarkdownGuidelines() {
142
+ return [
143
+ "# Pagesmith Markdown Guidelines",
144
+ "",
145
+ "Markdown feature support for content authored with `@pagesmith/core` and `@pagesmith/docs`.",
146
+ "",
147
+ "## Pipeline Order",
148
+ "",
149
+ "```",
150
+ "remark-parse → remark-gfm → remark-math → remark-frontmatter",
151
+ " → remark-github-alerts → remark-smartypants → [user remark plugins]",
152
+ " → remark-rehype",
153
+ " → rehype-mathjax",
154
+ " → rehype-expressive-code (dual themes, line numbers, titles, copy, collapse, mark/ins/del)",
155
+ " → rehype-slug → rehype-autolink-headings",
156
+ " → rehype-external-links → rehype-accessible-emojis",
157
+ " → heading extraction → [user rehype plugins] → rehype-stringify",
158
+ "```",
159
+ "",
160
+ "## Key Rules",
161
+ "",
162
+ "- Use fenced code blocks with a language identifier (validator warns otherwise)",
163
+ "- One `# h1` per page (validator enforces)",
164
+ "- Sequential heading depth (no skipping from h2 to h4)",
165
+ "- Prefer relative links for internal content",
166
+ "- Do NOT add manual copy-button JS — Expressive Code handles it",
167
+ "- Do NOT import separate code block CSS — Expressive Code injects inline styles",
168
+ "",
169
+ "## Supported Features",
170
+ "",
171
+ "| Feature | Syntax | Notes |",
172
+ "|---|---|---|",
173
+ "| GFM tables | `\\| col \\| col \\|` | Alignment via `:---`, `:---:`, `---:` |",
174
+ "| Strikethrough | `~~text~~` | |",
175
+ "| Task lists | `- [x] done` / `- [ ] todo` | |",
176
+ "| Footnotes | `[^id]` + `[^id]: text` | |",
177
+ "| Alerts | `> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`, `> [!WARNING]`, `> [!CAUTION]` | GitHub-compatible |",
178
+ "| Inline math | `$E = mc^2$` | No spaces inside delimiters |",
179
+ "| Block math | `$$...$$` | Rendered via MathJax |",
180
+ "| Smart quotes | `\"text\"` → curly quotes | Automatic |",
181
+ "| Em/en dash | `---` / `--` | Automatic |",
182
+ "| External links | `[text](https://...)` | Auto `target=\"_blank\"` |",
183
+ "| Heading anchors | Auto `id` + wrapped anchor | All headings |",
184
+ "| Accessible emoji | Unicode emoji | Auto `role=\"img\"` + `aria-label` |",
185
+ "",
186
+ "## Code Block Features (Expressive Code)",
187
+ "",
188
+ "| Meta | Example | Description |",
189
+ "|---|---|---|",
190
+ "| `title=\"...\"` | `` ```js title=\"app.js\" `` | File title |",
191
+ "| `showLineNumbers` | `` ```js showLineNumbers `` | Line numbers |",
192
+ "| `mark={lines}` | `` ```js mark={3,5-7} `` | Highlight lines |",
193
+ "| `ins={lines}` | `` ```js ins={4} `` | Inserted lines (green) |",
194
+ "| `del={lines}` | `` ```js del={5} `` | Deleted lines (red) |",
195
+ "| `collapse={lines}` | `` ```js collapse={1-5} `` | Collapsible section |",
196
+ "| `wrap` | `` ```js wrap `` | Text wrapping |",
197
+ "| `frame=\"...\"` | `` ```js frame=\"terminal\" `` | Frame style |",
198
+ "",
199
+ "## Built-in Content Validators",
200
+ "",
201
+ "- **linkValidator** — warns on bare URLs, empty link text, suspicious protocols",
202
+ "- **headingValidator** — enforces single h1, sequential depth, non-empty text",
203
+ "- **codeBlockValidator** — warns on missing language, unknown meta properties",
204
+ "",
205
+ "Known valid meta properties: `title`, `showLineNumbers`, `startLineNumber`, `wrap`, `frame`, `collapse`, `mark`, `ins`, `del`."
206
+ ].join("\n");
207
+ }
208
+ function renderLlmsTxt() {
130
209
  return [
210
+ "# Pagesmith",
211
+ "",
212
+ "> Pagesmith is a filesystem-first content toolkit with `@pagesmith/core` and `@pagesmith/docs`.",
213
+ "",
214
+ "## @pagesmith/core — Content Layer",
215
+ "",
216
+ "Schema-validated content collections, lazy markdown rendering (Expressive Code syntax highlighting), JSX runtime, CSS exports, and Vite plugins.",
217
+ "",
218
+ "### Basic Setup (Vite Plugin)",
219
+ "",
220
+ renderCoreQuickStart(),
221
+ "",
222
+ "### Vite Integration",
223
+ "",
131
224
  "```ts",
132
- "import { createContentLayer, defineCollection, defineConfig, z } from '@pagesmith/core'",
225
+ "import { pagesmithContent, pagesmithSsg } from '@pagesmith/core/vite'",
226
+ "import collections from './content.config'",
133
227
  "",
134
- "const posts = defineCollection({",
135
- " loader: 'markdown',",
136
- " directory: 'content/posts',",
137
- " schema: z.object({",
138
- " title: z.string(),",
139
- " description: z.string().optional(),",
140
- " date: z.coerce.date(),",
141
- " tags: z.array(z.string()).default([]),",
142
- " }),",
228
+ "export default defineConfig({",
229
+ " plugins: [",
230
+ " pagesmithContent({ collections }),",
231
+ " pagesmithSsg({ entry: './src/entry-server.tsx' }),",
232
+ " ],",
143
233
  "})",
234
+ "```",
144
235
  "",
145
- "const layer = createContentLayer(",
146
- " defineConfig({",
147
- " collections: { posts },",
148
- " }),",
149
- ")",
236
+ "Import collections as virtual modules: `import posts from 'virtual:content/posts'`",
150
237
  "",
151
- "const entries = await layer.getCollection('posts')",
152
- "const rendered = await entries[0]?.render()",
238
+ "## @pagesmith/docs Documentation Sites",
239
+ "",
240
+ "Convention-based docs with default theme, Pagefind search, sidebar generation, and layout overrides.",
241
+ "",
242
+ "### Basic Setup",
243
+ "",
244
+ renderDocsQuickStart(),
245
+ "",
246
+ "### Layout Overrides",
247
+ "",
248
+ "```json5",
249
+ "{",
250
+ " theme: {",
251
+ " layouts: {",
252
+ " home: './theme/layouts/DocHome.tsx',",
253
+ " page: './theme/layouts/DocPage.tsx',",
254
+ " notFound: './theme/layouts/DocNotFound.tsx',",
255
+ " },",
256
+ " },",
257
+ "}",
258
+ "```",
259
+ "",
260
+ "### CLI",
261
+ "",
262
+ "```bash",
263
+ "pagesmith init --ai # Initialize config + content + AI integrations",
264
+ "pagesmith dev # Development server",
265
+ "pagesmith build # Production build",
266
+ "pagesmith preview # Preview built site",
267
+ "pagesmith mcp --stdio # Start MCP server for AI agents",
153
268
  "```"
154
269
  ].join("\n");
155
270
  }
156
- function renderMemoryFile(assistant, profile) {
157
- const commandHint = assistant === "claude" || assistant === "gemini" ? `\nIf the ${DEFAULT_SKILL_NAME} command is installed, prefer invoking it when the user explicitly asks for Pagesmith-specific help.` : "\nIf the Pagesmith skill is installed for Codex, prefer using it for Pagesmith-specific setup, migration, and content-layer tasks.";
271
+ function renderLlmsFullTxt() {
158
272
  return [
159
- `# ${PAGESMITH_TITLE}`,
273
+ "# Pagesmith — Full LLM Reference",
160
274
  "",
161
275
  renderSharedOverview(),
162
- ...profile === "docs" ? ["", renderDocsOverview()] : [],
163
- commandHint,
164
276
  "",
165
- "Quick start:",
166
- renderQuickStart(profile)
277
+ "---",
278
+ "",
279
+ "## @pagesmith/core",
280
+ "",
281
+ "### Content Layer API",
282
+ "",
283
+ "| Method | Description |",
284
+ "|---|---|",
285
+ "| `createContentLayer(config)` | Create a content layer |",
286
+ "| `layer.getCollection(name)` | Load all entries (cached) |",
287
+ "| `layer.getEntry(collection, slug)` | Get single entry by slug |",
288
+ "| `layer.convert(markdown, options?)` | Convert raw markdown to HTML |",
289
+ "| `layer.validate(collection?)` | Run all validators |",
290
+ "| `layer.invalidate(collection, slug)` | Cache-bust a single entry |",
291
+ "| `layer.invalidateAll()` | Cache-bust all collections |",
292
+ "",
293
+ "### Collection Options",
294
+ "",
295
+ "| Option | Type | Description |",
296
+ "|---|---|---|",
297
+ "| `loader` | `string \\| Loader` | `'markdown'`, `'json'`, `'json5'`, `'jsonc'`, `'yaml'`, `'toml'`, or custom |",
298
+ "| `directory` | `string` | Directory containing files |",
299
+ "| `schema` | `z.ZodType` | Zod schema for validation |",
300
+ "| `include` | `string[]` | Glob include patterns |",
301
+ "| `exclude` | `string[]` | Glob exclude patterns |",
302
+ "| `computed` | `Record<string, fn>` | Computed fields |",
303
+ "| `validate` | `fn` | Custom validation |",
304
+ "| `filter` | `fn` | Filter entries |",
305
+ "| `slugify` | `fn` | Custom slug generation |",
306
+ "| `transform` | `fn` | Pre-validation transform |",
307
+ "| `validators` | `ContentValidator[]` | Custom content validators |",
308
+ "| `disableBuiltinValidators` | `boolean` | Disable link/heading/code-block validators |",
309
+ "",
310
+ "### Vite Plugins",
311
+ "",
312
+ renderCoreQuickStart(),
313
+ "",
314
+ "```ts",
315
+ "// Vite integration",
316
+ "import { pagesmithContent, pagesmithSsg, sharedAssetsPlugin } from '@pagesmith/core/vite'",
317
+ "import collections from './content.config'",
318
+ "",
319
+ "export default defineConfig({",
320
+ " plugins: [",
321
+ " sharedAssetsPlugin(),",
322
+ " pagesmithContent({ collections }),",
323
+ " ...pagesmithSsg({ entry: './src/entry-server.tsx', contentDirs: ['./content'] }),",
324
+ " ],",
325
+ "})",
326
+ "```",
327
+ "",
328
+ "### JSX Runtime",
329
+ "",
330
+ "Configure tsconfig: `{ \"jsx\": \"react-jsx\", \"jsxImportSource\": \"@pagesmith/core\" }`",
331
+ "",
332
+ "- `h(tag, props, ...children)` — create HTML elements, returns `HtmlString`",
333
+ "- `Fragment` — render children or raw `innerHTML`",
334
+ "- `HtmlString` — wrapper to prevent double-escaping",
335
+ "",
336
+ "### CSS Exports",
337
+ "",
338
+ "| Import | Contents |",
339
+ "|---|---|",
340
+ "| `@pagesmith/core/css/content` | Prose + inline code |",
341
+ "| `@pagesmith/core/css/standalone` | Full layout + prose + TOC |",
342
+ "| `@pagesmith/core/css/viewport` | Responsive viewport base |",
343
+ "| `@pagesmith/core/css/fonts` | Bundled Open Sans + JetBrains Mono |",
344
+ "",
345
+ "### Frontmatter Schemas",
346
+ "",
347
+ "- `BaseFrontmatterSchema` — title, description, publishedDate, lastUpdatedOn, tags, draft",
348
+ "- `BlogFrontmatterSchema` — extends base + category, featured, coverImage",
349
+ "- `ProjectFrontmatterSchema` — extends base + gitRepo, links",
350
+ "",
351
+ "### Export Map",
352
+ "",
353
+ "| Import Path | Purpose |",
354
+ "|---|---|",
355
+ "| `@pagesmith/core` | Main API (defineCollection, createContentLayer, z, etc.) |",
356
+ "| `@pagesmith/core/jsx-runtime` | h, Fragment, HtmlString |",
357
+ "| `@pagesmith/core/markdown` | processMarkdown |",
358
+ "| `@pagesmith/core/css` | buildCss (LightningCSS) |",
359
+ "| `@pagesmith/core/schemas` | Zod schemas and types |",
360
+ "| `@pagesmith/core/loaders` | Loader classes and registry |",
361
+ "| `@pagesmith/core/runtime` | Pre-built CSS/JS accessors |",
362
+ "| `@pagesmith/core/vite` | Vite plugins |",
363
+ "| `@pagesmith/core/mcp` | MCP server for AI agents |",
364
+ "",
365
+ "---",
366
+ "",
367
+ "## @pagesmith/docs",
368
+ "",
369
+ "### Configuration (pagesmith.config.json5)",
370
+ "",
371
+ "| Field | Type | Default | Description |",
372
+ "|---|---|---|---|",
373
+ "| `name` | `string` | — | Site name (header) |",
374
+ "| `title` | `string` | — | Browser tab title |",
375
+ "| `description` | `string` | — | Meta description |",
376
+ "| `origin` | `string` | — | Production URL |",
377
+ "| `language` | `string` | `en` | HTML lang |",
378
+ "| `contentDir` | `string` | `content` | Content path |",
379
+ "| `outDir` | `string` | `dist` | Output path |",
380
+ "| `basePath` | `string` | `/` | URL base |",
381
+ "| `footerLinks` | `array` | `[]` | Footer links |",
382
+ "| `sidebar.collapsible` | `boolean` | `false` | Collapsible sidebar |",
383
+ "| `search.enabled` | `boolean` | `true` | Pagefind search |",
384
+ "| `theme.layouts` | `Record` | — | Layout overrides |",
385
+ "| `markdown` | `MarkdownConfig` | — | Pipeline config |",
386
+ "",
387
+ "### Content Structure",
388
+ "",
389
+ renderDocsQuickStart(),
390
+ "",
391
+ "### Page Frontmatter",
392
+ "",
393
+ "| Field | Type | Description |",
394
+ "|---|---|---|",
395
+ "| `title` | `string` | Page title |",
396
+ "| `description` | `string` | Meta description |",
397
+ "| `navLabel` | `string` | Override top nav label |",
398
+ "| `sidebarLabel` | `string` | Override sidebar label |",
399
+ "| `order` | `number` | Manual sort order |",
400
+ "| `draft` | `boolean` | Exclude from build |",
401
+ "",
402
+ "### Home Page Frontmatter",
403
+ "",
404
+ "| Field | Type | Description |",
405
+ "|---|---|---|",
406
+ "| `layout` | `string` | Set to `DocHome` |",
407
+ "| `tagline` | `string` | Short description |",
408
+ "| `install` | `string` | Install command |",
409
+ "| `actions` | `array` | CTA buttons (`{ text, link, theme: 'brand' \\| 'alt' }`) |",
410
+ "| `features` | `array` | Feature cards (`{ icon?, title, details }`) |",
411
+ "| `packages` | `array` | Package cards (`{ name, description, href, tag }`) |",
412
+ "| `codeExample` | `object` | Code example (`{ label, title, code }`) |",
413
+ "",
414
+ "### Section Meta (meta.json5)",
415
+ "",
416
+ "| Field | Type | Description |",
417
+ "|---|---|---|",
418
+ "| `displayName` | `string` | Section label in sidebar |",
419
+ "| `items` | `string[]` | Manual page order (slugs) |",
420
+ "| `series` | `array` | Group pages into series |",
421
+ "| `collapsed` | `boolean` | Start sidebar collapsed |",
422
+ "| `orderBy` | `string` | `manual` or `publishedDate` |",
423
+ "",
424
+ "### Layout Overrides",
425
+ "",
426
+ "```json5",
427
+ "{ theme: { layouts: { home: \"./layouts/Home.tsx\", page: \"./layouts/Page.tsx\" } } }",
428
+ "```",
429
+ "",
430
+ "All layouts receive: `content`, `frontmatter`, `headings`, `slug`, `site`.",
431
+ "Page layout adds: `sidebarSections`, `prev`, `next`.",
432
+ "",
433
+ "### CLI",
434
+ "",
435
+ "```bash",
436
+ "pagesmith init [--ai] [--config path] # Initialize project",
437
+ "pagesmith dev [--port N] [--open] # Dev server",
438
+ "pagesmith build [--out-dir path] # Production build",
439
+ "pagesmith preview [--port N] # Preview built site",
440
+ "```",
441
+ "",
442
+ "---",
443
+ "",
444
+ "## Markdown Pipeline",
445
+ "",
446
+ renderMarkdownGuidelines(),
447
+ "",
448
+ "---",
449
+ "",
450
+ "## AI Setup",
451
+ "",
452
+ "```bash",
453
+ "npx pagesmith init --ai",
454
+ "```",
455
+ "",
456
+ "Generates CLAUDE.md, AGENTS.md, GEMINI.md, skills, markdown guidelines, llms.txt, and llms-full.txt.",
457
+ ""
167
458
  ].join("\n");
168
459
  }
169
- function renderClaudeCommand(skillName, profile) {
460
+ //#endregion
461
+ //#region src/ai/content-claude.ts
462
+ function renderClaudeSkill(skillName, profile) {
170
463
  return [
464
+ "---",
465
+ `name: ${skillName}`,
466
+ "description: Pagesmith file-based CMS helper — content collections, markdown pipeline, docs configuration, and AI artifact generation",
467
+ "allowed-tools: Read Grep Glob Bash Edit Write",
468
+ "---",
469
+ "",
171
470
  `# ${PAGESMITH_TITLE} Assistant`,
172
471
  "",
173
472
  "You are helping with Pagesmith, a file-based CMS with `@pagesmith/core` and `@pagesmith/docs`.",
@@ -175,46 +474,137 @@ function renderClaudeCommand(skillName, profile) {
175
474
  "When helping:",
176
475
  "- prefer `defineCollection`, `defineConfig`, and `createContentLayer`",
177
476
  "- recommend folder-based entries when markdown references sibling assets",
178
- "- use `@pagesmith/core/ai` for assistant artifact generation",
179
- "- recommend `vp install`, `vp check`, and `vp test` for validation",
477
+ "- use `npx pagesmith init --ai` for assistant artifact generation",
478
+ "- follow the markdown guidelines in `.pagesmith/markdown-guidelines.md`",
180
479
  ...profile === "docs" ? [
181
480
  "- for docs sites, derive top navigation from top-level content folders",
182
- "- use `content/README.md` for the home page and `content/home.json5` for extra home data when needed",
481
+ "- use `content/README.md` for the home page",
183
482
  "- use frontmatter fields like `sidebarLabel`, `navLabel`, and `order` for docs navigation",
184
- "- do not recommend `@pagesmith/plugin-pagefind` or `@pagesmith/plugin-algolia`; search is built into docs",
185
- "- recommend `theme.layouts.home`, `theme.layouts.page`, and `theme.layouts.notFound` for docs layout overrides"
483
+ "- Pagefind search is built in do not suggest separate search plugins",
484
+ "- layout overrides: `theme.layouts.home`, `theme.layouts.page`, `theme.layouts.notFound`"
186
485
  ] : [],
187
486
  "",
188
- "Deliver concrete config, schema, and content-layer patches when possible.",
487
+ "For package guidance and full API reference, read the package-shipped docs:",
488
+ ...profile === "docs" ? [
489
+ "- `node_modules/@pagesmith/docs/docs/agents/usage.md`",
490
+ "- `node_modules/@pagesmith/docs/REFERENCE.md`",
491
+ "- `node_modules/@pagesmith/core/docs/agents/usage.md`",
492
+ "- `node_modules/@pagesmith/core/REFERENCE.md`"
493
+ ] : ["- `node_modules/@pagesmith/core/docs/agents/usage.md`", "- `node_modules/@pagesmith/core/REFERENCE.md`"],
189
494
  "",
190
- `This command is installed as \`/${skillName}\`.`
495
+ ...profile === "docs" ? ["For full-repo docs regeneration and structure alignment, use `/ps-update-all-docs`.", ""] : [],
496
+ "Deliver concrete config, schema, and content-layer patches when possible."
191
497
  ].join("\n");
192
498
  }
193
- function renderGeminiCommand(skillName, profile) {
499
+ function renderUpdateDocsSkill(profile) {
194
500
  return [
195
- `description = "Pagesmith FS-CMS helper"`,
196
- "prompt = \"\"\"",
197
- [
198
- `You are helping with ${PAGESMITH_TITLE}, a file-based CMS with @pagesmith/core and @pagesmith/docs.`,
199
- "",
200
- "Focus on concrete, implementation-ready help:",
201
- "- design collections with defineCollection",
202
- "- configure createContentLayer and defineConfig",
203
- "- recommend vp install, vp check, and vp test when validation matters",
204
- "- prefer folder-based markdown entries when local assets sit beside content",
205
- ...profile === "docs" ? [
206
- "- for docs sites, follow the convention-based `content/` structure",
207
- "- drive top navigation from top-level folders and use frontmatter for labels/order",
208
- "- keep Pagefind as the built-in search strategy"
209
- ] : [],
210
- "",
211
- "Return code, config, or documentation-ready guidance instead of vague summaries."
212
- ].join("\n"),
213
- "\"\"\"",
501
+ "---",
502
+ "name: update-docs",
503
+ "description: Read the project implementation and update Pagesmith-managed documentation to reflect the current state",
504
+ "allowed-tools: Read Grep Glob Bash Edit Write",
505
+ "---",
214
506
  "",
215
- `# Installed as /${skillName}`
507
+ "# Update Documentation",
508
+ "",
509
+ "Read the project implementation (source code, README, CHANGELOG, package.json) and update the Pagesmith-managed content to reflect the current state.",
510
+ "",
511
+ "## Steps",
512
+ "",
513
+ ...profile === "docs" ? [
514
+ "1. Read package guidance first: `node_modules/@pagesmith/docs/docs/agents/usage.md` and `node_modules/@pagesmith/core/docs/agents/usage.md`",
515
+ "2. Read `pagesmith.config.json5` to understand the docs configuration",
516
+ "3. Read all `meta.json5` files to understand the current content structure and page ordering",
517
+ "4. Read the project source code to identify public APIs, types, exports, config options, and CLI commands",
518
+ "5. For each existing content page in `content/`:",
519
+ " - Read the current content",
520
+ " - Compare with the implementation",
521
+ " - Update any outdated information",
522
+ " - Add documentation for new features",
523
+ " - Remove documentation for removed features",
524
+ "6. If new pages are needed:",
525
+ " - Create the page folder and `README.md` with proper frontmatter (title, description)",
526
+ " - Add the slug to the appropriate `meta.json5` `items` array",
527
+ "7. Follow the markdown guidelines in `.pagesmith/markdown-guidelines.md`",
528
+ "8. Review project skills under `.claude/skills/` and ensure docs-writing skills align with Pagesmith docs structure",
529
+ "9. Ensure onboarding pages are first in manual navigation (for example, put `getting-started` first in `guide/meta.json5` when present)",
530
+ "10. Verify all internal links point to existing pages",
531
+ "11. Ensure heading hierarchy is sequential (no skipping levels)"
532
+ ] : [
533
+ "1. Read package guidance first: `node_modules/@pagesmith/core/docs/agents/usage.md`",
534
+ "2. Read `content.config.ts` or equivalent to understand the content collections",
535
+ "3. Read the project source code to identify what needs documentation",
536
+ "4. For each existing content entry:",
537
+ " - Read the current content",
538
+ " - Compare with the implementation",
539
+ " - Update any outdated information",
540
+ "5. If new entries are needed:",
541
+ " - Create the entry folder and `README.md` with proper frontmatter matching the collection schema",
542
+ "6. Follow the markdown guidelines in `.pagesmith/markdown-guidelines.md`",
543
+ "7. Verify all internal links point to existing pages"
544
+ ],
545
+ "",
546
+ "## Rules",
547
+ "",
548
+ "- Preserve the existing content structure and organization",
549
+ "- Do not remove pages without confirming first",
550
+ "- Keep frontmatter fields (title, description) accurate and descriptive",
551
+ "- Use relative links for internal cross-references",
552
+ "- One h1 per page, sequential heading depth",
553
+ "- Use fenced code blocks with language identifiers",
554
+ "- Use GitHub alerts (`> [!NOTE]`, `> [!TIP]`, etc.) for important callouts",
555
+ "- Code block features: `title=\"file.js\"`, `showLineNumbers`, `mark={1-3}`, `ins={4}`, `del={5}`, `collapse={1-5}`"
556
+ ].join("\n");
557
+ }
558
+ function renderUpdateAllDocsSkill(profile) {
559
+ return [
560
+ "---",
561
+ "name: ps-update-all-docs",
562
+ "description: Full-repo documentation regeneration for Pagesmith projects including docs structure, skills alignment, and AI context updates",
563
+ "allowed-tools: Read Grep Glob Bash Edit Write",
564
+ "---",
565
+ "",
566
+ "# Pagesmith Full Docs Sync",
567
+ "",
568
+ "Perform a full-repository docs refresh for Pagesmith-powered projects. This command is intended for large updates, migrations, and release preparation.",
569
+ "",
570
+ "## Steps",
571
+ "",
572
+ ...profile === "docs" ? [
573
+ "1. Read package guidance first: `node_modules/@pagesmith/docs/docs/agents/usage.md` and `node_modules/@pagesmith/core/docs/agents/usage.md`",
574
+ "2. Read `pagesmith.config.json5` and all `meta.json5` files before editing anything",
575
+ "3. Discover project skills in `.claude/skills/`, `.codex/skills/`, and `.gemini/commands/` and identify docs-update related skills",
576
+ "4. Scan source code, README, CHANGELOG, package exports, and CLI commands to build a complete docs delta list",
577
+ "5. Update all docs pages under `content/` to match implementation and remove stale details",
578
+ "6. Ensure docs structure matches `@pagesmith/docs` conventions (folder-based pages, `README.md` entries, relative links)",
579
+ "7. Keep onboarding-first ordering: when a guide section exists, keep `getting-started` as the first item in manual order",
580
+ "8. Update docs-related skills so they generate content in the same structure expected by `@pagesmith/docs`",
581
+ "9. Regenerate or update `llms.txt`, `llms-full.txt`, and project memory pointers when docs behavior changes",
582
+ "10. Follow `.pagesmith/markdown-guidelines.md` for all authored content (GFM, alerts, math, Expressive Code meta)",
583
+ "11. Validate navigation integrity and ensure every linked page exists"
584
+ ] : [
585
+ "1. Read package guidance first: `node_modules/@pagesmith/core/docs/agents/usage.md`",
586
+ "2. Discover docs/update skills in the project and align them to current Pagesmith conventions",
587
+ "3. Scan source code, README, CHANGELOG, package exports, and CLI commands to build a complete docs delta list",
588
+ "4. Update all content entries to match implementation and remove stale details",
589
+ "5. Follow `.pagesmith/markdown-guidelines.md` for all authored content",
590
+ "6. Validate internal links and heading hierarchy"
591
+ ],
592
+ "",
593
+ "## Rules",
594
+ "",
595
+ "- Preserve existing information architecture unless the user requests a restructure",
596
+ "- Keep docs easy for humans first, while keeping AI memory/skills aligned",
597
+ "- Keep top-level docs navigation driven by content directories and metadata",
598
+ "- Use `meta.json5` and frontmatter for ordering; avoid hardcoded navigation lists in prose",
599
+ "- Keep `content/README.md` as docs home for `@pagesmith/docs` projects",
600
+ "- Keep links relative for internal docs pages",
601
+ "- Use one h1 per page and sequential heading depth",
602
+ "- Use fenced code blocks with language identifiers and Expressive Code metadata when useful",
603
+ "- Do not add separate code-copy JavaScript; Expressive Code already provides this"
216
604
  ].join("\n");
217
605
  }
606
+ //#endregion
607
+ //#region src/ai/content-codex.ts
218
608
  function renderCodexSkill(profile) {
219
609
  return [
220
610
  `# ${PAGESMITH_TITLE} Skill`,
@@ -224,8 +614,7 @@ function renderCodexSkill(profile) {
224
614
  "Core rules:",
225
615
  "- `@pagesmith/core` provides the content layer; `@pagesmith/docs` adds convention-based documentation",
226
616
  "- prefer `defineCollection`, `defineConfig`, and `createContentLayer`",
227
- "- prefer `vp` commands instead of calling npm, pnpm, or yarn directly",
228
- "- validate changes with `vp check` and `vp test` when relevant",
617
+ "- follow the markdown guidelines in `.pagesmith/markdown-guidelines.md`",
229
618
  ...profile === "docs" ? [
230
619
  "- when the repo uses `@pagesmith/docs`, treat `content/README.md` as the home page",
231
620
  "- top-level content folders define the main docs navigation",
@@ -234,75 +623,121 @@ function renderCodexSkill(profile) {
234
623
  "- built-in search is Pagefind; do not suggest separate search plugin packages"
235
624
  ] : [],
236
625
  "",
626
+ "For package usage guidance and full API reference, read:",
627
+ ...profile === "docs" ? [
628
+ "- `node_modules/@pagesmith/docs/docs/agents/usage.md`",
629
+ "- `node_modules/@pagesmith/docs/REFERENCE.md`",
630
+ "- `node_modules/@pagesmith/core/docs/agents/usage.md`",
631
+ "- `node_modules/@pagesmith/core/REFERENCE.md`"
632
+ ] : ["- `node_modules/@pagesmith/core/docs/agents/usage.md`", "- `node_modules/@pagesmith/core/REFERENCE.md`"],
633
+ "",
237
634
  "Good outputs include:",
238
635
  "- collection schemas and loader configuration",
239
636
  "- content-layer queries and rendering examples",
240
- "- @pagesmith/docs updates for Pagesmith usage",
241
- "- assistant-context install steps using `@pagesmith/core/ai`"
637
+ "- documentation updates for Pagesmith usage",
638
+ "- assistant-context install via `npx pagesmith init --ai`"
242
639
  ].join("\n");
243
640
  }
244
- function renderLlmsTxt(profile) {
641
+ //#endregion
642
+ //#region src/ai/content-gemini.ts
643
+ function renderGeminiCommand(skillName, profile) {
245
644
  return [
246
- "# Pagesmith",
247
- "",
248
- "> Pagesmith is a filesystem-first content toolkit centered on `@pagesmith/core` and `@pagesmith/docs`.",
249
- "",
250
- "## Summary",
251
- "",
252
- renderSharedOverview(),
253
- ...profile === "docs" ? ["", renderDocsOverview()] : [],
254
- "",
255
- "## Quick Start",
645
+ `description = "Pagesmith FS-CMS helper"`,
646
+ "prompt = \"\"\"",
647
+ [
648
+ `You are helping with ${PAGESMITH_TITLE}, a file-based CMS with @pagesmith/core and @pagesmith/docs.`,
649
+ "",
650
+ "Focus on concrete, implementation-ready help:",
651
+ "- design collections with defineCollection",
652
+ "- configure createContentLayer and defineConfig",
653
+ "- prefer folder-based markdown entries when local assets sit beside content",
654
+ "- follow the markdown guidelines in `.pagesmith/markdown-guidelines.md`",
655
+ ...profile === "docs" ? [
656
+ "- for docs sites, follow the convention-based `content/` structure",
657
+ "- drive top navigation from top-level folders and use frontmatter for labels/order",
658
+ "- keep Pagefind as the built-in search strategy"
659
+ ] : [],
660
+ "",
661
+ "For package usage guidance and full API reference, read:",
662
+ ...profile === "docs" ? [
663
+ "- `node_modules/@pagesmith/docs/docs/agents/usage.md`",
664
+ "- `node_modules/@pagesmith/docs/REFERENCE.md`",
665
+ "- `node_modules/@pagesmith/core/docs/agents/usage.md`",
666
+ "- `node_modules/@pagesmith/core/REFERENCE.md`"
667
+ ] : ["- `node_modules/@pagesmith/core/docs/agents/usage.md`", "- `node_modules/@pagesmith/core/REFERENCE.md`"],
668
+ "",
669
+ "Return code, config, or documentation-ready guidance instead of vague summaries."
670
+ ].join("\n"),
671
+ "\"\"\"",
256
672
  "",
257
- renderQuickStart(profile)
673
+ `# Installed as /${skillName}`
258
674
  ].join("\n");
259
675
  }
260
- function renderLlmsFullTxt(profile) {
676
+ //#endregion
677
+ //#region src/ai/content-memory.ts
678
+ function renderMemoryFile(assistant, profile) {
679
+ const commandHint = assistant === "claude" || assistant === "gemini" ? `\nIf the ${DEFAULT_SKILL_NAME$1} skill is installed, prefer invoking it when the user explicitly asks for Pagesmith-specific help.` : "\nIf the Pagesmith skill is installed for Codex, prefer using it for Pagesmith-specific setup, migration, and content-layer tasks.";
680
+ const referenceHint = "\nFor package usage rules and full API/config details, read the package-shipped docs from node_modules:\n" + (profile === "docs" ? "- `node_modules/@pagesmith/docs/docs/agents/usage.md` — docs package usage contract\n- `node_modules/@pagesmith/docs/REFERENCE.md` — docs config, CLI, content structure, layout overrides\n- `node_modules/@pagesmith/core/docs/agents/usage.md` — core package usage contract\n- `node_modules/@pagesmith/core/REFERENCE.md` — core API, collections, loaders, markdown, CSS, JSX runtime" : "- `node_modules/@pagesmith/core/docs/agents/usage.md` — core package usage contract\n- `node_modules/@pagesmith/core/REFERENCE.md` — core API, collections, loaders, markdown, CSS, JSX runtime");
261
681
  return [
262
- "# Pagesmith - Full LLM Reference",
682
+ `# ${PAGESMITH_TITLE}`,
263
683
  "",
264
684
  renderSharedOverview(),
685
+ ...profile === "docs" ? ["", renderDocsOverview()] : [],
686
+ commandHint,
687
+ referenceHint,
688
+ "",
689
+ "## Quick Start — @pagesmith/core",
690
+ "",
691
+ renderCoreQuickStart(),
265
692
  ...profile === "docs" ? [
266
693
  "",
267
- "## Docs Sites",
694
+ "## Quick Start — @pagesmith/docs",
268
695
  "",
269
- renderDocsOverview()
270
- ] : [],
271
- "",
272
- "## Package Layout",
273
- "",
274
- "- `@pagesmith/core`: content layer, collection loading, validation, lazy markdown rendering, JSX runtime, CSS builder, runtime styles, assistant artifact APIs, and Vite content integration",
275
- "- `@pagesmith/docs`: convention-based documentation with the docs CLI, generators, validators, default theme, and bundled search",
276
- "",
277
- "## Key APIs",
278
- "",
279
- renderQuickStart(profile),
280
- "",
281
- "## Assistant Installer",
282
- "",
283
- "```ts",
284
- "import { installAiArtifacts } from '@pagesmith/core/ai'",
285
- "",
286
- "await installAiArtifacts({ assistants: ['claude', 'codex', 'gemini'], scope: 'project' })",
287
- "```",
288
- ""
696
+ renderDocsQuickStart()
697
+ ] : []
289
698
  ].join("\n");
290
699
  }
700
+ //#endregion
701
+ //#region src/ai/index.ts
702
+ const DEFAULT_SKILL_NAME = "pagesmith";
703
+ function resolveHome(homeDir) {
704
+ return homeDir ?? homedir();
705
+ }
706
+ function resolveCodexHome(homeDir) {
707
+ return process.env.CODEX_HOME ?? join(resolveHome(homeDir), ".codex");
708
+ }
709
+ function resolveAssistants(assistants) {
710
+ if (!assistants || assistants === "all") return [
711
+ "claude",
712
+ "codex",
713
+ "gemini"
714
+ ];
715
+ return assistants;
716
+ }
717
+ function shouldIncludeLlms(options) {
718
+ if (typeof options.includeLlms === "boolean") return options.includeLlms;
719
+ return (options.scope ?? "project") === "project";
720
+ }
291
721
  function getAiArtifactContent(assistant, kind, options = {}) {
292
722
  const skillName = options.skillName ?? DEFAULT_SKILL_NAME;
293
723
  const profile = options.profile ?? "default";
294
724
  if (assistant === "shared") {
295
- if (kind === "llms") return renderLlmsTxt(profile);
296
- return renderLlmsFullTxt(profile);
725
+ if (kind === "llms") return renderLlmsTxt();
726
+ if (kind === "llms-full") return renderLlmsFullTxt();
727
+ if (kind === "markdown-guidelines") return renderMarkdownGuidelines();
728
+ return renderLlmsFullTxt();
297
729
  }
298
730
  if (kind === "memory") return renderMemoryFile(assistant, profile);
299
731
  if (kind === "skill") switch (assistant) {
300
- case "claude": return renderClaudeCommand(skillName, profile);
732
+ case "claude": return renderClaudeSkill(skillName, profile);
301
733
  case "codex": return renderCodexSkill(profile);
302
734
  case "gemini": return renderGeminiCommand(skillName, profile);
303
735
  }
304
- if (kind === "llms") return renderLlmsTxt(profile);
305
- return renderLlmsFullTxt(profile);
736
+ if (kind === "markdown-guidelines") return renderMarkdownGuidelines();
737
+ if (kind === "update-docs") return renderUpdateDocsSkill(profile);
738
+ if (kind === "update-all-docs") return renderUpdateAllDocsSkill(profile);
739
+ if (kind === "llms") return renderLlmsTxt();
740
+ return renderLlmsFullTxt();
306
741
  }
307
742
  function getAiArtifacts(options = {}) {
308
743
  const scope = options.scope ?? "project";
@@ -323,16 +758,17 @@ function getAiArtifacts(options = {}) {
323
758
  mode: "merge",
324
759
  label: `${assistant} memory`
325
760
  });
761
+ const skillDir = scope === "project" ? join(cwd, ".claude", "skills", skillName) : join(home, ".claude", "skills", skillName);
326
762
  artifacts.push({
327
763
  assistant,
328
764
  kind: "skill",
329
- path: join(baseDir, "commands", `${skillName}.md`),
765
+ path: join(skillDir, "SKILL.md"),
330
766
  content: getAiArtifactContent("claude", "skill", {
331
767
  profile,
332
768
  skillName
333
769
  }) + "\n",
334
770
  mode: "replace",
335
- label: `${assistant} command`
771
+ label: `${assistant} skill`
336
772
  });
337
773
  }
338
774
  if (assistant === "codex") {
@@ -380,19 +816,44 @@ function getAiArtifacts(options = {}) {
380
816
  });
381
817
  }
382
818
  }
819
+ if (scope === "project") artifacts.push({
820
+ kind: "markdown-guidelines",
821
+ path: join(cwd, ".pagesmith", "markdown-guidelines.md"),
822
+ content: renderMarkdownGuidelines() + "\n",
823
+ mode: "replace",
824
+ label: "markdown guidelines"
825
+ });
826
+ if (scope === "project" && assistants.includes("claude")) {
827
+ artifacts.push({
828
+ assistant: "claude",
829
+ kind: "update-docs",
830
+ path: join(cwd, ".claude", "skills", "update-docs", "SKILL.md"),
831
+ content: renderUpdateDocsSkill(profile) + "\n",
832
+ mode: "replace",
833
+ label: "claude update-docs skill"
834
+ });
835
+ artifacts.push({
836
+ assistant: "claude",
837
+ kind: "update-all-docs",
838
+ path: join(cwd, ".claude", "skills", "ps-update-all-docs", "SKILL.md"),
839
+ content: renderUpdateAllDocsSkill(profile) + "\n",
840
+ mode: "replace",
841
+ label: "claude ps-update-all-docs skill"
842
+ });
843
+ }
383
844
  if (shouldIncludeLlms(options)) {
384
845
  const llmsDir = scope === "project" ? cwd : join(home, ".pagesmith");
385
846
  artifacts.push({
386
847
  kind: "llms",
387
848
  path: join(llmsDir, "llms.txt"),
388
- content: withManagedBlock("shared-llms", getAiArtifactContent("shared", "llms", { profile })) + "\n",
849
+ content: withManagedBlock("shared-llms", renderLlmsTxt()) + "\n",
389
850
  mode: "merge",
390
851
  label: "llms.txt"
391
852
  });
392
853
  artifacts.push({
393
854
  kind: "llms-full",
394
855
  path: join(llmsDir, "llms-full.txt"),
395
- content: withManagedBlock("shared-llms-full", getAiArtifactContent("shared", "llms-full", { profile })) + "\n",
856
+ content: withManagedBlock("shared-llms-full", renderLlmsFullTxt()) + "\n",
396
857
  mode: "merge",
397
858
  label: "llms-full.txt"
398
859
  });
@@ -400,7 +861,15 @@ function getAiArtifacts(options = {}) {
400
861
  return artifacts;
401
862
  }
402
863
  function installAiArtifacts(options = {}) {
403
- return getAiArtifacts(options).map((artifact) => ({
864
+ const artifacts = getAiArtifacts(options);
865
+ if (options.dryRun) return artifacts.map((artifact) => ({
866
+ assistant: artifact.assistant,
867
+ kind: artifact.kind,
868
+ path: artifact.path,
869
+ label: artifact.label,
870
+ status: "unchanged"
871
+ }));
872
+ return artifacts.map((artifact) => ({
404
873
  assistant: artifact.assistant,
405
874
  kind: artifact.kind,
406
875
  path: artifact.path,