@stritti/vitepress-plugin-openspec 0.7.1 → 0.8.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/plugin.d.ts CHANGED
@@ -6,45 +6,24 @@ import type { OpenSpecPluginOptions, WithOpenSpecOptions } from './types.js';
6
6
  *
7
7
  * Call this at the top of your `docs/.vitepress/config.ts` **before**
8
8
  * `defineConfig()` so the files exist when VitePress scans the source
9
- * directory for routes.
10
- *
11
- * @example
12
- * ```typescript
13
- * // docs/.vitepress/config.ts
14
- * import { defineConfig } from 'vitepress'
15
- * import path from 'node:path'
16
- * import { fileURLToPath } from 'node:url'
17
- * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'
18
- *
19
- * const __dirname = path.dirname(fileURLToPath(import.meta.url))
20
- * const specDir = path.resolve(__dirname, '../../openspec')
21
- *
22
- * // Generate pages before VitePress scans srcDir for routes
23
- * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })
24
- *
25
- * export default defineConfig({ ... })
26
- * ```
9
+ * directory for routes. In most cases `withOpenSpec()` (which calls this
10
+ * internally) is the simpler integration point.
11
+ *
12
+ * @returns true when pages were written; false when generation was skipped
13
+ * (missing or unreadable source, ambiguous source-directory detection) or
14
+ * failed.
15
+ * @throws if `outDir` is not a relative path inside `srcDir` (absolute,
16
+ * traversal, or empty).
27
17
  */
28
- export declare function generateOpenSpecPages(userOptions?: OpenSpecPluginOptions): void;
18
+ export declare function generateOpenSpecPages(userOptions?: OpenSpecPluginOptions): boolean;
29
19
  /**
30
- * VitePress plugin that reads an openspec/ directory and generates structured
31
- * Markdown documentation pages inside the VitePress source directory.
20
+ * Vite plugin that regenerates the openspec documentation pages whenever a
21
+ * file inside the openspec/ directory changes. This makes `vitepress dev`
22
+ * pick up spec edits without a manual restart.
32
23
  *
33
- * For the pages to be available on the first build (including CI), also call
34
- * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.
35
- *
36
- * @example
37
- * ```typescript
38
- * // .vitepress/config.ts
39
- * import { defineConfig } from 'vitepress'
40
- * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'
41
- *
42
- * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })
43
- *
44
- * export default defineConfig({
45
- * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },
46
- * })
47
- * ```
24
+ * For the pages to be available on the first build (including CI), the pages
25
+ * are generated once in `configResolved`. When using `withOpenSpec()` this
26
+ * plugin is wired up automatically.
48
27
  */
49
28
  export declare function openspec(userOptions?: OpenSpecPluginOptions): Plugin;
50
29
  /**
@@ -55,24 +34,16 @@ export declare function openspec(userOptions?: OpenSpecPluginOptions): Plugin;
55
34
  * into the provided config object.
56
35
  *
57
36
  * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to
58
- * the array without replacing it:
59
- *
60
- * @example
61
- * ```typescript
62
- * // docs/.vitepress/config.ts
63
- * import { defineConfig } from 'vitepress'
64
- * import { withOpenSpec } from 'vitepress-plugin-openspec'
37
+ * the array without replacing it.
65
38
  *
66
- * export default defineConfig(
67
- * withOpenSpec({
68
- * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved
69
- * themeConfig: { nav: [], sidebar: {} },
70
- * })
71
- * )
72
- * ```
39
+ * When the VitePress source directory cannot be detected unambiguously
40
+ * (multiple `.vitepress` folders at the same level), a warning is emitted and
41
+ * the config is returned with only the sidebar shape normalized — nothing is
42
+ * generated or injected.
73
43
  *
74
44
  * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).
75
45
  * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.
46
+ * @throws if `outDir` is not a relative path inside `srcDir` (absolute, traversal, or empty).
76
47
  */
77
48
  export declare function withOpenSpec<T extends Record<string, unknown>>(config: T, options?: WithOpenSpecOptions): T;
78
49
  export default openspec;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,KAAK,EAAU,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAmBpF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,GAAE,qBAA0B,GAAG,IAAI,CA0EnF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CAAC,WAAW,GAAE,qBAA0B,GAAG,MAAM,CAYxE;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,MAAM,EAAE,CAAC,EACT,OAAO,GAAE,mBAAwB,GAChC,CAAC,CAsCH;eAEc,QAAQ"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAS5E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,GAAE,qBAA0B,GAAG,OAAO,CAQtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,WAAW,GAAE,qBAA0B,GAAG,MAAM,CAyFxE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,MAAM,EAAE,CAAC,EACT,OAAO,GAAE,mBAAwB,GAChC,CAAC,CA+DH;eAEc,QAAQ"}
package/dist/types.d.ts CHANGED
@@ -13,6 +13,11 @@ export interface WithOpenSpecOptions extends OpenSpecPluginOptions {
13
13
  * @default true
14
14
  */
15
15
  sidebar?: boolean;
16
+ /**
17
+ * Label for the nav entry injected into `themeConfig.nav`.
18
+ * @default 'Docs'
19
+ */
20
+ navText?: string;
16
21
  }
17
22
  /**
18
23
  * Configuration options for the vitepress-plugin-openspec plugin.
@@ -21,13 +26,16 @@ export interface OpenSpecPluginOptions {
21
26
  /**
22
27
  * Path to the openspec/ directory of the project.
23
28
  *
24
- * Use an explicit path when your `openspec/` folder is not at the project root
25
- * (e.g. when `config.ts` lives inside `docs/.vitepress/`).
29
+ * By default the plugin walks up from the current working directory looking
30
+ * for an `openspec/` folder (skipping generated output recognized by its
31
+ * marker), so no configuration is needed when it lives at the project root.
32
+ * Set an explicit path only for custom locations.
26
33
  *
27
34
  * If the directory does not exist a warning is printed and the build continues
28
35
  * without generating any pages or nav/sidebar entries — no error is thrown.
36
+ * An invalid `outDir` (absolute, empty, or escaping `srcDir`) throws instead.
29
37
  *
30
- * @default './openspec'
38
+ * @default auto-detected (`<nearest ancestor>/openspec`, falling back to `'./openspec'`)
31
39
  * @example
32
40
  * // Resolving from docs/.vitepress/config.ts
33
41
  * import path from 'node:path'
@@ -44,10 +52,12 @@ export interface OpenSpecPluginOptions {
44
52
  outDir?: string;
45
53
  /**
46
54
  * VitePress source directory — the directory containing your `.md` files
47
- * (i.e. the `docs/` folder). Required when calling `generateOpenSpecPages()`
48
- * at config evaluation time so it knows where to write the generated files.
55
+ * (i.e. the `docs/` folder). By default the plugin detects the directory that
56
+ * contains `.vitepress` (the working directory, a first-level subdirectory
57
+ * such as `docs/`, or the parent when the config is evaluated from inside
58
+ * `docs/.vitepress/`), so no configuration is needed for standard layouts.
49
59
  *
50
- * @default process.cwd()
60
+ * @default auto-detected (directory containing `.vitepress`, falling back to the working directory)
51
61
  * @example path.resolve(__dirname, '..') // from docs/.vitepress/config.ts
52
62
  */
53
63
  srcDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE5D;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,qHAAqH;IACrH,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAA;IACX,uCAAuC;IACvC,SAAS,EAAE,cAAc,EAAE,CAAA;IAC3B,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAA;IACX,sDAAsD;IACtD,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,iEAAiE;IACjE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,sDAAsD;IACtD,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,WAAW,EAAE,CAAA;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE5D;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,qHAAqH;IACrH,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAA;IACX,uCAAuC;IACvC,SAAS,EAAE,cAAc,EAAE,CAAA;IAC3B,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAA;IACX,sDAAsD;IACtD,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,iEAAiE;IACjE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,sDAAsD;IACtD,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,WAAW,EAAE,CAAA;CACtB"}
package/dist/utils.d.ts CHANGED
@@ -1,60 +1,9 @@
1
- import type { CapabilitySpec, Change, NavItem, OpenSpecFolder, SidebarItem } from './types.js';
2
1
  /**
3
- * Scans an openspec/ directory and returns a structured representation of all
4
- * canonical specs, active changes, and archived changes.
5
- *
6
- * Throws if the directory does not exist.
2
+ * Compatibility re-exports. The implementation lives in `./lib/` modules;
3
+ * these named exports are kept stable for existing consumers.
7
4
  */
8
- export declare function readOpenSpecFolder(dir: string): OpenSpecFolder;
9
- /**
10
- * Generates VitePress Markdown for a canonical capability spec page.
11
- */
12
- export declare function generateSpecPage(spec: CapabilitySpec): string;
13
- /**
14
- * Generates the index page listing all canonical specs.
15
- */
16
- export declare function generateSpecsIndexPage(specs: CapabilitySpec[], outDir: string): string;
17
- /**
18
- * Generates the index page for a single change.
19
- */
20
- export declare function generateChangeIndexPage(change: Change, outDir: string): string;
21
- /**
22
- * Generates the changes overview page listing active and archived changes.
23
- */
24
- export declare function generateChangesIndexPage(folder: OpenSpecFolder, outDir: string): string;
25
- /**
26
- * Rewrites relative markdown links in an artifact file's content so that they
27
- * use absolute VitePress paths instead of paths relative to the original
28
- * openspec source directory.
29
- *
30
- * When artifact files (proposal.md, design.md, tasks.md) are copied from the
31
- * openspec source directory into the VitePress output directory, any relative
32
- * links they contain that reference other files within the openspec directory
33
- * must be rewritten to absolute VitePress paths — otherwise VitePress will
34
- * report them as dead links.
35
- *
36
- * Links that point outside the openspec root, absolute paths, HTTP URLs, and
37
- * anchor-only links are left unchanged.
38
- *
39
- * @param content - The markdown content of the artifact file.
40
- * @param srcFilePath - The absolute path of the source artifact file.
41
- * @param openspecRootDir - The absolute path of the openspec root directory.
42
- * @param outDir - The VitePress output directory name (e.g. `"openspec"`).
43
- * @returns The content with rewritten links.
44
- */
45
- export declare function rewriteRelativeLinks(content: string, srcFilePath: string, openspecRootDir: string, outDir: string): string;
46
- /**
47
- * Returns a VitePress sidebar configuration for the OpenSpec documentation.
48
- * Includes groups for Specifications, active Changes, and archived Changes.
49
- */
50
- export declare function generateOpenSpecSidebar(specDir: string, options?: {
51
- outDir?: string;
52
- }): SidebarItem[];
53
- /**
54
- * Returns a VitePress nav entry for the OpenSpec documentation section.
55
- */
56
- export declare function openspecNav(specDir: string, options?: {
57
- outDir?: string;
58
- text?: string;
59
- }): NavItem | null;
5
+ export { readOpenSpecFolder } from './lib/reader.js';
6
+ export { rewriteRelativeLinks } from './lib/links.js';
7
+ export { generateSpecPage, generateSpecsIndexPage, generateChangeIndexPage, generateChangesIndexPage, } from './lib/pages.js';
8
+ export { generateOpenSpecSidebar, openspecNav } from './lib/navigation.js';
60
9
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,cAAc,EACd,MAAM,EAEN,OAAO,EACP,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAA;AA0EnB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAoE9D;AA6DD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAe7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAetF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAuB9E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA8BvF;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,MAAM,CAoDR;AAgBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,WAAW,EAAE,CA+Cf;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,OAAO,GAAG,IAAI,CAUhB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stritti/vitepress-plugin-openspec",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "A VitePress plugin that integrates OpenSpec documentation into your VitePress site",
5
5
  "keywords": [
6
6
  "openspec",