@stritti/vitepress-plugin-openspec 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5,21 +5,20 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var fs = require('fs');
6
6
  var path = require('path');
7
7
  var pc = require('picocolors');
8
- var yaml = require('js-yaml');
8
+ var jsYaml = require('js-yaml');
9
9
 
10
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
11
 
12
12
  var fs__default = /*#__PURE__*/_interopDefault(fs);
13
13
  var path__default = /*#__PURE__*/_interopDefault(path);
14
14
  var pc__default = /*#__PURE__*/_interopDefault(pc);
15
- var yaml__default = /*#__PURE__*/_interopDefault(yaml);
16
15
 
17
16
  // src/plugin.ts
18
17
  function readOpenSpecYaml(dir) {
19
18
  const yamlPath = path__default.default.join(dir, ".openspec.yaml");
20
19
  if (!fs__default.default.existsSync(yamlPath)) return {};
21
20
  try {
22
- return yaml__default.default.load(fs__default.default.readFileSync(yamlPath, "utf-8")) ?? {};
21
+ return jsYaml.load(fs__default.default.readFileSync(yamlPath, "utf-8")) ?? {};
23
22
  } catch {
24
23
  return {};
25
24
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/plugin.ts"],"names":["path","fs","yaml","pc"],"mappings":";;;;;;;;;;;;;;;;;AAgBA,SAAS,iBAAiB,GAAA,EAAsC;AAC9D,EAAA,MAAM,QAAA,GAAWA,qBAAA,CAAK,IAAA,CAAK,GAAA,EAAK,gBAAgB,CAAA;AAChD,EAAA,IAAI,CAACC,mBAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,SAAU,EAAC;AACtC,EAAA,IAAI;AACF,IAAA,OAAQC,qBAAA,CAAK,KAAKD,mBAAA,CAAG,YAAA,CAAa,UAAU,OAAO,CAAC,KAAK,EAAC;AAAA,EAC5D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAEA,IAAM,YAAA,GAAuC;AAAA,EAC3C,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,MAAA;AAAA,EACN,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,MAAA;AAAA,EACN,OAAA,EAAS,SAAA;AAAA,EACT,KAAA,EAAO,OAAA;AAAA,EACP,MAAA,EAAQ,QAAA;AAAA,EACR,IAAA,EAAM,MAAA;AAAA,EACN,KAAA,EAAO,OAAA;AAAA,EACP,GAAA,EAAK,KAAA;AAAA,EACL,GAAA,EAAK,KAAA;AAAA,EACL,GAAA,EAAK,KAAA;AAAA,EACL,EAAA,EAAI,IAAA;AAAA,EACJ,EAAA,EAAI,IAAA;AAAA,EACJ,EAAA,EAAI,IAAA;AAAA,EACJ,EAAA,EAAI,IAAA;AAAA,EACJ,GAAA,EAAK,KAAA;AAAA,EACL,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,GAAA,EAAK,KAAA;AAAA,EACL,GAAA,EAAK,KAAA;AAAA,EACL,EAAA,EAAI,IAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEA,SAAS,cAAc,IAAA,EAAsB;AAC3C,EAAA,IAAI,CAAC,MAAM,OAAO,EAAA;AAClB,EAAA,OAAO,KACJ,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,IAAI,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA,EAAG,OAAO,IAAA;AAChC,IAAA,OAAO,YAAA,CAAa,IAAI,CAAA,IAAM,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,GAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAAA,EAC3E,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AACb;AAEA,SAAS,sBAAsB,OAAA,EAAqC;AAClE,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,uDAAuD,CAAA;AACnF,EAAA,OAAO,KAAA,GAAQ,CAAC,CAAA,EAAG,IAAA,EAAK,IAAK,MAAA;AAC/B;AAEA,SAAS,WAAW,GAAA,EAAkC;AACpD,EAAA,IAAI,CAAC,KAAK,OAAO,MAAA;AACjB,EAAA,IAAI,GAAA,YAAe,MAAM,OAAO,GAAA,CAAI,aAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAC7D,EAAA,OAAO,OAAO,GAAG,CAAA;AACnB;AAEA,SAAS,cAAc,GAAA,EAA+B;AACpD,EAAA,MAAM,YAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,UAAA,EAAY,QAAA,EAAU,OAAO,CAAA,EAAuB;AACtE,IAAA,IAAIA,mBAAA,CAAG,UAAA,CAAWD,qBAAA,CAAK,IAAA,CAAK,GAAA,EAAK,CAAA,EAAG,IAAI,CAAA,GAAA,CAAK,CAAC,CAAA,EAAG,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,SAAA;AACT;AAQO,SAAS,mBAAmB,GAAA,EAA6B;AAC9D,EAAA,MAAM,QAAA,GAAWA,qBAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACjC,EAAA,IAAI,CAACC,mBAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0DAAA,EAA6D,QAAQ,CAAA,CAAE,CAAA;AAAA,EACzF;AAGA,EAAA,MAAM,QAA0B,EAAC;AACjC,EAAA,MAAM,QAAA,GAAWD,qBAAA,CAAK,IAAA,CAAK,QAAA,EAAU,OAAO,CAAA;AAC5C,EAAA,IAAIC,mBAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC3B,IAAA,KAAA,MAAW,KAAA,IAASA,oBAAG,WAAA,CAAY,QAAA,EAAU,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA,EAAG;AACrE,MAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAY,EAAG;AAC1B,MAAA,MAAM,WAAWD,qBAAA,CAAK,IAAA,CAAK,QAAA,EAAU,KAAA,CAAM,MAAM,SAAS,CAAA;AAC1D,MAAA,IAAI,CAACC,mBAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC9B,MAAA,MAAM,OAAA,GAAUA,mBAAA,CAAG,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AACjD,MAAA,KAAA,CAAM,IAAA,CAAK;AAAA,QACT,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,KAAA,EAAO,sBAAsB,OAAO,CAAA;AAAA,QACpC,QAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,UAAA,GAAaD,qBAAA,CAAK,IAAA,CAAK,QAAA,EAAU,SAAS,CAAA;AAChD,EAAA,IAAIC,mBAAA,CAAG,UAAA,CAAW,UAAU,CAAA,EAAG;AAC7B,IAAA,KAAA,MAAW,KAAA,IAASA,oBAAG,WAAA,CAAY,UAAA,EAAY,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA,EAAG;AACvE,MAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAY,IAAK,KAAA,CAAM,SAAS,SAAA,EAAW;AACtD,MAAA,MAAM,SAAA,GAAYD,qBAAA,CAAK,IAAA,CAAK,UAAA,EAAY,MAAM,IAAI,CAAA;AAClD,MAAA,IAAI,CAACC,oBAAG,UAAA,CAAWD,qBAAA,CAAK,KAAK,SAAA,EAAW,gBAAgB,CAAC,CAAA,EAAG;AAC5D,MAAA,MAAM,IAAA,GAAO,iBAAiB,SAAS,CAAA;AACvC,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,OAAO,IAAA,CAAK,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,GAAI,MAAA;AAAA,QACzC,GAAA,EAAK,SAAA;AAAA,QACL,SAAA,EAAW,cAAc,SAAS,CAAA;AAAA,QAClC,WAAA,EAAa,UAAA,CAAW,IAAA,CAAK,OAAO;AAAA,OACrC,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,MAAM,kBAA4B,EAAC;AACnC,EAAA,MAAM,UAAA,GAAaA,qBAAA,CAAK,IAAA,CAAK,UAAA,EAAY,SAAS,CAAA;AAClD,EAAA,IAAIC,mBAAA,CAAG,UAAA,CAAW,UAAU,CAAA,EAAG;AAC7B,IAAA,KAAA,MAAW,KAAA,IAASA,oBAAG,WAAA,CAAY,UAAA,EAAY,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA,EAAG;AACvE,MAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAY,EAAG;AAC1B,MAAA,MAAM,SAAA,GAAYD,qBAAA,CAAK,IAAA,CAAK,UAAA,EAAY,MAAM,IAAI,CAAA;AAElD,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,4BAA4B,CAAA;AAC3D,MAAA,MAAM,YAAA,GAAe,QAAQ,CAAC,CAAA;AAC9B,MAAA,MAAM,IAAA,GAAO,KAAA,GAAQ,CAAC,CAAA,IAAK,KAAA,CAAM,IAAA;AACjC,MAAA,MAAM,IAAA,GAAO,iBAAiB,SAAS,CAAA;AACvC,MAAA,eAAA,CAAgB,IAAA,CAAK;AAAA,QACnB,IAAA;AAAA,QACA,OAAO,IAAA,CAAK,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,GAAI,MAAA;AAAA,QACzC,GAAA,EAAK,SAAA;AAAA,QACL,SAAA,EAAW,cAAc,SAAS,CAAA;AAAA,QAClC,WAAA,EAAa,UAAA,CAAW,IAAA,CAAK,OAAO,CAAA;AAAA,QACpC,YAAA;AAAA,QACA,mBAAmB,KAAA,CAAM;AAAA,OAC1B,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,SAAS,eAAA,EAAgB;AAC1D;AAMA,SAAS,uBAAuB,OAAA,EAAqC;AACnE,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,KAAA,CAAM,yDAAyD,CAAA;AACxF,EAAA,IAAI,CAAC,UAAU,OAAO,MAAA;AACtB,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,CAAC,CAAA,CAAE,IAAA,EAAK;AAC9B,EAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,iBAAiB,CAAA;AAClD,EAAA,IAAI,CAAC,eAAe,OAAO,MAAA;AAC3B,EAAA,IAAI,QAAA,GAAW,aAAA,CAAc,CAAC,CAAA,CAAE,IAAA,EAAK;AACrC,EAAA,IAAI,QAAA,CAAS,SAAS,GAAA,EAAK;AACzB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,WAAA,CAAY,GAAA,EAAK,GAAG,CAAA;AACzC,IAAA,QAAA,GAAA,CAAY,GAAA,GAAM,CAAA,GAAI,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,GAAI,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,IAAK,QAAA;AAAA,EAC3E;AACA,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,IAAA,EAAM,KAAK,CAAA;AACrC;AAEA,SAAS,kBAAkB,OAAA,EAAyB;AAClD,EAAA,MAAM,QAAA,GAAW,OAAA,CACd,KAAA,CAAM,IAAI,EACV,MAAA,CAAO,CAAC,IAAA,KAAS,CAAC,gDAAgD,IAAA,CAAK,IAAI,CAAC,CAAA,CAC5E,KAAK,IAAI,CAAA;AAEZ,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,SAAA,EAAW,MAAM,CAAA;AAC3C;AAEA,SAAS,mBAAmB,OAAA,EAAyB;AACnD,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AAChC,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI,UAAA,GAAa,KAAA;AAEjB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,uBAAuB,CAAA;AACxD,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA;AAEtC,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,IAAI,UAAA,EAAY,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AACjC,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,WAAA,EAAc,aAAA,CAAc,CAAC,CAAC,CAAA,CAAE,CAAA;AAC5C,MAAA,UAAA,GAAa,IAAA;AAAA,IACf,CAAA,MAAA,IAAW,aAAa,UAAA,EAAY;AAClC,MAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AACjB,MAAA,MAAA,CAAO,KAAK,EAAE,CAAA;AACd,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,MAAA,UAAA,GAAa,KAAA;AAAA,IACf,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IAClB;AAAA,EACF;AAEA,EAAA,IAAI,UAAA,EAAY,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AACjC,EAAA,OAAO,MAAA,CAAO,KAAK,IAAI,CAAA;AACzB;AASO,SAAS,iBAAiB,IAAA,EAA8B;AAC7D,EAAA,MAAM,WAAA,GAAc,sBAAA,CAAuB,IAAA,CAAK,OAAO,CAAA;AACvD,EAAA,MAAM,WAAA,GAAc,kBAAA,CAAmB,iBAAA,CAAkB,IAAA,CAAK,OAAO,CAAC,CAAA;AACtE,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,cAAA,EAAiB,WAAW,CAAA,CAAA,CAAG,CAAA;AAC1C,IAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AACA,EAAA,KAAA,CAAM,IAAA,CAAK,KAAK,IAAA,CAAK,KAAA,IAAS,cAAc,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACxD,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,IAAA,CAAK,WAAA,CAAY,OAAA,EAAS,CAAA;AAChC,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAKO,SAAS,sBAAA,CAAuB,OAAyB,MAAA,EAAwB;AACtF,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,CAAM,KAAK,kBAAkB,CAAA;AAC7B,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,KAAK,uDAAuD,CAAA;AAClE,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,KAAA,CAAM,KAAK,kCAAkC,CAAA;AAAA,EAC/C,CAAA,MAAO;AACL,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,KAAA,CAAM,IAAA,CAAK,CAAA,GAAA,EAAM,IAAA,CAAK,KAAA,IAAS,aAAA,CAAc,IAAA,CAAK,IAAI,CAAC,CAAA,GAAA,EAAM,MAAM,CAAA,OAAA,EAAU,IAAA,CAAK,IAAI,CAAA,EAAA,CAAI,CAAA;AAAA,IAC5F;AAAA,EACF;AACA,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAKO,SAAS,uBAAA,CAAwB,QAAgB,MAAA,EAAwB;AAC9E,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,CAAM,IAAA,CAAK,KAAK,MAAA,CAAO,KAAA,IAAS,cAAc,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,CAAA;AAC5D,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,IAAI,OAAO,WAAA,EAAa;AACtB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,aAAA,EAAgB,MAAA,CAAO,WAAW,CAAA,CAAE,CAAA;AAC/C,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AACA,EAAA,IAAI,OAAO,YAAA,EAAc;AACvB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,cAAA,EAAiB,MAAA,CAAO,YAAY,CAAA,CAAE,CAAA;AACjD,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AACA,EAAA,KAAA,CAAM,KAAK,cAAc,CAAA;AACzB,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,iBAAA,GAClB,CAAA,CAAA,EAAI,MAAM,CAAA,iBAAA,EAAoB,MAAA,CAAO,iBAAiB,CAAA,CAAA,GACtD,CAAA,CAAA,EAAI,MAAM,CAAA,SAAA,EAAY,OAAO,IAAI,CAAA,CAAA;AACrC,EAAA,KAAA,MAAW,QAAA,IAAY,OAAO,SAAA,EAAW;AACvC,IAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,CAAO,CAAC,EAAE,WAAA,EAAY,GAAI,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA;AACjE,IAAA,KAAA,CAAM,KAAK,CAAA,GAAA,EAAM,KAAK,KAAK,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,CAAG,CAAA;AAAA,EAClD;AACA,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAKO,SAAS,wBAAA,CAAyB,QAAwB,MAAA,EAAwB;AACvF,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,CAAM,KAAK,WAAW,CAAA;AACtB,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAEb,EAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AAC/B,IAAA,KAAA,CAAM,KAAK,sBAAsB,CAAA;AAAA,EACnC,CAAA,MAAO;AACL,IAAA,KAAA,CAAM,KAAK,WAAW,CAAA;AACtB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,MAAW,MAAA,IAAU,OAAO,OAAA,EAAS;AACnC,MAAA,MAAM,OAAO,MAAA,CAAO,WAAA,GAAc,CAAA,GAAA,EAAM,MAAA,CAAO,WAAW,CAAA,EAAA,CAAA,GAAO,EAAA;AACjE,MAAA,KAAA,CAAM,IAAA,CAAK,CAAA,GAAA,EAAM,MAAA,CAAO,KAAA,IAAS,cAAc,MAAA,CAAO,IAAI,CAAC,CAAA,GAAA,EAAM,MAAM,CAAA,SAAA,EAAY,MAAA,CAAO,IAAI,CAAA,EAAA,EAAK,IAAI,CAAA,CAAE,CAAA;AAAA,IAC3G;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACrC,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,KAAK,WAAW,CAAA;AACtB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,MAAW,MAAA,IAAU,OAAO,eAAA,EAAiB;AAC3C,MAAA,MAAM,OAAO,MAAA,CAAO,YAAA,GAAe,CAAA,eAAA,EAAkB,MAAA,CAAO,YAAY,CAAA,EAAA,CAAA,GAAO,EAAA;AAC/E,MAAA,KAAA,CAAM,IAAA;AAAA,QACJ,CAAA,GAAA,EAAM,MAAA,CAAO,KAAA,IAAS,aAAA,CAAc,MAAA,CAAO,IAAI,CAAC,CAAA,GAAA,EAAM,MAAM,CAAA,iBAAA,EAAoB,MAAA,CAAO,iBAAiB,KAAK,IAAI,CAAA;AAAA,OACnH;AAAA,IACF;AAAA,EACF;AAEA,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AA0BO,SAAS,oBAAA,CACd,OAAA,EACA,WAAA,EACA,eAAA,EACA,MAAA,EACQ;AACR,EAAA,MAAM,MAAA,GAASA,qBAAA,CAAK,OAAA,CAAQ,WAAW,CAAA;AAEvC,EAAA,OAAO,OAAA,CAAQ,OAAA;AAAA,IACb,0BAAA;AAAA,IACA,CAAC,MAAA,EAAQ,QAAA,EAAkB,OAAA,KAAoB;AAE7C,MAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,CAAM,gCAAgC,CAAA;AACjE,MAAA,IAAI,CAAC,YAAY,OAAO,MAAA;AACxB,MAAA,MAAM,MAAA,GAAS,UAAA,CAAW,CAAC,CAAA,CAAE,IAAA,EAAK;AAClC,MAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,CAAC,CAAA,IAAK,EAAA;AAG/B,MAAA,IACE,CAAC,MAAA,IACD,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA,IAC3B,MAAA,CAAO,UAAA,CAAW,UAAU,CAAA,IAC5B,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA,IACtB,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA,IACrB,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA,IACrB,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA,IAC3B,MAAA,CAAO,UAAA,CAAW,MAAM,CAAA,EACxB;AACA,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA;AAClC,MAAA,MAAM,qBAAqB,OAAA,IAAW,CAAA,GAAI,OAAO,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,GAAI,MAAA;AACrE,MAAA,MAAM,WAAW,OAAA,IAAW,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,GAAI,EAAA;AAExD,MAAA,IAAI,CAAC,kBAAA,EAAoB;AAEvB,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,MAAM,YAAA,GAAeA,qBAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,kBAAkB,CAAA;AAG5D,MAAA,MAAM,aAAA,GAAgBA,qBAAA,CAAK,QAAA,CAAS,eAAA,EAAiB,YAAY,CAAA;AACjE,MAAA,IAAI,cAAc,UAAA,CAAW,IAAI,KAAKA,qBAAA,CAAK,UAAA,CAAW,aAAa,CAAA,EAAG;AACpE,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,MAAM,QAAA,GAAW,cAAc,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA,CAAE,OAAA,CAAQ,OAAO,GAAG,CAAA;AACtE,MAAA,MAAM,eAAe,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,EAAI,QAAQ,GAAG,QAAQ,CAAA,CAAA;AAEtD,MAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,YAAY,GAAG,KAAK,CAAA,CAAA,CAAA;AAAA,IAC5C;AAAA,GACF;AACF;AAMA,SAAS,WAAA,CAAY,MAAA,EAAgB,MAAA,EAAgB,UAAA,GAAa,KAAA,EAAsB;AACtF,EAAA,MAAM,MAAA,GAAS,UAAA,GACX,CAAA,CAAA,EAAI,MAAM,CAAA,iBAAA,EAAoB,MAAA,CAAO,iBAAiB,CAAA,CAAA,GACtD,CAAA,CAAA,EAAI,MAAM,CAAA,SAAA,EAAY,MAAA,CAAO,IAAI,CAAA,CAAA;AACrC,EAAA,OAAO,MAAA,CAAO,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IAClC,IAAA,EAAM,EAAE,MAAA,CAAO,CAAC,EAAE,WAAA,EAAY,GAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA;AAAA,IAC3C,IAAA,EAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA,GACtB,CAAE,CAAA;AACJ;AAMO,SAAS,uBAAA,CACd,OAAA,EACA,OAAA,GAA+B,EAAC,EACjB;AACf,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,UAAA;AACjC,EAAA,IAAI,CAACC,mBAAA,CAAG,UAAA,CAAWD,sBAAK,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG;AACzC,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,0DAAA,EAA6DA,qBAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,GAAA,EAAI,EAAGA,qBAAA,CAAK,OAAA,CAAQ,OAAO,CAAC,CAAC,CAAA,mCAAA,CAAgC,CAAA;AAC7J,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,MAAA,GAAS,mBAAmB,OAAO,CAAA;AACzC,EAAA,MAAM,SAAwB,EAAC;AAG/B,EAAA,MAAA,CAAO,IAAA,CAAK;AAAA,IACV,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,EAAW,KAAA;AAAA,IACX,KAAA,EAAO;AAAA,MACL,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,CAAA,OAAA,CAAA,EAAU;AAAA,MAC9C,GAAG,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,MAAM,CAAA,CAAE,KAAA,IAAS,cAAc,CAAA,CAAE,IAAI,GAAG,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,CAAA,OAAA,EAAU,CAAA,CAAE,IAAI,CAAA,CAAA,CAAA,EAAI,CAAE;AAAA;AAC9G,GACD,CAAA;AAGD,EAAA,MAAA,CAAO,IAAA,CAAK;AAAA,IACV,IAAA,EAAM,SAAA;AAAA,IACN,SAAA,EAAW,KAAA;AAAA,IACX,KAAA,EAAO;AAAA,MACL,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,CAAA,SAAA,CAAA,EAAY;AAAA,MAChD,GAAG,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QAC5B,IAAA,EAAM,CAAA,CAAE,KAAA,IAAS,aAAA,CAAc,EAAE,IAAI,CAAA;AAAA,QACrC,SAAA,EAAW,IAAA;AAAA,QACX,KAAA,EAAO,WAAA,CAAY,CAAA,EAAG,MAAM;AAAA,OAC9B,CAAE;AAAA;AACJ,GACD,CAAA;AAGD,EAAA,IAAI,MAAA,CAAO,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACrC,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,QAAA;AAAA,MACN,SAAA,EAAW,IAAA;AAAA,MACX,KAAA,EAAO,MAAA,CAAO,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACxC,IAAA,EAAM,CAAA,CAAE,KAAA,IAAS,aAAA,CAAc,EAAE,IAAI,CAAA;AAAA,QACrC,SAAA,EAAW,IAAA;AAAA,QACX,KAAA,EAAO,WAAA,CAAY,CAAA,EAAG,MAAA,EAAQ,IAAI;AAAA,OACpC,CAAE;AAAA,KACH,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,WAAA,CACd,OAAA,EACA,OAAA,GAA8C,EAAC,EAC/B;AAChB,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,UAAA;AACjC,EAAA,IAAI,CAACC,mBAAA,CAAG,UAAA,CAAWD,sBAAK,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG;AACzC,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,0DAAA,EAA6DA,qBAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,GAAA,EAAI,EAAGA,qBAAA,CAAK,OAAA,CAAQ,OAAO,CAAC,CAAC,CAAA,+BAAA,CAA4B,CAAA;AACzJ,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAQ,IAAA,IAAQ,MAAA;AAAA,IACtB,IAAA,EAAM,IAAI,MAAM,CAAA,CAAA;AAAA,GAClB;AACF;;;AC3dA,IAAM,WAAA,GAAc,2BAAA;AAEpB,SAAS,SAAA,CAAU,UAAkB,OAAA,EAAuB;AAC1D,EAAAC,mBAAAA,CAAG,UAAUD,qBAAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA;AACxD,EAAAC,mBAAAA,CAAG,aAAA,CAAc,QAAA,EAAU,OAAA,EAAS,OAAO,CAAA;AAC7C;AA2BO,SAAS,qBAAA,CAAsB,WAAA,GAAqC,EAAC,EAAS;AACnF,EAAA,MAAM,OAAA,GAAU,YAAY,OAAA,IAAW,YAAA;AACvC,EAAA,MAAM,MAAA,GAAS,YAAY,MAAA,IAAU,UAAA;AACrC,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAA,IAAU,OAAA,CAAQ,GAAA,EAAI;AACjD,EAAA,MAAM,cAAA,GAAiBD,qBAAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,MAAM,CAAA;AAElD,EAAA,IAAI,CAACC,mBAAAA,CAAG,UAAA,CAAWD,sBAAK,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG;AACzC,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,GAAGG,mBAAA,CAAG,IAAA,CAAKA,oBAAG,MAAA,CAAO,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,CAAG,CAAC,CAAC,CAAA,+BAAA,EAAkCH,sBAAK,QAAA,CAAS,MAAA,EAAQA,sBAAK,OAAA,CAAQ,OAAO,CAAC,CAAC,CAAA,gCAAA;AAAA,KACzH;AACA,IAAA;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,mBAAmB,OAAO,CAAA;AAGzC,IAAA,KAAA,MAAW,IAAA,IAAQ,OAAO,KAAA,EAAO;AAC/B,MAAA,MAAM,OAAOA,qBAAAA,CAAK,IAAA,CAAK,gBAAgB,OAAA,EAAS,IAAA,CAAK,MAAM,UAAU,CAAA;AACrE,MAAA,SAAA,CAAU,IAAA,EAAM,gBAAA,CAAiB,IAAI,CAAC,CAAA;AAAA,IACxC;AACA,IAAA,SAAA;AAAA,MACEA,qBAAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,OAAA,EAAS,UAAU,CAAA;AAAA,MAC7C,sBAAA,CAAuB,MAAA,CAAO,KAAA,EAAO,MAAM;AAAA,KAC7C;AAGA,IAAA,KAAA,MAAW,MAAA,IAAU,OAAO,OAAA,EAAS;AACnC,MAAA,eAAA,CAAgB,MAAA,EAAQ,cAAA,EAAgB,MAAA,EAAQ,KAAA,EAAO,OAAO,GAAG,CAAA;AAAA,IACnE;AAGA,IAAA,KAAA,MAAW,MAAA,IAAU,OAAO,eAAA,EAAiB;AAC3C,MAAA,eAAA,CAAgB,MAAA,EAAQ,cAAA,EAAgB,MAAA,EAAQ,IAAA,EAAM,OAAO,GAAG,CAAA;AAAA,IAClE;AAGA,IAAA,SAAA;AAAA,MACEA,qBAAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,SAAA,EAAW,UAAU,CAAA;AAAA,MAC/C,wBAAA,CAAyB,QAAQ,MAAM;AAAA,KACzC;AAGA,IAAA,MAAM,SAAA,GAAY;AAAA,MAChB,yBAAA;AAAA,MACA,EAAA;AAAA,MACA,wFAAA;AAAA,MACA,mFAAA;AAAA,MACA,sGAAA;AAAA,MACA,EAAA;AAAA,MACA,uBAAuB,MAAM,CAAA,0CAAA,CAAA;AAAA,MAC7B,gBAAgB,MAAM,CAAA,sDAAA,CAAA;AAAA,MACtB;AAAA,KACF,CAAE,KAAK,IAAI,CAAA;AACX,IAAA,SAAA,CAAUA,qBAAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,UAAU,GAAG,SAAS,CAAA;AAI1D,IAAA,SAAA;AAAA,MACEA,qBAAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,YAAY,CAAA;AAAA,MACtC;AAAA,KACF;AAEA,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,GAAGG,mBAAA,CAAG,IAAA,CAAKA,oBAAG,IAAA,CAAK,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,CAAG,CAAC,CAAC,CAAA,qBAAA,EAAwBA,oBAAG,IAAA,CAAK,OAAO,CAAC,CAAA,EAAA,EAC1EA,mBAAA,CAAG,MAAM,MAAA,CAAO,MAAA,CAAO,KAAA,CAAM,MAAM,CAAC,CAAC,CAAA,UAAA,EACrCA,oBAAG,KAAA,CAAM,MAAA,CAAO,OAAO,OAAA,CAAQ,MAAM,CAAC,CAAC,CAAA,YAAA,EACvCA,oBAAG,KAAA,CAAM,MAAA,CAAO,OAAO,eAAA,CAAgB,MAAM,CAAC,CAAC,CAAA,SAAA;AAAA,KACtD;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,KAAA;AAAA,MACN,CAAA,EAAGA,mBAAA,CAAG,IAAA,CAAKA,mBAAA,CAAG,IAAI,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,CAAG,CAAC,CAAC,CAAA,uCAAA,EAA0C,OAAO,CAAA,GAAA,EAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,KAC1G;AAAA,EACF;AACF;AAsBO,SAAS,QAAA,CAAS,WAAA,GAAqC,EAAC,EAAW;AACxE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IAET,eAAe,cAAA,EAAgB;AAC7B,MAAA,MAAM,WAAY,cAAA,CAAkE,SAAA;AACpF,MAAA,MAAM,MAAA,GACJ,YAAY,MAAA,IAAU,QAAA,EAAU,UAAU,cAAA,CAAe,IAAA,IAAQ,QAAQ,GAAA,EAAI;AAC/E,MAAA,qBAAA,CAAsB,EAAE,GAAG,WAAA,EAAa,MAAA,EAAQ,CAAA;AAAA,IAClD;AAAA,GACF;AACF;AAEA,SAAS,eAAA,CACP,MAAA,EACA,cAAA,EACA,MAAA,EACA,YACA,eAAA,EACM;AACN,EAAA,MAAM,UAAU,UAAA,GACZH,qBAAAA,CAAK,KAAK,SAAA,EAAW,SAAA,EAAW,GAAG,MAAA,CAAO,YAAY,CAAA,CAAA,EAAI,MAAA,CAAO,IAAI,CAAA,CAAE,CAAA,GACvEA,sBAAK,IAAA,CAAK,SAAA,EAAW,OAAO,IAAI,CAAA;AACpC,EAAA,MAAM,YAAA,GAAeA,qBAAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,OAAO,CAAA;AAGtD,EAAA,SAAA,CAAUA,qBAAAA,CAAK,KAAK,YAAA,EAAc,UAAU,GAAG,uBAAA,CAAwB,MAAA,EAAQ,MAAM,CAAC,CAAA;AAGtF,EAAA,KAAA,MAAW,QAAA,IAAY,OAAO,SAAA,EAAW;AACvC,IAAA,MAAM,UAAUA,qBAAAA,CAAK,IAAA,CAAK,OAAO,GAAA,EAAK,CAAA,EAAG,QAAQ,CAAA,GAAA,CAAK,CAAA;AACtD,IAAA,MAAM,WAAWA,qBAAAA,CAAK,IAAA,CAAK,YAAA,EAAc,CAAA,EAAG,QAAQ,CAAA,GAAA,CAAK,CAAA;AACzD,IAAA,MAAM,OAAA,GAAUC,mBAAAA,CAAG,YAAA,CAAa,OAAA,EAAS,OAAO,CAAA;AAChD,IAAA,SAAA,CAAU,UAAU,oBAAA,CAAqB,OAAA,EAAS,OAAA,EAAS,eAAA,EAAiB,MAAM,CAAC,CAAA;AAAA,EACrF;AACF;AA6BO,SAAS,YAAA,CACd,MAAA,EACA,OAAA,GAA+B,EAAC,EAC7B;AACH,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,YAAA;AACnC,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,UAAA;AACjC,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,IAAU,OAAA,CAAQ,GAAA,EAAI;AAE7C,EAAA,qBAAA,CAAsB,EAAE,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,CAAA;AAEjD,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,MAAA,EAAO;AAG3B,EAAA,MAAM,IAAA,GAAQ,MAAA,CAAO,IAAA,IAAQ,EAAC;AAC9B,EAAA,MAAM,eAAA,GAAmB,IAAA,CAAK,OAAA,IAAyB,EAAC;AACxD,EAAA,MAAA,CAAO,IAAA,GAAO,EAAE,GAAG,IAAA,EAAM,SAAS,CAAC,GAAG,eAAA,EAAiB,QAAA,CAAS,EAAE,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,CAAC,CAAA,EAAE;AAE9F,EAAA,MAAM,WAAA,GAAe,MAAA,CAAO,WAAA,IAAe,EAAC;AAG5C,EAAA,IAAI,OAAA,CAAQ,QAAQ,KAAA,EAAO;AACzB,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,OAAA,EAAS,EAAE,QAAQ,CAAA;AAChD,IAAA,MAAM,WAAA,GAAe,WAAA,CAAY,GAAA,IAAqB,EAAC;AACvD,IAAA,WAAA,CAAY,MAAM,QAAA,GAAW,CAAC,QAAA,EAAU,GAAG,WAAW,CAAA,GAAI,WAAA;AAAA,EAC5D;AAGA,EAAA,IAAI,OAAA,CAAQ,YAAY,KAAA,IAAS,CAAC,MAAM,OAAA,CAAQ,WAAA,CAAY,OAAO,CAAA,EAAG;AACpE,IAAA,MAAM,UAAA,GAAa,IAAI,MAAM,CAAA,CAAA,CAAA;AAC7B,IAAA,MAAM,eAAA,GAAmB,WAAA,CAAY,OAAA,IAAW,EAAC;AACjD,IAAA,IAAI,CAAC,eAAA,CAAgB,UAAU,CAAA,EAAG;AAChC,MAAA,WAAA,CAAY,OAAA,GAAU;AAAA,QACpB,GAAG,eAAA;AAAA,QACH,CAAC,UAAU,GAAG,wBAAwB,OAAA,EAAS,EAAE,QAAQ;AAAA,OAC3D;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,WAAA,GAAc,WAAA;AAErB,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport yaml from 'js-yaml'\nimport type {\n CapabilitySpec,\n Change,\n ChangeArtifact,\n NavItem,\n OpenSpecFolder,\n SidebarItem,\n} from './types.js'\n\n// ---------------------------------------------------------------------------\n// Folder reader\n// ---------------------------------------------------------------------------\n\nfunction readOpenSpecYaml(dir: string): Record<string, unknown> {\n const yamlPath = path.join(dir, '.openspec.yaml')\n if (!fs.existsSync(yamlPath)) return {}\n try {\n return (yaml.load(fs.readFileSync(yamlPath, 'utf-8')) ?? {}) as Record<string, unknown>\n } catch {\n return {}\n }\n}\n\nconst ACRONYM_DICT: Record<string, string> = {\n api: 'API',\n rest: 'REST',\n graphql: 'GraphQL',\n grpc: 'gRPC',\n openapi: 'OpenAPI',\n oauth: 'OAuth',\n oauth2: 'OAuth2',\n http: 'HTTP',\n https: 'HTTPS',\n url: 'URL',\n uri: 'URI',\n sdk: 'SDK',\n ui: 'UI',\n ux: 'UX',\n id: 'ID',\n db: 'DB',\n sql: 'SQL',\n css: 'CSS',\n html: 'HTML',\n json: 'JSON',\n yaml: 'YAML',\n xml: 'XML',\n jwt: 'JWT',\n ci: 'CI',\n cd: 'CD',\n}\n\nfunction humanizeLabel(name: string): string {\n if (!name) return ''\n return name\n .split('-')\n .map((word) => {\n if (/^v\\d+$/.test(word)) return word\n return ACRONYM_DICT[word] ?? (word.charAt(0).toUpperCase() + word.slice(1))\n })\n .join(' ')\n}\n\nfunction parseFrontmatterTitle(content: string): string | undefined {\n const match = content.match(/^---\\s*\\n(?:.*\\n)*?title:\\s*['\"]?([^\\n'\"]+)['\"]?\\s*\\n/)\n return match?.[1]?.trim() || undefined\n}\n\nfunction formatDate(val: unknown): string | undefined {\n if (!val) return undefined\n if (val instanceof Date) return val.toISOString().slice(0, 10)\n return String(val)\n}\n\nfunction readArtifacts(dir: string): ChangeArtifact[] {\n const artifacts: ChangeArtifact[] = []\n for (const name of ['proposal', 'design', 'tasks'] as ChangeArtifact[]) {\n if (fs.existsSync(path.join(dir, `${name}.md`))) artifacts.push(name)\n }\n return artifacts\n}\n\n/**\n * Scans an openspec/ directory and returns a structured representation of all\n * canonical specs, active changes, and archived changes.\n *\n * Throws if the directory does not exist.\n */\nexport function readOpenSpecFolder(dir: string): OpenSpecFolder {\n const resolved = path.resolve(dir)\n if (!fs.existsSync(resolved)) {\n throw new Error(`[vitepress-plugin-openspec] openspec directory not found: ${resolved}`)\n }\n\n // --- Canonical specs ---\n const specs: CapabilitySpec[] = []\n const specsDir = path.join(resolved, 'specs')\n if (fs.existsSync(specsDir)) {\n for (const entry of fs.readdirSync(specsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const specPath = path.join(specsDir, entry.name, 'spec.md')\n if (!fs.existsSync(specPath)) continue\n const content = fs.readFileSync(specPath, 'utf-8')\n specs.push({\n name: entry.name,\n title: parseFrontmatterTitle(content),\n specPath,\n content,\n })\n }\n }\n\n // --- Active changes ---\n const changes: Change[] = []\n const changesDir = path.join(resolved, 'changes')\n if (fs.existsSync(changesDir)) {\n for (const entry of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name === 'archive') continue\n const changeDir = path.join(changesDir, entry.name)\n if (!fs.existsSync(path.join(changeDir, '.openspec.yaml'))) continue\n const meta = readOpenSpecYaml(changeDir)\n changes.push({\n name: entry.name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n })\n }\n }\n\n // --- Archived changes ---\n const archivedChanges: Change[] = []\n const archiveDir = path.join(changesDir, 'archive')\n if (fs.existsSync(archiveDir)) {\n for (const entry of fs.readdirSync(archiveDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const changeDir = path.join(archiveDir, entry.name)\n // Parse YYYY-MM-DD-<name> format\n const match = entry.name.match(/^(\\d{4}-\\d{2}-\\d{2})-(.+)$/)\n const archivedDate = match?.[1]\n const name = match?.[2] ?? entry.name\n const meta = readOpenSpecYaml(changeDir)\n archivedChanges.push({\n name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n archivedDate,\n archiveFolderName: entry.name,\n })\n }\n }\n\n return { dir: resolved, specs, changes, archivedChanges }\n}\n\n// ---------------------------------------------------------------------------\n// Spec content transformations\n// ---------------------------------------------------------------------------\n\nfunction extractSpecDescription(content: string): string | undefined {\n const reqMatch = content.match(/^### Requirement:[^\\n]*\\n+([\\s\\S]*?)(?=\\n#{1,4} |\\n*$)/m)\n if (!reqMatch) return undefined\n const para = reqMatch[1].trim()\n if (!para) return undefined\n const sentenceMatch = para.match(/^([^.?!]+[.?!])/)\n if (!sentenceMatch) return undefined\n let sentence = sentenceMatch[1].trim()\n if (sentence.length > 160) {\n const cut = sentence.lastIndexOf(' ', 160)\n sentence = (cut > 0 ? sentence.slice(0, cut) : sentence.slice(0, 160)) + '…'\n }\n return sentence.replace(/\"/g, '\\\\\"')\n}\n\nfunction stripDeltaMarkers(content: string): string {\n const stripped = content\n .split('\\n')\n .filter((line) => !/^## (ADDED|MODIFIED|REMOVED) Requirements\\s*$/.test(line))\n .join('\\n')\n // Collapse consecutive blank lines to a single blank line\n return stripped.replace(/\\n{3,}/g, '\\n\\n')\n}\n\nfunction transformScenarios(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let inScenario = false\n\n for (const line of lines) {\n const scenarioMatch = line.match(/^#### Scenario: (.+)$/)\n const isHeading = /^#{1,6} /.test(line)\n\n if (scenarioMatch) {\n if (inScenario) result.push(':::')\n result.push(`:::details ${scenarioMatch[1]}`)\n inScenario = true\n } else if (isHeading && inScenario) {\n result.push(':::')\n result.push('')\n result.push(line)\n inScenario = false\n } else {\n result.push(line)\n }\n }\n\n if (inScenario) result.push(':::')\n return result.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Page generators\n// ---------------------------------------------------------------------------\n\n/**\n * Generates VitePress Markdown for a canonical capability spec page.\n */\nexport function generateSpecPage(spec: CapabilitySpec): string {\n const description = extractSpecDescription(spec.content)\n const transformed = transformScenarios(stripDeltaMarkers(spec.content))\n const lines: string[] = []\n if (description) {\n lines.push('---')\n lines.push(`description: \"${description}\"`)\n lines.push('---')\n lines.push('')\n }\n lines.push(`# ${spec.title ?? humanizeLabel(spec.name)}`)\n lines.push('')\n lines.push(transformed.trimEnd())\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page listing all canonical specs.\n */\nexport function generateSpecsIndexPage(specs: CapabilitySpec[], outDir: string): string {\n const lines: string[] = []\n lines.push('# Specifications')\n lines.push('')\n lines.push('Canonical capability specifications for this project.')\n lines.push('')\n if (specs.length === 0) {\n lines.push('*No specifications defined yet.*')\n } else {\n for (const spec of specs) {\n lines.push(`- [${spec.title ?? humanizeLabel(spec.name)}](/${outDir}/specs/${spec.name}/)`)\n }\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page for a single change.\n */\nexport function generateChangeIndexPage(change: Change, outDir: string): string {\n const lines: string[] = []\n lines.push(`# ${change.title ?? humanizeLabel(change.name)}`)\n lines.push('')\n if (change.createdDate) {\n lines.push(`**Created:** ${change.createdDate}`)\n lines.push('')\n }\n if (change.archivedDate) {\n lines.push(`**Archived:** ${change.archivedDate}`)\n lines.push('')\n }\n lines.push('## Artifacts')\n lines.push('')\n const prefix = change.archiveFolderName\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n for (const artifact of change.artifacts) {\n const label = artifact.charAt(0).toUpperCase() + artifact.slice(1)\n lines.push(`- [${label}](${prefix}/${artifact})`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the changes overview page listing active and archived changes.\n */\nexport function generateChangesIndexPage(folder: OpenSpecFolder, outDir: string): string {\n const lines: string[] = []\n lines.push('# Changes')\n lines.push('')\n\n if (folder.changes.length === 0) {\n lines.push('*No active changes.*')\n } else {\n lines.push('## Active')\n lines.push('')\n for (const change of folder.changes) {\n const date = change.createdDate ? ` *(${change.createdDate})*` : ''\n lines.push(`- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/${change.name}/)${date}`)\n }\n }\n\n if (folder.archivedChanges.length > 0) {\n lines.push('')\n lines.push('## Archiv')\n lines.push('')\n for (const change of folder.archivedChanges) {\n const date = change.archivedDate ? ` *(archiviert: ${change.archivedDate})*` : ''\n lines.push(\n `- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/archive/${change.archiveFolderName}/)${date}`,\n )\n }\n }\n\n lines.push('')\n return lines.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Artifact link rewriting\n// ---------------------------------------------------------------------------\n\n/**\n * Rewrites relative markdown links in an artifact file's content so that they\n * use absolute VitePress paths instead of paths relative to the original\n * openspec source directory.\n *\n * When artifact files (proposal.md, design.md, tasks.md) are copied from the\n * openspec source directory into the VitePress output directory, any relative\n * links they contain that reference other files within the openspec directory\n * must be rewritten to absolute VitePress paths — otherwise VitePress will\n * report them as dead links.\n *\n * Links that point outside the openspec root, absolute paths, HTTP URLs, and\n * anchor-only links are left unchanged.\n *\n * @param content - The markdown content of the artifact file.\n * @param srcFilePath - The absolute path of the source artifact file.\n * @param openspecRootDir - The absolute path of the openspec root directory.\n * @param outDir - The VitePress output directory name (e.g. `\"openspec\"`).\n * @returns The content with rewritten links.\n */\nexport function rewriteRelativeLinks(\n content: string,\n srcFilePath: string,\n openspecRootDir: string,\n outDir: string,\n): string {\n const srcDir = path.dirname(srcFilePath)\n\n return content.replace(\n /(\\[[^\\]]*\\])\\(([^)]+)\\)/g,\n (_match, linkText: string, urlPart: string) => {\n // Separate the URL from an optional quoted title: url \"title\" or url 'title'\n const titleMatch = urlPart.match(/^(.+?)(\\s+[\"'][^\"']*[\"'])?\\s*$/)\n if (!titleMatch) return _match\n const rawUrl = titleMatch[1].trim()\n const title = titleMatch[2] ?? ''\n\n // Leave non-relative URLs unchanged\n if (\n !rawUrl ||\n rawUrl.startsWith('http://') ||\n rawUrl.startsWith('https://') ||\n rawUrl.startsWith('//') ||\n rawUrl.startsWith('/') ||\n rawUrl.startsWith('#') ||\n rawUrl.startsWith('mailto:') ||\n rawUrl.startsWith('tel:')\n ) {\n return _match\n }\n\n // Separate the path component from any trailing fragment (#anchor)\n const hashIdx = rawUrl.indexOf('#')\n const urlWithoutFragment = hashIdx >= 0 ? rawUrl.slice(0, hashIdx) : rawUrl\n const fragment = hashIdx >= 0 ? rawUrl.slice(hashIdx) : ''\n\n if (!urlWithoutFragment) {\n // Pure anchor link — leave as-is\n return _match\n }\n\n // Resolve the relative path against the source file's directory\n const resolvedPath = path.resolve(srcDir, urlWithoutFragment)\n\n // Only rewrite links that remain within the openspec root directory\n const relToOpenspec = path.relative(openspecRootDir, resolvedPath)\n if (relToOpenspec.startsWith('..') || path.isAbsolute(relToOpenspec)) {\n return _match\n }\n\n // Build the absolute VitePress path, stripping any .md extension\n const vitePath = relToOpenspec.replace(/\\.md$/, '').replace(/\\\\/g, '/')\n const absoluteLink = `/${outDir}/${vitePath}${fragment}`\n\n return `${linkText}(${absoluteLink}${title})`\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Navigation helpers\n// ---------------------------------------------------------------------------\n\nfunction changeItems(change: Change, outDir: string, isArchived = false): SidebarItem[] {\n const prefix = isArchived\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n return change.artifacts.map((a) => ({\n text: a.charAt(0).toUpperCase() + a.slice(1),\n link: `${prefix}/${a}`,\n }))\n}\n\n/**\n * Returns a VitePress sidebar configuration for the OpenSpec documentation.\n * Includes groups for Specifications, active Changes, and archived Changes.\n */\nexport function generateOpenSpecSidebar(\n specDir: string,\n options: { outDir?: string } = {},\n): SidebarItem[] {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping sidebar generation`)\n return []\n }\n const folder = readOpenSpecFolder(specDir)\n const groups: SidebarItem[] = []\n\n // Specifications group\n groups.push({\n text: 'Specifications',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/specs/` },\n ...folder.specs.map((s) => ({ text: s.title ?? humanizeLabel(s.name), link: `/${outDir}/specs/${s.name}/` })),\n ],\n })\n\n // Changes group\n groups.push({\n text: 'Changes',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/changes/` },\n ...folder.changes.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir),\n })),\n ],\n })\n\n // Archive group (only if non-empty)\n if (folder.archivedChanges.length > 0) {\n groups.push({\n text: 'Archiv',\n collapsed: true,\n items: folder.archivedChanges.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir, true),\n })),\n })\n }\n\n return groups\n}\n\n/**\n * Returns a VitePress nav entry for the OpenSpec documentation section.\n */\nexport function openspecNav(\n specDir: string,\n options: { outDir?: string; text?: string } = {},\n): NavItem | null {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping nav generation`)\n return null\n }\n return {\n text: options.text ?? 'Docs',\n link: `/${outDir}/`,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport pc from 'picocolors'\nimport type { Plugin } from 'vite'\nimport type { Change, OpenSpecPluginOptions, WithOpenSpecOptions } from './types.js'\nimport {\n generateChangeIndexPage,\n generateChangesIndexPage,\n generateOpenSpecSidebar,\n generateSpecPage,\n generateSpecsIndexPage,\n openspecNav,\n readOpenSpecFolder,\n rewriteRelativeLinks,\n} from './utils.js'\n\nconst PLUGIN_NAME = 'vitepress-plugin-openspec'\n\nfunction writeFile(filePath: string, content: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, content, 'utf-8')\n}\n\n/**\n * Synchronously generates all VitePress Markdown pages from the openspec/\n * directory and writes them to disk.\n *\n * Call this at the top of your `docs/.vitepress/config.ts` **before**\n * `defineConfig()` so the files exist when VitePress scans the source\n * directory for routes.\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import path from 'node:path'\n * import { fileURLToPath } from 'node:url'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * const __dirname = path.dirname(fileURLToPath(import.meta.url))\n * const specDir = path.resolve(__dirname, '../../openspec')\n *\n * // Generate pages before VitePress scans srcDir for routes\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({ ... })\n * ```\n */\nexport function generateOpenSpecPages(userOptions: OpenSpecPluginOptions = {}): void {\n const specDir = userOptions.specDir ?? './openspec'\n const outDir = userOptions.outDir ?? 'openspec'\n const srcDir = userOptions.srcDir ?? process.cwd()\n const absoluteOutDir = path.resolve(srcDir, outDir)\n\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(\n `${pc.bold(pc.yellow(`[${PLUGIN_NAME}]`))} openspec directory not found: ${path.relative(srcDir, path.resolve(specDir))} — skipping page generation`,\n )\n return\n }\n\n try {\n const folder = readOpenSpecFolder(specDir)\n\n // --- Spec pages ---\n for (const spec of folder.specs) {\n const dest = path.join(absoluteOutDir, 'specs', spec.name, 'index.md')\n writeFile(dest, generateSpecPage(spec))\n }\n writeFile(\n path.join(absoluteOutDir, 'specs', 'index.md'),\n generateSpecsIndexPage(folder.specs, outDir),\n )\n\n // --- Active change pages ---\n for (const change of folder.changes) {\n writeChangePage(change, absoluteOutDir, outDir, false, folder.dir)\n }\n\n // --- Archived change pages ---\n for (const change of folder.archivedChanges) {\n writeChangePage(change, absoluteOutDir, outDir, true, folder.dir)\n }\n\n // --- Changes index ---\n writeFile(\n path.join(absoluteOutDir, 'changes', 'index.md'),\n generateChangesIndexPage(folder, outDir),\n )\n\n // --- Root index ---\n const rootIndex = [\n '# Project Documentation',\n '',\n \"This section is generated from the project's [OpenSpec](https://openspec.dev/) folder.\",\n 'OpenSpec is a lightweight, file-based workflow for spec-driven development —',\n 'it structures your project\\'s capability specifications and change proposals as plain Markdown files.',\n '',\n `- [Specifications](/${outDir}/specs/) — canonical capability specs`,\n `- [Changes](/${outDir}/changes/) — active and archived change proposals`,\n '',\n ].join('\\n')\n writeFile(path.join(absoluteOutDir, 'index.md'), rootIndex)\n\n // Write a self-managed .gitignore so consumers don't need to add the\n // output directory to their project-level .gitignore manually.\n writeFile(\n path.join(absoluteOutDir, '.gitignore'),\n '# Generated by vitepress-plugin-openspec — do not commit generated files.\\n*\\n!.gitignore\\n',\n )\n\n console.log(\n `${pc.bold(pc.cyan(`[${PLUGIN_NAME}]`))} Generated docs from ${pc.cyan(specDir)}: ` +\n `${pc.green(String(folder.specs.length))} spec(s), ` +\n `${pc.green(String(folder.changes.length))} change(s), ` +\n `${pc.green(String(folder.archivedChanges.length))} archived`,\n )\n } catch (err) {\n console.error(\n `${pc.bold(pc.red(`[${PLUGIN_NAME}]`))} Failed to process openspec directory \"${specDir}\": ${String(err)}`,\n )\n }\n}\n\n/**\n * VitePress plugin that reads an openspec/ directory and generates structured\n * Markdown documentation pages inside the VitePress source directory.\n *\n * For the pages to be available on the first build (including CI), also call\n * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.\n *\n * @example\n * ```typescript\n * // .vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({\n * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },\n * })\n * ```\n */\nexport function openspec(userOptions: OpenSpecPluginOptions = {}): Plugin {\n return {\n name: PLUGIN_NAME,\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n const vpConfig = (resolvedConfig as unknown as { vitepress?: { srcDir?: string } }).vitepress\n const srcDir =\n userOptions.srcDir ?? vpConfig?.srcDir ?? resolvedConfig.root ?? process.cwd()\n generateOpenSpecPages({ ...userOptions, srcDir })\n },\n }\n}\n\nfunction writeChangePage(\n change: Change,\n absoluteOutDir: string,\n outDir: string,\n isArchived: boolean,\n openspecRootDir: string,\n): void {\n const subPath = isArchived\n ? path.join('changes', 'archive', `${change.archivedDate}-${change.name}`)\n : path.join('changes', change.name)\n const changeOutDir = path.join(absoluteOutDir, subPath)\n\n // Write index page\n writeFile(path.join(changeOutDir, 'index.md'), generateChangeIndexPage(change, outDir))\n\n // Copy artifact files, rewriting relative links to absolute VitePress paths\n for (const artifact of change.artifacts) {\n const srcFile = path.join(change.dir, `${artifact}.md`)\n const destFile = path.join(changeOutDir, `${artifact}.md`)\n const content = fs.readFileSync(srcFile, 'utf-8')\n writeFile(destFile, rewriteRelativeLinks(content, srcFile, openspecRootDir, outDir))\n }\n}\n\n/**\n * One-call VitePress config helper that wires up the full openspec integration.\n *\n * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans\n * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section\n * into the provided config object.\n *\n * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to\n * the array without replacing it:\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import { withOpenSpec } from 'vitepress-plugin-openspec'\n *\n * export default defineConfig(\n * withOpenSpec({\n * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved\n * themeConfig: { nav: [], sidebar: {} },\n * })\n * )\n * ```\n *\n * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).\n * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.\n */\nexport function withOpenSpec<T extends Record<string, unknown>>(\n config: T,\n options: WithOpenSpecOptions = {},\n): T {\n const specDir = options.specDir ?? './openspec'\n const outDir = options.outDir ?? 'openspec'\n const srcDir = options.srcDir ?? process.cwd()\n\n generateOpenSpecPages({ specDir, outDir, srcDir })\n\n const result = { ...config } as Record<string, unknown>\n\n // --- Vite plugin ---\n const vite = (result.vite ?? {}) as Record<string, unknown>\n const existingPlugins = (vite.plugins as unknown[]) ?? []\n result.vite = { ...vite, plugins: [...existingPlugins, openspec({ specDir, outDir, srcDir })] }\n\n const themeConfig = (result.themeConfig ?? {}) as Record<string, unknown>\n\n // --- Nav ---\n if (options.nav !== false) {\n const navEntry = openspecNav(specDir, { outDir })\n const existingNav = (themeConfig.nav as unknown[]) ?? []\n themeConfig.nav = navEntry ? [navEntry, ...existingNav] : existingNav\n }\n\n // --- Sidebar ---\n if (options.sidebar !== false && !Array.isArray(themeConfig.sidebar)) {\n const sidebarKey = `/${outDir}/`\n const existingSidebar = (themeConfig.sidebar ?? {}) as Record<string, unknown>\n if (!existingSidebar[sidebarKey]) {\n themeConfig.sidebar = {\n ...existingSidebar,\n [sidebarKey]: generateOpenSpecSidebar(specDir, { outDir }),\n }\n }\n }\n\n result.themeConfig = themeConfig\n\n return result as T\n}\n\nexport default openspec\n"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/plugin.ts"],"names":["path","fs","yamlLoad","pc"],"mappings":"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","file":"index.cjs","sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport { load as yamlLoad } from 'js-yaml'\nimport type {\n CapabilitySpec,\n Change,\n ChangeArtifact,\n NavItem,\n OpenSpecFolder,\n SidebarItem,\n} from './types.js'\n\n// ---------------------------------------------------------------------------\n// Folder reader\n// ---------------------------------------------------------------------------\n\nfunction readOpenSpecYaml(dir: string): Record<string, unknown> {\n const yamlPath = path.join(dir, '.openspec.yaml')\n if (!fs.existsSync(yamlPath)) return {}\n try {\n return (yamlLoad(fs.readFileSync(yamlPath, 'utf-8')) ?? {}) as Record<string, unknown>\n } catch {\n return {}\n }\n}\n\nconst ACRONYM_DICT: Record<string, string> = {\n api: 'API',\n rest: 'REST',\n graphql: 'GraphQL',\n grpc: 'gRPC',\n openapi: 'OpenAPI',\n oauth: 'OAuth',\n oauth2: 'OAuth2',\n http: 'HTTP',\n https: 'HTTPS',\n url: 'URL',\n uri: 'URI',\n sdk: 'SDK',\n ui: 'UI',\n ux: 'UX',\n id: 'ID',\n db: 'DB',\n sql: 'SQL',\n css: 'CSS',\n html: 'HTML',\n json: 'JSON',\n yaml: 'YAML',\n xml: 'XML',\n jwt: 'JWT',\n ci: 'CI',\n cd: 'CD',\n}\n\nfunction humanizeLabel(name: string): string {\n if (!name) return ''\n return name\n .split('-')\n .map((word) => {\n if (/^v\\d+$/.test(word)) return word\n return ACRONYM_DICT[word] ?? (word.charAt(0).toUpperCase() + word.slice(1))\n })\n .join(' ')\n}\n\nfunction parseFrontmatterTitle(content: string): string | undefined {\n const match = content.match(/^---\\s*\\n(?:.*\\n)*?title:\\s*['\"]?([^\\n'\"]+)['\"]?\\s*\\n/)\n return match?.[1]?.trim() || undefined\n}\n\nfunction formatDate(val: unknown): string | undefined {\n if (!val) return undefined\n if (val instanceof Date) return val.toISOString().slice(0, 10)\n return String(val)\n}\n\nfunction readArtifacts(dir: string): ChangeArtifact[] {\n const artifacts: ChangeArtifact[] = []\n for (const name of ['proposal', 'design', 'tasks'] as ChangeArtifact[]) {\n if (fs.existsSync(path.join(dir, `${name}.md`))) artifacts.push(name)\n }\n return artifacts\n}\n\n/**\n * Scans an openspec/ directory and returns a structured representation of all\n * canonical specs, active changes, and archived changes.\n *\n * Throws if the directory does not exist.\n */\nexport function readOpenSpecFolder(dir: string): OpenSpecFolder {\n const resolved = path.resolve(dir)\n if (!fs.existsSync(resolved)) {\n throw new Error(`[vitepress-plugin-openspec] openspec directory not found: ${resolved}`)\n }\n\n // --- Canonical specs ---\n const specs: CapabilitySpec[] = []\n const specsDir = path.join(resolved, 'specs')\n if (fs.existsSync(specsDir)) {\n for (const entry of fs.readdirSync(specsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const specPath = path.join(specsDir, entry.name, 'spec.md')\n if (!fs.existsSync(specPath)) continue\n const content = fs.readFileSync(specPath, 'utf-8')\n specs.push({\n name: entry.name,\n title: parseFrontmatterTitle(content),\n specPath,\n content,\n })\n }\n }\n\n // --- Active changes ---\n const changes: Change[] = []\n const changesDir = path.join(resolved, 'changes')\n if (fs.existsSync(changesDir)) {\n for (const entry of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name === 'archive') continue\n const changeDir = path.join(changesDir, entry.name)\n if (!fs.existsSync(path.join(changeDir, '.openspec.yaml'))) continue\n const meta = readOpenSpecYaml(changeDir)\n changes.push({\n name: entry.name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n })\n }\n }\n\n // --- Archived changes ---\n const archivedChanges: Change[] = []\n const archiveDir = path.join(changesDir, 'archive')\n if (fs.existsSync(archiveDir)) {\n for (const entry of fs.readdirSync(archiveDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const changeDir = path.join(archiveDir, entry.name)\n // Parse YYYY-MM-DD-<name> format\n const match = entry.name.match(/^(\\d{4}-\\d{2}-\\d{2})-(.+)$/)\n const archivedDate = match?.[1]\n const name = match?.[2] ?? entry.name\n const meta = readOpenSpecYaml(changeDir)\n archivedChanges.push({\n name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n archivedDate,\n archiveFolderName: entry.name,\n })\n }\n }\n\n return { dir: resolved, specs, changes, archivedChanges }\n}\n\n// ---------------------------------------------------------------------------\n// Spec content transformations\n// ---------------------------------------------------------------------------\n\nfunction extractSpecDescription(content: string): string | undefined {\n const reqMatch = content.match(/^### Requirement:[^\\n]*\\n+([\\s\\S]*?)(?=\\n#{1,4} |\\n*$)/m)\n if (!reqMatch) return undefined\n const para = reqMatch[1].trim()\n if (!para) return undefined\n const sentenceMatch = para.match(/^([^.?!]+[.?!])/)\n if (!sentenceMatch) return undefined\n let sentence = sentenceMatch[1].trim()\n if (sentence.length > 160) {\n const cut = sentence.lastIndexOf(' ', 160)\n sentence = (cut > 0 ? sentence.slice(0, cut) : sentence.slice(0, 160)) + '…'\n }\n return sentence.replace(/\"/g, '\\\\\"')\n}\n\nfunction stripDeltaMarkers(content: string): string {\n const stripped = content\n .split('\\n')\n .filter((line) => !/^## (ADDED|MODIFIED|REMOVED) Requirements\\s*$/.test(line))\n .join('\\n')\n // Collapse consecutive blank lines to a single blank line\n return stripped.replace(/\\n{3,}/g, '\\n\\n')\n}\n\nfunction transformScenarios(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let inScenario = false\n\n for (const line of lines) {\n const scenarioMatch = line.match(/^#### Scenario: (.+)$/)\n const isHeading = /^#{1,6} /.test(line)\n\n if (scenarioMatch) {\n if (inScenario) result.push(':::')\n result.push(`:::details ${scenarioMatch[1]}`)\n inScenario = true\n } else if (isHeading && inScenario) {\n result.push(':::')\n result.push('')\n result.push(line)\n inScenario = false\n } else {\n result.push(line)\n }\n }\n\n if (inScenario) result.push(':::')\n return result.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Page generators\n// ---------------------------------------------------------------------------\n\n/**\n * Generates VitePress Markdown for a canonical capability spec page.\n */\nexport function generateSpecPage(spec: CapabilitySpec): string {\n const description = extractSpecDescription(spec.content)\n const transformed = transformScenarios(stripDeltaMarkers(spec.content))\n const lines: string[] = []\n if (description) {\n lines.push('---')\n lines.push(`description: \"${description}\"`)\n lines.push('---')\n lines.push('')\n }\n lines.push(`# ${spec.title ?? humanizeLabel(spec.name)}`)\n lines.push('')\n lines.push(transformed.trimEnd())\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page listing all canonical specs.\n */\nexport function generateSpecsIndexPage(specs: CapabilitySpec[], outDir: string): string {\n const lines: string[] = []\n lines.push('# Specifications')\n lines.push('')\n lines.push('Canonical capability specifications for this project.')\n lines.push('')\n if (specs.length === 0) {\n lines.push('*No specifications defined yet.*')\n } else {\n for (const spec of specs) {\n lines.push(`- [${spec.title ?? humanizeLabel(spec.name)}](/${outDir}/specs/${spec.name}/)`)\n }\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page for a single change.\n */\nexport function generateChangeIndexPage(change: Change, outDir: string): string {\n const lines: string[] = []\n lines.push(`# ${change.title ?? humanizeLabel(change.name)}`)\n lines.push('')\n if (change.createdDate) {\n lines.push(`**Created:** ${change.createdDate}`)\n lines.push('')\n }\n if (change.archivedDate) {\n lines.push(`**Archived:** ${change.archivedDate}`)\n lines.push('')\n }\n lines.push('## Artifacts')\n lines.push('')\n const prefix = change.archiveFolderName\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n for (const artifact of change.artifacts) {\n const label = artifact.charAt(0).toUpperCase() + artifact.slice(1)\n lines.push(`- [${label}](${prefix}/${artifact})`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the changes overview page listing active and archived changes.\n */\nexport function generateChangesIndexPage(folder: OpenSpecFolder, outDir: string): string {\n const lines: string[] = []\n lines.push('# Changes')\n lines.push('')\n\n if (folder.changes.length === 0) {\n lines.push('*No active changes.*')\n } else {\n lines.push('## Active')\n lines.push('')\n for (const change of folder.changes) {\n const date = change.createdDate ? ` *(${change.createdDate})*` : ''\n lines.push(`- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/${change.name}/)${date}`)\n }\n }\n\n if (folder.archivedChanges.length > 0) {\n lines.push('')\n lines.push('## Archiv')\n lines.push('')\n for (const change of folder.archivedChanges) {\n const date = change.archivedDate ? ` *(archiviert: ${change.archivedDate})*` : ''\n lines.push(\n `- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/archive/${change.archiveFolderName}/)${date}`,\n )\n }\n }\n\n lines.push('')\n return lines.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Artifact link rewriting\n// ---------------------------------------------------------------------------\n\n/**\n * Rewrites relative markdown links in an artifact file's content so that they\n * use absolute VitePress paths instead of paths relative to the original\n * openspec source directory.\n *\n * When artifact files (proposal.md, design.md, tasks.md) are copied from the\n * openspec source directory into the VitePress output directory, any relative\n * links they contain that reference other files within the openspec directory\n * must be rewritten to absolute VitePress paths — otherwise VitePress will\n * report them as dead links.\n *\n * Links that point outside the openspec root, absolute paths, HTTP URLs, and\n * anchor-only links are left unchanged.\n *\n * @param content - The markdown content of the artifact file.\n * @param srcFilePath - The absolute path of the source artifact file.\n * @param openspecRootDir - The absolute path of the openspec root directory.\n * @param outDir - The VitePress output directory name (e.g. `\"openspec\"`).\n * @returns The content with rewritten links.\n */\nexport function rewriteRelativeLinks(\n content: string,\n srcFilePath: string,\n openspecRootDir: string,\n outDir: string,\n): string {\n const srcDir = path.dirname(srcFilePath)\n\n return content.replace(\n /(\\[[^\\]]*\\])\\(([^)]+)\\)/g,\n (_match, linkText: string, urlPart: string) => {\n // Separate the URL from an optional quoted title: url \"title\" or url 'title'\n const titleMatch = urlPart.match(/^(.+?)(\\s+[\"'][^\"']*[\"'])?\\s*$/)\n if (!titleMatch) return _match\n const rawUrl = titleMatch[1].trim()\n const title = titleMatch[2] ?? ''\n\n // Leave non-relative URLs unchanged\n if (\n !rawUrl ||\n rawUrl.startsWith('http://') ||\n rawUrl.startsWith('https://') ||\n rawUrl.startsWith('//') ||\n rawUrl.startsWith('/') ||\n rawUrl.startsWith('#') ||\n rawUrl.startsWith('mailto:') ||\n rawUrl.startsWith('tel:')\n ) {\n return _match\n }\n\n // Separate the path component from any trailing fragment (#anchor)\n const hashIdx = rawUrl.indexOf('#')\n const urlWithoutFragment = hashIdx >= 0 ? rawUrl.slice(0, hashIdx) : rawUrl\n const fragment = hashIdx >= 0 ? rawUrl.slice(hashIdx) : ''\n\n if (!urlWithoutFragment) {\n // Pure anchor link — leave as-is\n return _match\n }\n\n // Resolve the relative path against the source file's directory\n const resolvedPath = path.resolve(srcDir, urlWithoutFragment)\n\n // Only rewrite links that remain within the openspec root directory\n const relToOpenspec = path.relative(openspecRootDir, resolvedPath)\n if (relToOpenspec.startsWith('..') || path.isAbsolute(relToOpenspec)) {\n return _match\n }\n\n // Build the absolute VitePress path, stripping any .md extension\n const vitePath = relToOpenspec.replace(/\\.md$/, '').replace(/\\\\/g, '/')\n const absoluteLink = `/${outDir}/${vitePath}${fragment}`\n\n return `${linkText}(${absoluteLink}${title})`\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Navigation helpers\n// ---------------------------------------------------------------------------\n\nfunction changeItems(change: Change, outDir: string, isArchived = false): SidebarItem[] {\n const prefix = isArchived\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n return change.artifacts.map((a) => ({\n text: a.charAt(0).toUpperCase() + a.slice(1),\n link: `${prefix}/${a}`,\n }))\n}\n\n/**\n * Returns a VitePress sidebar configuration for the OpenSpec documentation.\n * Includes groups for Specifications, active Changes, and archived Changes.\n */\nexport function generateOpenSpecSidebar(\n specDir: string,\n options: { outDir?: string } = {},\n): SidebarItem[] {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping sidebar generation`)\n return []\n }\n const folder = readOpenSpecFolder(specDir)\n const groups: SidebarItem[] = []\n\n // Specifications group\n groups.push({\n text: 'Specifications',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/specs/` },\n ...folder.specs.map((s) => ({ text: s.title ?? humanizeLabel(s.name), link: `/${outDir}/specs/${s.name}/` })),\n ],\n })\n\n // Changes group\n groups.push({\n text: 'Changes',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/changes/` },\n ...folder.changes.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir),\n })),\n ],\n })\n\n // Archive group (only if non-empty)\n if (folder.archivedChanges.length > 0) {\n groups.push({\n text: 'Archiv',\n collapsed: true,\n items: folder.archivedChanges.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir, true),\n })),\n })\n }\n\n return groups\n}\n\n/**\n * Returns a VitePress nav entry for the OpenSpec documentation section.\n */\nexport function openspecNav(\n specDir: string,\n options: { outDir?: string; text?: string } = {},\n): NavItem | null {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping nav generation`)\n return null\n }\n return {\n text: options.text ?? 'Docs',\n link: `/${outDir}/`,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport pc from 'picocolors'\nimport type { Plugin } from 'vite'\nimport type { Change, OpenSpecPluginOptions, WithOpenSpecOptions } from './types.js'\nimport {\n generateChangeIndexPage,\n generateChangesIndexPage,\n generateOpenSpecSidebar,\n generateSpecPage,\n generateSpecsIndexPage,\n openspecNav,\n readOpenSpecFolder,\n rewriteRelativeLinks,\n} from './utils.js'\n\nconst PLUGIN_NAME = 'vitepress-plugin-openspec'\n\nfunction writeFile(filePath: string, content: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, content, 'utf-8')\n}\n\n/**\n * Synchronously generates all VitePress Markdown pages from the openspec/\n * directory and writes them to disk.\n *\n * Call this at the top of your `docs/.vitepress/config.ts` **before**\n * `defineConfig()` so the files exist when VitePress scans the source\n * directory for routes.\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import path from 'node:path'\n * import { fileURLToPath } from 'node:url'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * const __dirname = path.dirname(fileURLToPath(import.meta.url))\n * const specDir = path.resolve(__dirname, '../../openspec')\n *\n * // Generate pages before VitePress scans srcDir for routes\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({ ... })\n * ```\n */\nexport function generateOpenSpecPages(userOptions: OpenSpecPluginOptions = {}): void {\n const specDir = userOptions.specDir ?? './openspec'\n const outDir = userOptions.outDir ?? 'openspec'\n const srcDir = userOptions.srcDir ?? process.cwd()\n const absoluteOutDir = path.resolve(srcDir, outDir)\n\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(\n `${pc.bold(pc.yellow(`[${PLUGIN_NAME}]`))} openspec directory not found: ${path.relative(srcDir, path.resolve(specDir))} — skipping page generation`,\n )\n return\n }\n\n try {\n const folder = readOpenSpecFolder(specDir)\n\n // --- Spec pages ---\n for (const spec of folder.specs) {\n const dest = path.join(absoluteOutDir, 'specs', spec.name, 'index.md')\n writeFile(dest, generateSpecPage(spec))\n }\n writeFile(\n path.join(absoluteOutDir, 'specs', 'index.md'),\n generateSpecsIndexPage(folder.specs, outDir),\n )\n\n // --- Active change pages ---\n for (const change of folder.changes) {\n writeChangePage(change, absoluteOutDir, outDir, false, folder.dir)\n }\n\n // --- Archived change pages ---\n for (const change of folder.archivedChanges) {\n writeChangePage(change, absoluteOutDir, outDir, true, folder.dir)\n }\n\n // --- Changes index ---\n writeFile(\n path.join(absoluteOutDir, 'changes', 'index.md'),\n generateChangesIndexPage(folder, outDir),\n )\n\n // --- Root index ---\n const rootIndex = [\n '# Project Documentation',\n '',\n \"This section is generated from the project's [OpenSpec](https://openspec.dev/) folder.\",\n 'OpenSpec is a lightweight, file-based workflow for spec-driven development —',\n 'it structures your project\\'s capability specifications and change proposals as plain Markdown files.',\n '',\n `- [Specifications](/${outDir}/specs/) — canonical capability specs`,\n `- [Changes](/${outDir}/changes/) — active and archived change proposals`,\n '',\n ].join('\\n')\n writeFile(path.join(absoluteOutDir, 'index.md'), rootIndex)\n\n // Write a self-managed .gitignore so consumers don't need to add the\n // output directory to their project-level .gitignore manually.\n writeFile(\n path.join(absoluteOutDir, '.gitignore'),\n '# Generated by vitepress-plugin-openspec — do not commit generated files.\\n*\\n!.gitignore\\n',\n )\n\n console.log(\n `${pc.bold(pc.cyan(`[${PLUGIN_NAME}]`))} Generated docs from ${pc.cyan(specDir)}: ` +\n `${pc.green(String(folder.specs.length))} spec(s), ` +\n `${pc.green(String(folder.changes.length))} change(s), ` +\n `${pc.green(String(folder.archivedChanges.length))} archived`,\n )\n } catch (err) {\n console.error(\n `${pc.bold(pc.red(`[${PLUGIN_NAME}]`))} Failed to process openspec directory \"${specDir}\": ${String(err)}`,\n )\n }\n}\n\n/**\n * VitePress plugin that reads an openspec/ directory and generates structured\n * Markdown documentation pages inside the VitePress source directory.\n *\n * For the pages to be available on the first build (including CI), also call\n * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.\n *\n * @example\n * ```typescript\n * // .vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({\n * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },\n * })\n * ```\n */\nexport function openspec(userOptions: OpenSpecPluginOptions = {}): Plugin {\n return {\n name: PLUGIN_NAME,\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n const vpConfig = (resolvedConfig as unknown as { vitepress?: { srcDir?: string } }).vitepress\n const srcDir =\n userOptions.srcDir ?? vpConfig?.srcDir ?? resolvedConfig.root ?? process.cwd()\n generateOpenSpecPages({ ...userOptions, srcDir })\n },\n }\n}\n\nfunction writeChangePage(\n change: Change,\n absoluteOutDir: string,\n outDir: string,\n isArchived: boolean,\n openspecRootDir: string,\n): void {\n const subPath = isArchived\n ? path.join('changes', 'archive', `${change.archivedDate}-${change.name}`)\n : path.join('changes', change.name)\n const changeOutDir = path.join(absoluteOutDir, subPath)\n\n // Write index page\n writeFile(path.join(changeOutDir, 'index.md'), generateChangeIndexPage(change, outDir))\n\n // Copy artifact files, rewriting relative links to absolute VitePress paths\n for (const artifact of change.artifacts) {\n const srcFile = path.join(change.dir, `${artifact}.md`)\n const destFile = path.join(changeOutDir, `${artifact}.md`)\n const content = fs.readFileSync(srcFile, 'utf-8')\n writeFile(destFile, rewriteRelativeLinks(content, srcFile, openspecRootDir, outDir))\n }\n}\n\n/**\n * One-call VitePress config helper that wires up the full openspec integration.\n *\n * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans\n * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section\n * into the provided config object.\n *\n * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to\n * the array without replacing it:\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import { withOpenSpec } from 'vitepress-plugin-openspec'\n *\n * export default defineConfig(\n * withOpenSpec({\n * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved\n * themeConfig: { nav: [], sidebar: {} },\n * })\n * )\n * ```\n *\n * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).\n * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.\n */\nexport function withOpenSpec<T extends Record<string, unknown>>(\n config: T,\n options: WithOpenSpecOptions = {},\n): T {\n const specDir = options.specDir ?? './openspec'\n const outDir = options.outDir ?? 'openspec'\n const srcDir = options.srcDir ?? process.cwd()\n\n generateOpenSpecPages({ specDir, outDir, srcDir })\n\n const result = { ...config } as Record<string, unknown>\n\n // --- Vite plugin ---\n const vite = (result.vite ?? {}) as Record<string, unknown>\n const existingPlugins = (vite.plugins as unknown[]) ?? []\n result.vite = { ...vite, plugins: [...existingPlugins, openspec({ specDir, outDir, srcDir })] }\n\n const themeConfig = (result.themeConfig ?? {}) as Record<string, unknown>\n\n // --- Nav ---\n if (options.nav !== false) {\n const navEntry = openspecNav(specDir, { outDir })\n const existingNav = (themeConfig.nav as unknown[]) ?? []\n themeConfig.nav = navEntry ? [navEntry, ...existingNav] : existingNav\n }\n\n // --- Sidebar ---\n if (options.sidebar !== false && !Array.isArray(themeConfig.sidebar)) {\n const sidebarKey = `/${outDir}/`\n const existingSidebar = (themeConfig.sidebar ?? {}) as Record<string, unknown>\n if (!existingSidebar[sidebarKey]) {\n themeConfig.sidebar = {\n ...existingSidebar,\n [sidebarKey]: generateOpenSpecSidebar(specDir, { outDir }),\n }\n }\n }\n\n result.themeConfig = themeConfig\n\n return result as T\n}\n\nexport default openspec\n"]}
package/dist/index.d.ts CHANGED
@@ -1,217 +1,4 @@
1
- import { Plugin } from 'vite';
2
-
3
- /**
4
- * Options for the `withOpenSpec()` config helper.
5
- * Extends `OpenSpecPluginOptions` with optional nav/sidebar merge controls.
6
- */
7
- interface WithOpenSpecOptions extends OpenSpecPluginOptions {
8
- /**
9
- * Whether to prepend an openspec nav entry to `themeConfig.nav`.
10
- * @default true
11
- */
12
- nav?: boolean;
13
- /**
14
- * Whether to inject the openspec sidebar section into `themeConfig.sidebar`.
15
- * @default true
16
- */
17
- sidebar?: boolean;
18
- }
19
- /**
20
- * Configuration options for the vitepress-plugin-openspec plugin.
21
- */
22
- interface OpenSpecPluginOptions {
23
- /**
24
- * Path to the openspec/ directory of the project.
25
- *
26
- * Use an explicit path when your `openspec/` folder is not at the project root
27
- * (e.g. when `config.ts` lives inside `docs/.vitepress/`).
28
- *
29
- * If the directory does not exist a warning is printed and the build continues
30
- * without generating any pages or nav/sidebar entries — no error is thrown.
31
- *
32
- * @default './openspec'
33
- * @example
34
- * // Resolving from docs/.vitepress/config.ts
35
- * import path from 'node:path'
36
- * import { fileURLToPath } from 'node:url'
37
- * const __dirname = path.dirname(fileURLToPath(import.meta.url))
38
- * const specDir = path.resolve(__dirname, '../../openspec')
39
- */
40
- specDir?: string;
41
- /**
42
- * Output directory (relative to VitePress `srcDir`) where the generated
43
- * Markdown pages will be written.
44
- * @default 'openspec'
45
- */
46
- outDir?: string;
47
- /**
48
- * VitePress source directory — the directory containing your `.md` files
49
- * (i.e. the `docs/` folder). Required when calling `generateOpenSpecPages()`
50
- * at config evaluation time so it knows where to write the generated files.
51
- *
52
- * @default process.cwd()
53
- * @example path.resolve(__dirname, '..') // from docs/.vitepress/config.ts
54
- */
55
- srcDir?: string;
56
- }
57
- /**
58
- * A canonical capability specification from openspec/specs/<name>/spec.md
59
- */
60
- interface CapabilitySpec {
61
- /** Folder name (kebab-case capability identifier) */
62
- name: string;
63
- /** Optional display title from spec.md frontmatter. Overrides humanized name. */
64
- title?: string;
65
- /** Absolute path to the spec.md file */
66
- specPath: string;
67
- /** Raw Markdown content of the spec */
68
- content: string;
69
- }
70
- /**
71
- * A single artifact (file) belonging to a Change.
72
- */
73
- type ChangeArtifact = 'proposal' | 'design' | 'tasks';
74
- /**
75
- * An OpenSpec change (active or archived).
76
- */
77
- interface Change {
78
- /** Change directory name (e.g. "my-feature" or for archived: "my-feature" extracted from "2026-03-10-my-feature") */
79
- name: string;
80
- /** Optional display title from .openspec.yaml. Overrides humanized name. */
81
- title?: string;
82
- /** Absolute path to the change directory */
83
- dir: string;
84
- /** Which artifact files are present */
85
- artifacts: ChangeArtifact[];
86
- /** Creation date from .openspec.yaml, if available */
87
- createdDate?: string;
88
- /** For archived changes: the archive date (YYYY-MM-DD) parsed from directory name */
89
- archivedDate?: string;
90
- /**
91
- * For archived changes: the original archive folder name (e.g. "2026-01-15-my-feature" or
92
- * "legacy-feature" for non-standard names). Used to build correct archive URLs.
93
- */
94
- archiveFolderName?: string;
95
- }
96
- /**
97
- * The full parsed structure of an openspec/ directory.
98
- */
99
- interface OpenSpecFolder {
100
- /** Absolute path to the openspec/ root */
101
- dir: string;
102
- /** Canonical capability specs from openspec/specs/ */
103
- specs: CapabilitySpec[];
104
- /** Active changes from openspec/changes/ (excluding archive/) */
105
- changes: Change[];
106
- /** Archived changes from openspec/changes/archive/ */
107
- archivedChanges: Change[];
108
- }
109
- /**
110
- * A nav item compatible with VitePress `DefaultTheme.NavItem`.
111
- */
112
- interface NavItem {
113
- text: string;
114
- link: string;
115
- }
116
- /**
117
- * A sidebar item compatible with VitePress `DefaultTheme.SidebarItem`.
118
- */
119
- interface SidebarItem {
120
- text: string;
121
- link?: string;
122
- collapsed?: boolean;
123
- items?: SidebarItem[];
124
- }
125
-
126
- /**
127
- * Synchronously generates all VitePress Markdown pages from the openspec/
128
- * directory and writes them to disk.
129
- *
130
- * Call this at the top of your `docs/.vitepress/config.ts` **before**
131
- * `defineConfig()` so the files exist when VitePress scans the source
132
- * directory for routes.
133
- *
134
- * @example
135
- * ```typescript
136
- * // docs/.vitepress/config.ts
137
- * import { defineConfig } from 'vitepress'
138
- * import path from 'node:path'
139
- * import { fileURLToPath } from 'node:url'
140
- * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'
141
- *
142
- * const __dirname = path.dirname(fileURLToPath(import.meta.url))
143
- * const specDir = path.resolve(__dirname, '../../openspec')
144
- *
145
- * // Generate pages before VitePress scans srcDir for routes
146
- * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })
147
- *
148
- * export default defineConfig({ ... })
149
- * ```
150
- */
151
- declare function generateOpenSpecPages(userOptions?: OpenSpecPluginOptions): void;
152
- /**
153
- * VitePress plugin that reads an openspec/ directory and generates structured
154
- * Markdown documentation pages inside the VitePress source directory.
155
- *
156
- * For the pages to be available on the first build (including CI), also call
157
- * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.
158
- *
159
- * @example
160
- * ```typescript
161
- * // .vitepress/config.ts
162
- * import { defineConfig } from 'vitepress'
163
- * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'
164
- *
165
- * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })
166
- *
167
- * export default defineConfig({
168
- * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },
169
- * })
170
- * ```
171
- */
172
- declare function openspec(userOptions?: OpenSpecPluginOptions): Plugin;
173
- /**
174
- * One-call VitePress config helper that wires up the full openspec integration.
175
- *
176
- * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans
177
- * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section
178
- * into the provided config object.
179
- *
180
- * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to
181
- * the array without replacing it:
182
- *
183
- * @example
184
- * ```typescript
185
- * // docs/.vitepress/config.ts
186
- * import { defineConfig } from 'vitepress'
187
- * import { withOpenSpec } from 'vitepress-plugin-openspec'
188
- *
189
- * export default defineConfig(
190
- * withOpenSpec({
191
- * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved
192
- * themeConfig: { nav: [], sidebar: {} },
193
- * })
194
- * )
195
- * ```
196
- *
197
- * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).
198
- * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.
199
- */
200
- declare function withOpenSpec<T extends Record<string, unknown>>(config: T, options?: WithOpenSpecOptions): T;
201
-
202
- /**
203
- * Returns a VitePress sidebar configuration for the OpenSpec documentation.
204
- * Includes groups for Specifications, active Changes, and archived Changes.
205
- */
206
- declare function generateOpenSpecSidebar(specDir: string, options?: {
207
- outDir?: string;
208
- }): SidebarItem[];
209
- /**
210
- * Returns a VitePress nav entry for the OpenSpec documentation section.
211
- */
212
- declare function openspecNav(specDir: string, options?: {
213
- outDir?: string;
214
- text?: string;
215
- }): NavItem | null;
216
-
217
- export { type CapabilitySpec, type Change, type ChangeArtifact, type NavItem, type OpenSpecFolder, type OpenSpecPluginOptions, type SidebarItem, type WithOpenSpecOptions, openspec as default, generateOpenSpecPages, generateOpenSpecSidebar, openspec, openspecNav, withOpenSpec };
1
+ export { openspec as default, openspec, generateOpenSpecPages, withOpenSpec } from './plugin.js';
2
+ export { generateOpenSpecSidebar, openspecNav } from './utils.js';
3
+ export type { CapabilitySpec, Change, ChangeArtifact, NavItem, OpenSpecFolder, OpenSpecPluginOptions, SidebarItem, WithOpenSpecOptions, } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAChG,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACjE,YAAY,EACV,cAAc,EACd,MAAM,EACN,cAAc,EACd,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,WAAW,EACX,mBAAmB,GACpB,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import pc from 'picocolors';
4
- import yaml from 'js-yaml';
4
+ import { load } from 'js-yaml';
5
5
 
6
6
  // src/plugin.ts
7
7
  function readOpenSpecYaml(dir) {
8
8
  const yamlPath = path.join(dir, ".openspec.yaml");
9
9
  if (!fs.existsSync(yamlPath)) return {};
10
10
  try {
11
- return yaml.load(fs.readFileSync(yamlPath, "utf-8")) ?? {};
11
+ return load(fs.readFileSync(yamlPath, "utf-8")) ?? {};
12
12
  } catch {
13
13
  return {};
14
14
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/plugin.ts"],"names":["fs","path"],"mappings":"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","file":"index.js","sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport yaml from 'js-yaml'\nimport type {\n CapabilitySpec,\n Change,\n ChangeArtifact,\n NavItem,\n OpenSpecFolder,\n SidebarItem,\n} from './types.js'\n\n// ---------------------------------------------------------------------------\n// Folder reader\n// ---------------------------------------------------------------------------\n\nfunction readOpenSpecYaml(dir: string): Record<string, unknown> {\n const yamlPath = path.join(dir, '.openspec.yaml')\n if (!fs.existsSync(yamlPath)) return {}\n try {\n return (yaml.load(fs.readFileSync(yamlPath, 'utf-8')) ?? {}) as Record<string, unknown>\n } catch {\n return {}\n }\n}\n\nconst ACRONYM_DICT: Record<string, string> = {\n api: 'API',\n rest: 'REST',\n graphql: 'GraphQL',\n grpc: 'gRPC',\n openapi: 'OpenAPI',\n oauth: 'OAuth',\n oauth2: 'OAuth2',\n http: 'HTTP',\n https: 'HTTPS',\n url: 'URL',\n uri: 'URI',\n sdk: 'SDK',\n ui: 'UI',\n ux: 'UX',\n id: 'ID',\n db: 'DB',\n sql: 'SQL',\n css: 'CSS',\n html: 'HTML',\n json: 'JSON',\n yaml: 'YAML',\n xml: 'XML',\n jwt: 'JWT',\n ci: 'CI',\n cd: 'CD',\n}\n\nfunction humanizeLabel(name: string): string {\n if (!name) return ''\n return name\n .split('-')\n .map((word) => {\n if (/^v\\d+$/.test(word)) return word\n return ACRONYM_DICT[word] ?? (word.charAt(0).toUpperCase() + word.slice(1))\n })\n .join(' ')\n}\n\nfunction parseFrontmatterTitle(content: string): string | undefined {\n const match = content.match(/^---\\s*\\n(?:.*\\n)*?title:\\s*['\"]?([^\\n'\"]+)['\"]?\\s*\\n/)\n return match?.[1]?.trim() || undefined\n}\n\nfunction formatDate(val: unknown): string | undefined {\n if (!val) return undefined\n if (val instanceof Date) return val.toISOString().slice(0, 10)\n return String(val)\n}\n\nfunction readArtifacts(dir: string): ChangeArtifact[] {\n const artifacts: ChangeArtifact[] = []\n for (const name of ['proposal', 'design', 'tasks'] as ChangeArtifact[]) {\n if (fs.existsSync(path.join(dir, `${name}.md`))) artifacts.push(name)\n }\n return artifacts\n}\n\n/**\n * Scans an openspec/ directory and returns a structured representation of all\n * canonical specs, active changes, and archived changes.\n *\n * Throws if the directory does not exist.\n */\nexport function readOpenSpecFolder(dir: string): OpenSpecFolder {\n const resolved = path.resolve(dir)\n if (!fs.existsSync(resolved)) {\n throw new Error(`[vitepress-plugin-openspec] openspec directory not found: ${resolved}`)\n }\n\n // --- Canonical specs ---\n const specs: CapabilitySpec[] = []\n const specsDir = path.join(resolved, 'specs')\n if (fs.existsSync(specsDir)) {\n for (const entry of fs.readdirSync(specsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const specPath = path.join(specsDir, entry.name, 'spec.md')\n if (!fs.existsSync(specPath)) continue\n const content = fs.readFileSync(specPath, 'utf-8')\n specs.push({\n name: entry.name,\n title: parseFrontmatterTitle(content),\n specPath,\n content,\n })\n }\n }\n\n // --- Active changes ---\n const changes: Change[] = []\n const changesDir = path.join(resolved, 'changes')\n if (fs.existsSync(changesDir)) {\n for (const entry of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name === 'archive') continue\n const changeDir = path.join(changesDir, entry.name)\n if (!fs.existsSync(path.join(changeDir, '.openspec.yaml'))) continue\n const meta = readOpenSpecYaml(changeDir)\n changes.push({\n name: entry.name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n })\n }\n }\n\n // --- Archived changes ---\n const archivedChanges: Change[] = []\n const archiveDir = path.join(changesDir, 'archive')\n if (fs.existsSync(archiveDir)) {\n for (const entry of fs.readdirSync(archiveDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const changeDir = path.join(archiveDir, entry.name)\n // Parse YYYY-MM-DD-<name> format\n const match = entry.name.match(/^(\\d{4}-\\d{2}-\\d{2})-(.+)$/)\n const archivedDate = match?.[1]\n const name = match?.[2] ?? entry.name\n const meta = readOpenSpecYaml(changeDir)\n archivedChanges.push({\n name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n archivedDate,\n archiveFolderName: entry.name,\n })\n }\n }\n\n return { dir: resolved, specs, changes, archivedChanges }\n}\n\n// ---------------------------------------------------------------------------\n// Spec content transformations\n// ---------------------------------------------------------------------------\n\nfunction extractSpecDescription(content: string): string | undefined {\n const reqMatch = content.match(/^### Requirement:[^\\n]*\\n+([\\s\\S]*?)(?=\\n#{1,4} |\\n*$)/m)\n if (!reqMatch) return undefined\n const para = reqMatch[1].trim()\n if (!para) return undefined\n const sentenceMatch = para.match(/^([^.?!]+[.?!])/)\n if (!sentenceMatch) return undefined\n let sentence = sentenceMatch[1].trim()\n if (sentence.length > 160) {\n const cut = sentence.lastIndexOf(' ', 160)\n sentence = (cut > 0 ? sentence.slice(0, cut) : sentence.slice(0, 160)) + '…'\n }\n return sentence.replace(/\"/g, '\\\\\"')\n}\n\nfunction stripDeltaMarkers(content: string): string {\n const stripped = content\n .split('\\n')\n .filter((line) => !/^## (ADDED|MODIFIED|REMOVED) Requirements\\s*$/.test(line))\n .join('\\n')\n // Collapse consecutive blank lines to a single blank line\n return stripped.replace(/\\n{3,}/g, '\\n\\n')\n}\n\nfunction transformScenarios(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let inScenario = false\n\n for (const line of lines) {\n const scenarioMatch = line.match(/^#### Scenario: (.+)$/)\n const isHeading = /^#{1,6} /.test(line)\n\n if (scenarioMatch) {\n if (inScenario) result.push(':::')\n result.push(`:::details ${scenarioMatch[1]}`)\n inScenario = true\n } else if (isHeading && inScenario) {\n result.push(':::')\n result.push('')\n result.push(line)\n inScenario = false\n } else {\n result.push(line)\n }\n }\n\n if (inScenario) result.push(':::')\n return result.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Page generators\n// ---------------------------------------------------------------------------\n\n/**\n * Generates VitePress Markdown for a canonical capability spec page.\n */\nexport function generateSpecPage(spec: CapabilitySpec): string {\n const description = extractSpecDescription(spec.content)\n const transformed = transformScenarios(stripDeltaMarkers(spec.content))\n const lines: string[] = []\n if (description) {\n lines.push('---')\n lines.push(`description: \"${description}\"`)\n lines.push('---')\n lines.push('')\n }\n lines.push(`# ${spec.title ?? humanizeLabel(spec.name)}`)\n lines.push('')\n lines.push(transformed.trimEnd())\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page listing all canonical specs.\n */\nexport function generateSpecsIndexPage(specs: CapabilitySpec[], outDir: string): string {\n const lines: string[] = []\n lines.push('# Specifications')\n lines.push('')\n lines.push('Canonical capability specifications for this project.')\n lines.push('')\n if (specs.length === 0) {\n lines.push('*No specifications defined yet.*')\n } else {\n for (const spec of specs) {\n lines.push(`- [${spec.title ?? humanizeLabel(spec.name)}](/${outDir}/specs/${spec.name}/)`)\n }\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page for a single change.\n */\nexport function generateChangeIndexPage(change: Change, outDir: string): string {\n const lines: string[] = []\n lines.push(`# ${change.title ?? humanizeLabel(change.name)}`)\n lines.push('')\n if (change.createdDate) {\n lines.push(`**Created:** ${change.createdDate}`)\n lines.push('')\n }\n if (change.archivedDate) {\n lines.push(`**Archived:** ${change.archivedDate}`)\n lines.push('')\n }\n lines.push('## Artifacts')\n lines.push('')\n const prefix = change.archiveFolderName\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n for (const artifact of change.artifacts) {\n const label = artifact.charAt(0).toUpperCase() + artifact.slice(1)\n lines.push(`- [${label}](${prefix}/${artifact})`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the changes overview page listing active and archived changes.\n */\nexport function generateChangesIndexPage(folder: OpenSpecFolder, outDir: string): string {\n const lines: string[] = []\n lines.push('# Changes')\n lines.push('')\n\n if (folder.changes.length === 0) {\n lines.push('*No active changes.*')\n } else {\n lines.push('## Active')\n lines.push('')\n for (const change of folder.changes) {\n const date = change.createdDate ? ` *(${change.createdDate})*` : ''\n lines.push(`- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/${change.name}/)${date}`)\n }\n }\n\n if (folder.archivedChanges.length > 0) {\n lines.push('')\n lines.push('## Archiv')\n lines.push('')\n for (const change of folder.archivedChanges) {\n const date = change.archivedDate ? ` *(archiviert: ${change.archivedDate})*` : ''\n lines.push(\n `- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/archive/${change.archiveFolderName}/)${date}`,\n )\n }\n }\n\n lines.push('')\n return lines.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Artifact link rewriting\n// ---------------------------------------------------------------------------\n\n/**\n * Rewrites relative markdown links in an artifact file's content so that they\n * use absolute VitePress paths instead of paths relative to the original\n * openspec source directory.\n *\n * When artifact files (proposal.md, design.md, tasks.md) are copied from the\n * openspec source directory into the VitePress output directory, any relative\n * links they contain that reference other files within the openspec directory\n * must be rewritten to absolute VitePress paths — otherwise VitePress will\n * report them as dead links.\n *\n * Links that point outside the openspec root, absolute paths, HTTP URLs, and\n * anchor-only links are left unchanged.\n *\n * @param content - The markdown content of the artifact file.\n * @param srcFilePath - The absolute path of the source artifact file.\n * @param openspecRootDir - The absolute path of the openspec root directory.\n * @param outDir - The VitePress output directory name (e.g. `\"openspec\"`).\n * @returns The content with rewritten links.\n */\nexport function rewriteRelativeLinks(\n content: string,\n srcFilePath: string,\n openspecRootDir: string,\n outDir: string,\n): string {\n const srcDir = path.dirname(srcFilePath)\n\n return content.replace(\n /(\\[[^\\]]*\\])\\(([^)]+)\\)/g,\n (_match, linkText: string, urlPart: string) => {\n // Separate the URL from an optional quoted title: url \"title\" or url 'title'\n const titleMatch = urlPart.match(/^(.+?)(\\s+[\"'][^\"']*[\"'])?\\s*$/)\n if (!titleMatch) return _match\n const rawUrl = titleMatch[1].trim()\n const title = titleMatch[2] ?? ''\n\n // Leave non-relative URLs unchanged\n if (\n !rawUrl ||\n rawUrl.startsWith('http://') ||\n rawUrl.startsWith('https://') ||\n rawUrl.startsWith('//') ||\n rawUrl.startsWith('/') ||\n rawUrl.startsWith('#') ||\n rawUrl.startsWith('mailto:') ||\n rawUrl.startsWith('tel:')\n ) {\n return _match\n }\n\n // Separate the path component from any trailing fragment (#anchor)\n const hashIdx = rawUrl.indexOf('#')\n const urlWithoutFragment = hashIdx >= 0 ? rawUrl.slice(0, hashIdx) : rawUrl\n const fragment = hashIdx >= 0 ? rawUrl.slice(hashIdx) : ''\n\n if (!urlWithoutFragment) {\n // Pure anchor link — leave as-is\n return _match\n }\n\n // Resolve the relative path against the source file's directory\n const resolvedPath = path.resolve(srcDir, urlWithoutFragment)\n\n // Only rewrite links that remain within the openspec root directory\n const relToOpenspec = path.relative(openspecRootDir, resolvedPath)\n if (relToOpenspec.startsWith('..') || path.isAbsolute(relToOpenspec)) {\n return _match\n }\n\n // Build the absolute VitePress path, stripping any .md extension\n const vitePath = relToOpenspec.replace(/\\.md$/, '').replace(/\\\\/g, '/')\n const absoluteLink = `/${outDir}/${vitePath}${fragment}`\n\n return `${linkText}(${absoluteLink}${title})`\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Navigation helpers\n// ---------------------------------------------------------------------------\n\nfunction changeItems(change: Change, outDir: string, isArchived = false): SidebarItem[] {\n const prefix = isArchived\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n return change.artifacts.map((a) => ({\n text: a.charAt(0).toUpperCase() + a.slice(1),\n link: `${prefix}/${a}`,\n }))\n}\n\n/**\n * Returns a VitePress sidebar configuration for the OpenSpec documentation.\n * Includes groups for Specifications, active Changes, and archived Changes.\n */\nexport function generateOpenSpecSidebar(\n specDir: string,\n options: { outDir?: string } = {},\n): SidebarItem[] {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping sidebar generation`)\n return []\n }\n const folder = readOpenSpecFolder(specDir)\n const groups: SidebarItem[] = []\n\n // Specifications group\n groups.push({\n text: 'Specifications',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/specs/` },\n ...folder.specs.map((s) => ({ text: s.title ?? humanizeLabel(s.name), link: `/${outDir}/specs/${s.name}/` })),\n ],\n })\n\n // Changes group\n groups.push({\n text: 'Changes',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/changes/` },\n ...folder.changes.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir),\n })),\n ],\n })\n\n // Archive group (only if non-empty)\n if (folder.archivedChanges.length > 0) {\n groups.push({\n text: 'Archiv',\n collapsed: true,\n items: folder.archivedChanges.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir, true),\n })),\n })\n }\n\n return groups\n}\n\n/**\n * Returns a VitePress nav entry for the OpenSpec documentation section.\n */\nexport function openspecNav(\n specDir: string,\n options: { outDir?: string; text?: string } = {},\n): NavItem | null {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping nav generation`)\n return null\n }\n return {\n text: options.text ?? 'Docs',\n link: `/${outDir}/`,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport pc from 'picocolors'\nimport type { Plugin } from 'vite'\nimport type { Change, OpenSpecPluginOptions, WithOpenSpecOptions } from './types.js'\nimport {\n generateChangeIndexPage,\n generateChangesIndexPage,\n generateOpenSpecSidebar,\n generateSpecPage,\n generateSpecsIndexPage,\n openspecNav,\n readOpenSpecFolder,\n rewriteRelativeLinks,\n} from './utils.js'\n\nconst PLUGIN_NAME = 'vitepress-plugin-openspec'\n\nfunction writeFile(filePath: string, content: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, content, 'utf-8')\n}\n\n/**\n * Synchronously generates all VitePress Markdown pages from the openspec/\n * directory and writes them to disk.\n *\n * Call this at the top of your `docs/.vitepress/config.ts` **before**\n * `defineConfig()` so the files exist when VitePress scans the source\n * directory for routes.\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import path from 'node:path'\n * import { fileURLToPath } from 'node:url'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * const __dirname = path.dirname(fileURLToPath(import.meta.url))\n * const specDir = path.resolve(__dirname, '../../openspec')\n *\n * // Generate pages before VitePress scans srcDir for routes\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({ ... })\n * ```\n */\nexport function generateOpenSpecPages(userOptions: OpenSpecPluginOptions = {}): void {\n const specDir = userOptions.specDir ?? './openspec'\n const outDir = userOptions.outDir ?? 'openspec'\n const srcDir = userOptions.srcDir ?? process.cwd()\n const absoluteOutDir = path.resolve(srcDir, outDir)\n\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(\n `${pc.bold(pc.yellow(`[${PLUGIN_NAME}]`))} openspec directory not found: ${path.relative(srcDir, path.resolve(specDir))} — skipping page generation`,\n )\n return\n }\n\n try {\n const folder = readOpenSpecFolder(specDir)\n\n // --- Spec pages ---\n for (const spec of folder.specs) {\n const dest = path.join(absoluteOutDir, 'specs', spec.name, 'index.md')\n writeFile(dest, generateSpecPage(spec))\n }\n writeFile(\n path.join(absoluteOutDir, 'specs', 'index.md'),\n generateSpecsIndexPage(folder.specs, outDir),\n )\n\n // --- Active change pages ---\n for (const change of folder.changes) {\n writeChangePage(change, absoluteOutDir, outDir, false, folder.dir)\n }\n\n // --- Archived change pages ---\n for (const change of folder.archivedChanges) {\n writeChangePage(change, absoluteOutDir, outDir, true, folder.dir)\n }\n\n // --- Changes index ---\n writeFile(\n path.join(absoluteOutDir, 'changes', 'index.md'),\n generateChangesIndexPage(folder, outDir),\n )\n\n // --- Root index ---\n const rootIndex = [\n '# Project Documentation',\n '',\n \"This section is generated from the project's [OpenSpec](https://openspec.dev/) folder.\",\n 'OpenSpec is a lightweight, file-based workflow for spec-driven development —',\n 'it structures your project\\'s capability specifications and change proposals as plain Markdown files.',\n '',\n `- [Specifications](/${outDir}/specs/) — canonical capability specs`,\n `- [Changes](/${outDir}/changes/) — active and archived change proposals`,\n '',\n ].join('\\n')\n writeFile(path.join(absoluteOutDir, 'index.md'), rootIndex)\n\n // Write a self-managed .gitignore so consumers don't need to add the\n // output directory to their project-level .gitignore manually.\n writeFile(\n path.join(absoluteOutDir, '.gitignore'),\n '# Generated by vitepress-plugin-openspec — do not commit generated files.\\n*\\n!.gitignore\\n',\n )\n\n console.log(\n `${pc.bold(pc.cyan(`[${PLUGIN_NAME}]`))} Generated docs from ${pc.cyan(specDir)}: ` +\n `${pc.green(String(folder.specs.length))} spec(s), ` +\n `${pc.green(String(folder.changes.length))} change(s), ` +\n `${pc.green(String(folder.archivedChanges.length))} archived`,\n )\n } catch (err) {\n console.error(\n `${pc.bold(pc.red(`[${PLUGIN_NAME}]`))} Failed to process openspec directory \"${specDir}\": ${String(err)}`,\n )\n }\n}\n\n/**\n * VitePress plugin that reads an openspec/ directory and generates structured\n * Markdown documentation pages inside the VitePress source directory.\n *\n * For the pages to be available on the first build (including CI), also call\n * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.\n *\n * @example\n * ```typescript\n * // .vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({\n * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },\n * })\n * ```\n */\nexport function openspec(userOptions: OpenSpecPluginOptions = {}): Plugin {\n return {\n name: PLUGIN_NAME,\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n const vpConfig = (resolvedConfig as unknown as { vitepress?: { srcDir?: string } }).vitepress\n const srcDir =\n userOptions.srcDir ?? vpConfig?.srcDir ?? resolvedConfig.root ?? process.cwd()\n generateOpenSpecPages({ ...userOptions, srcDir })\n },\n }\n}\n\nfunction writeChangePage(\n change: Change,\n absoluteOutDir: string,\n outDir: string,\n isArchived: boolean,\n openspecRootDir: string,\n): void {\n const subPath = isArchived\n ? path.join('changes', 'archive', `${change.archivedDate}-${change.name}`)\n : path.join('changes', change.name)\n const changeOutDir = path.join(absoluteOutDir, subPath)\n\n // Write index page\n writeFile(path.join(changeOutDir, 'index.md'), generateChangeIndexPage(change, outDir))\n\n // Copy artifact files, rewriting relative links to absolute VitePress paths\n for (const artifact of change.artifacts) {\n const srcFile = path.join(change.dir, `${artifact}.md`)\n const destFile = path.join(changeOutDir, `${artifact}.md`)\n const content = fs.readFileSync(srcFile, 'utf-8')\n writeFile(destFile, rewriteRelativeLinks(content, srcFile, openspecRootDir, outDir))\n }\n}\n\n/**\n * One-call VitePress config helper that wires up the full openspec integration.\n *\n * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans\n * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section\n * into the provided config object.\n *\n * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to\n * the array without replacing it:\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import { withOpenSpec } from 'vitepress-plugin-openspec'\n *\n * export default defineConfig(\n * withOpenSpec({\n * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved\n * themeConfig: { nav: [], sidebar: {} },\n * })\n * )\n * ```\n *\n * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).\n * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.\n */\nexport function withOpenSpec<T extends Record<string, unknown>>(\n config: T,\n options: WithOpenSpecOptions = {},\n): T {\n const specDir = options.specDir ?? './openspec'\n const outDir = options.outDir ?? 'openspec'\n const srcDir = options.srcDir ?? process.cwd()\n\n generateOpenSpecPages({ specDir, outDir, srcDir })\n\n const result = { ...config } as Record<string, unknown>\n\n // --- Vite plugin ---\n const vite = (result.vite ?? {}) as Record<string, unknown>\n const existingPlugins = (vite.plugins as unknown[]) ?? []\n result.vite = { ...vite, plugins: [...existingPlugins, openspec({ specDir, outDir, srcDir })] }\n\n const themeConfig = (result.themeConfig ?? {}) as Record<string, unknown>\n\n // --- Nav ---\n if (options.nav !== false) {\n const navEntry = openspecNav(specDir, { outDir })\n const existingNav = (themeConfig.nav as unknown[]) ?? []\n themeConfig.nav = navEntry ? [navEntry, ...existingNav] : existingNav\n }\n\n // --- Sidebar ---\n if (options.sidebar !== false && !Array.isArray(themeConfig.sidebar)) {\n const sidebarKey = `/${outDir}/`\n const existingSidebar = (themeConfig.sidebar ?? {}) as Record<string, unknown>\n if (!existingSidebar[sidebarKey]) {\n themeConfig.sidebar = {\n ...existingSidebar,\n [sidebarKey]: generateOpenSpecSidebar(specDir, { outDir }),\n }\n }\n }\n\n result.themeConfig = themeConfig\n\n return result as T\n}\n\nexport default openspec\n"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/plugin.ts"],"names":["yamlLoad","fs","path"],"mappings":"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","file":"index.js","sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport { load as yamlLoad } from 'js-yaml'\nimport type {\n CapabilitySpec,\n Change,\n ChangeArtifact,\n NavItem,\n OpenSpecFolder,\n SidebarItem,\n} from './types.js'\n\n// ---------------------------------------------------------------------------\n// Folder reader\n// ---------------------------------------------------------------------------\n\nfunction readOpenSpecYaml(dir: string): Record<string, unknown> {\n const yamlPath = path.join(dir, '.openspec.yaml')\n if (!fs.existsSync(yamlPath)) return {}\n try {\n return (yamlLoad(fs.readFileSync(yamlPath, 'utf-8')) ?? {}) as Record<string, unknown>\n } catch {\n return {}\n }\n}\n\nconst ACRONYM_DICT: Record<string, string> = {\n api: 'API',\n rest: 'REST',\n graphql: 'GraphQL',\n grpc: 'gRPC',\n openapi: 'OpenAPI',\n oauth: 'OAuth',\n oauth2: 'OAuth2',\n http: 'HTTP',\n https: 'HTTPS',\n url: 'URL',\n uri: 'URI',\n sdk: 'SDK',\n ui: 'UI',\n ux: 'UX',\n id: 'ID',\n db: 'DB',\n sql: 'SQL',\n css: 'CSS',\n html: 'HTML',\n json: 'JSON',\n yaml: 'YAML',\n xml: 'XML',\n jwt: 'JWT',\n ci: 'CI',\n cd: 'CD',\n}\n\nfunction humanizeLabel(name: string): string {\n if (!name) return ''\n return name\n .split('-')\n .map((word) => {\n if (/^v\\d+$/.test(word)) return word\n return ACRONYM_DICT[word] ?? (word.charAt(0).toUpperCase() + word.slice(1))\n })\n .join(' ')\n}\n\nfunction parseFrontmatterTitle(content: string): string | undefined {\n const match = content.match(/^---\\s*\\n(?:.*\\n)*?title:\\s*['\"]?([^\\n'\"]+)['\"]?\\s*\\n/)\n return match?.[1]?.trim() || undefined\n}\n\nfunction formatDate(val: unknown): string | undefined {\n if (!val) return undefined\n if (val instanceof Date) return val.toISOString().slice(0, 10)\n return String(val)\n}\n\nfunction readArtifacts(dir: string): ChangeArtifact[] {\n const artifacts: ChangeArtifact[] = []\n for (const name of ['proposal', 'design', 'tasks'] as ChangeArtifact[]) {\n if (fs.existsSync(path.join(dir, `${name}.md`))) artifacts.push(name)\n }\n return artifacts\n}\n\n/**\n * Scans an openspec/ directory and returns a structured representation of all\n * canonical specs, active changes, and archived changes.\n *\n * Throws if the directory does not exist.\n */\nexport function readOpenSpecFolder(dir: string): OpenSpecFolder {\n const resolved = path.resolve(dir)\n if (!fs.existsSync(resolved)) {\n throw new Error(`[vitepress-plugin-openspec] openspec directory not found: ${resolved}`)\n }\n\n // --- Canonical specs ---\n const specs: CapabilitySpec[] = []\n const specsDir = path.join(resolved, 'specs')\n if (fs.existsSync(specsDir)) {\n for (const entry of fs.readdirSync(specsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const specPath = path.join(specsDir, entry.name, 'spec.md')\n if (!fs.existsSync(specPath)) continue\n const content = fs.readFileSync(specPath, 'utf-8')\n specs.push({\n name: entry.name,\n title: parseFrontmatterTitle(content),\n specPath,\n content,\n })\n }\n }\n\n // --- Active changes ---\n const changes: Change[] = []\n const changesDir = path.join(resolved, 'changes')\n if (fs.existsSync(changesDir)) {\n for (const entry of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name === 'archive') continue\n const changeDir = path.join(changesDir, entry.name)\n if (!fs.existsSync(path.join(changeDir, '.openspec.yaml'))) continue\n const meta = readOpenSpecYaml(changeDir)\n changes.push({\n name: entry.name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n })\n }\n }\n\n // --- Archived changes ---\n const archivedChanges: Change[] = []\n const archiveDir = path.join(changesDir, 'archive')\n if (fs.existsSync(archiveDir)) {\n for (const entry of fs.readdirSync(archiveDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const changeDir = path.join(archiveDir, entry.name)\n // Parse YYYY-MM-DD-<name> format\n const match = entry.name.match(/^(\\d{4}-\\d{2}-\\d{2})-(.+)$/)\n const archivedDate = match?.[1]\n const name = match?.[2] ?? entry.name\n const meta = readOpenSpecYaml(changeDir)\n archivedChanges.push({\n name,\n title: meta.title ? String(meta.title) : undefined,\n dir: changeDir,\n artifacts: readArtifacts(changeDir),\n createdDate: formatDate(meta.created),\n archivedDate,\n archiveFolderName: entry.name,\n })\n }\n }\n\n return { dir: resolved, specs, changes, archivedChanges }\n}\n\n// ---------------------------------------------------------------------------\n// Spec content transformations\n// ---------------------------------------------------------------------------\n\nfunction extractSpecDescription(content: string): string | undefined {\n const reqMatch = content.match(/^### Requirement:[^\\n]*\\n+([\\s\\S]*?)(?=\\n#{1,4} |\\n*$)/m)\n if (!reqMatch) return undefined\n const para = reqMatch[1].trim()\n if (!para) return undefined\n const sentenceMatch = para.match(/^([^.?!]+[.?!])/)\n if (!sentenceMatch) return undefined\n let sentence = sentenceMatch[1].trim()\n if (sentence.length > 160) {\n const cut = sentence.lastIndexOf(' ', 160)\n sentence = (cut > 0 ? sentence.slice(0, cut) : sentence.slice(0, 160)) + '…'\n }\n return sentence.replace(/\"/g, '\\\\\"')\n}\n\nfunction stripDeltaMarkers(content: string): string {\n const stripped = content\n .split('\\n')\n .filter((line) => !/^## (ADDED|MODIFIED|REMOVED) Requirements\\s*$/.test(line))\n .join('\\n')\n // Collapse consecutive blank lines to a single blank line\n return stripped.replace(/\\n{3,}/g, '\\n\\n')\n}\n\nfunction transformScenarios(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let inScenario = false\n\n for (const line of lines) {\n const scenarioMatch = line.match(/^#### Scenario: (.+)$/)\n const isHeading = /^#{1,6} /.test(line)\n\n if (scenarioMatch) {\n if (inScenario) result.push(':::')\n result.push(`:::details ${scenarioMatch[1]}`)\n inScenario = true\n } else if (isHeading && inScenario) {\n result.push(':::')\n result.push('')\n result.push(line)\n inScenario = false\n } else {\n result.push(line)\n }\n }\n\n if (inScenario) result.push(':::')\n return result.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Page generators\n// ---------------------------------------------------------------------------\n\n/**\n * Generates VitePress Markdown for a canonical capability spec page.\n */\nexport function generateSpecPage(spec: CapabilitySpec): string {\n const description = extractSpecDescription(spec.content)\n const transformed = transformScenarios(stripDeltaMarkers(spec.content))\n const lines: string[] = []\n if (description) {\n lines.push('---')\n lines.push(`description: \"${description}\"`)\n lines.push('---')\n lines.push('')\n }\n lines.push(`# ${spec.title ?? humanizeLabel(spec.name)}`)\n lines.push('')\n lines.push(transformed.trimEnd())\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page listing all canonical specs.\n */\nexport function generateSpecsIndexPage(specs: CapabilitySpec[], outDir: string): string {\n const lines: string[] = []\n lines.push('# Specifications')\n lines.push('')\n lines.push('Canonical capability specifications for this project.')\n lines.push('')\n if (specs.length === 0) {\n lines.push('*No specifications defined yet.*')\n } else {\n for (const spec of specs) {\n lines.push(`- [${spec.title ?? humanizeLabel(spec.name)}](/${outDir}/specs/${spec.name}/)`)\n }\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the index page for a single change.\n */\nexport function generateChangeIndexPage(change: Change, outDir: string): string {\n const lines: string[] = []\n lines.push(`# ${change.title ?? humanizeLabel(change.name)}`)\n lines.push('')\n if (change.createdDate) {\n lines.push(`**Created:** ${change.createdDate}`)\n lines.push('')\n }\n if (change.archivedDate) {\n lines.push(`**Archived:** ${change.archivedDate}`)\n lines.push('')\n }\n lines.push('## Artifacts')\n lines.push('')\n const prefix = change.archiveFolderName\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n for (const artifact of change.artifacts) {\n const label = artifact.charAt(0).toUpperCase() + artifact.slice(1)\n lines.push(`- [${label}](${prefix}/${artifact})`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Generates the changes overview page listing active and archived changes.\n */\nexport function generateChangesIndexPage(folder: OpenSpecFolder, outDir: string): string {\n const lines: string[] = []\n lines.push('# Changes')\n lines.push('')\n\n if (folder.changes.length === 0) {\n lines.push('*No active changes.*')\n } else {\n lines.push('## Active')\n lines.push('')\n for (const change of folder.changes) {\n const date = change.createdDate ? ` *(${change.createdDate})*` : ''\n lines.push(`- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/${change.name}/)${date}`)\n }\n }\n\n if (folder.archivedChanges.length > 0) {\n lines.push('')\n lines.push('## Archiv')\n lines.push('')\n for (const change of folder.archivedChanges) {\n const date = change.archivedDate ? ` *(archiviert: ${change.archivedDate})*` : ''\n lines.push(\n `- [${change.title ?? humanizeLabel(change.name)}](/${outDir}/changes/archive/${change.archiveFolderName}/)${date}`,\n )\n }\n }\n\n lines.push('')\n return lines.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Artifact link rewriting\n// ---------------------------------------------------------------------------\n\n/**\n * Rewrites relative markdown links in an artifact file's content so that they\n * use absolute VitePress paths instead of paths relative to the original\n * openspec source directory.\n *\n * When artifact files (proposal.md, design.md, tasks.md) are copied from the\n * openspec source directory into the VitePress output directory, any relative\n * links they contain that reference other files within the openspec directory\n * must be rewritten to absolute VitePress paths — otherwise VitePress will\n * report them as dead links.\n *\n * Links that point outside the openspec root, absolute paths, HTTP URLs, and\n * anchor-only links are left unchanged.\n *\n * @param content - The markdown content of the artifact file.\n * @param srcFilePath - The absolute path of the source artifact file.\n * @param openspecRootDir - The absolute path of the openspec root directory.\n * @param outDir - The VitePress output directory name (e.g. `\"openspec\"`).\n * @returns The content with rewritten links.\n */\nexport function rewriteRelativeLinks(\n content: string,\n srcFilePath: string,\n openspecRootDir: string,\n outDir: string,\n): string {\n const srcDir = path.dirname(srcFilePath)\n\n return content.replace(\n /(\\[[^\\]]*\\])\\(([^)]+)\\)/g,\n (_match, linkText: string, urlPart: string) => {\n // Separate the URL from an optional quoted title: url \"title\" or url 'title'\n const titleMatch = urlPart.match(/^(.+?)(\\s+[\"'][^\"']*[\"'])?\\s*$/)\n if (!titleMatch) return _match\n const rawUrl = titleMatch[1].trim()\n const title = titleMatch[2] ?? ''\n\n // Leave non-relative URLs unchanged\n if (\n !rawUrl ||\n rawUrl.startsWith('http://') ||\n rawUrl.startsWith('https://') ||\n rawUrl.startsWith('//') ||\n rawUrl.startsWith('/') ||\n rawUrl.startsWith('#') ||\n rawUrl.startsWith('mailto:') ||\n rawUrl.startsWith('tel:')\n ) {\n return _match\n }\n\n // Separate the path component from any trailing fragment (#anchor)\n const hashIdx = rawUrl.indexOf('#')\n const urlWithoutFragment = hashIdx >= 0 ? rawUrl.slice(0, hashIdx) : rawUrl\n const fragment = hashIdx >= 0 ? rawUrl.slice(hashIdx) : ''\n\n if (!urlWithoutFragment) {\n // Pure anchor link — leave as-is\n return _match\n }\n\n // Resolve the relative path against the source file's directory\n const resolvedPath = path.resolve(srcDir, urlWithoutFragment)\n\n // Only rewrite links that remain within the openspec root directory\n const relToOpenspec = path.relative(openspecRootDir, resolvedPath)\n if (relToOpenspec.startsWith('..') || path.isAbsolute(relToOpenspec)) {\n return _match\n }\n\n // Build the absolute VitePress path, stripping any .md extension\n const vitePath = relToOpenspec.replace(/\\.md$/, '').replace(/\\\\/g, '/')\n const absoluteLink = `/${outDir}/${vitePath}${fragment}`\n\n return `${linkText}(${absoluteLink}${title})`\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Navigation helpers\n// ---------------------------------------------------------------------------\n\nfunction changeItems(change: Change, outDir: string, isArchived = false): SidebarItem[] {\n const prefix = isArchived\n ? `/${outDir}/changes/archive/${change.archiveFolderName}`\n : `/${outDir}/changes/${change.name}`\n return change.artifacts.map((a) => ({\n text: a.charAt(0).toUpperCase() + a.slice(1),\n link: `${prefix}/${a}`,\n }))\n}\n\n/**\n * Returns a VitePress sidebar configuration for the OpenSpec documentation.\n * Includes groups for Specifications, active Changes, and archived Changes.\n */\nexport function generateOpenSpecSidebar(\n specDir: string,\n options: { outDir?: string } = {},\n): SidebarItem[] {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping sidebar generation`)\n return []\n }\n const folder = readOpenSpecFolder(specDir)\n const groups: SidebarItem[] = []\n\n // Specifications group\n groups.push({\n text: 'Specifications',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/specs/` },\n ...folder.specs.map((s) => ({ text: s.title ?? humanizeLabel(s.name), link: `/${outDir}/specs/${s.name}/` })),\n ],\n })\n\n // Changes group\n groups.push({\n text: 'Changes',\n collapsed: false,\n items: [\n { text: 'Overview', link: `/${outDir}/changes/` },\n ...folder.changes.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir),\n })),\n ],\n })\n\n // Archive group (only if non-empty)\n if (folder.archivedChanges.length > 0) {\n groups.push({\n text: 'Archiv',\n collapsed: true,\n items: folder.archivedChanges.map((c) => ({\n text: c.title ?? humanizeLabel(c.name),\n collapsed: true,\n items: changeItems(c, outDir, true),\n })),\n })\n }\n\n return groups\n}\n\n/**\n * Returns a VitePress nav entry for the OpenSpec documentation section.\n */\nexport function openspecNav(\n specDir: string,\n options: { outDir?: string; text?: string } = {},\n): NavItem | null {\n const outDir = options.outDir ?? 'openspec'\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(`[vitepress-plugin-openspec] openspec directory not found: ${path.relative(process.cwd(), path.resolve(specDir))} — skipping nav generation`)\n return null\n }\n return {\n text: options.text ?? 'Docs',\n link: `/${outDir}/`,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport pc from 'picocolors'\nimport type { Plugin } from 'vite'\nimport type { Change, OpenSpecPluginOptions, WithOpenSpecOptions } from './types.js'\nimport {\n generateChangeIndexPage,\n generateChangesIndexPage,\n generateOpenSpecSidebar,\n generateSpecPage,\n generateSpecsIndexPage,\n openspecNav,\n readOpenSpecFolder,\n rewriteRelativeLinks,\n} from './utils.js'\n\nconst PLUGIN_NAME = 'vitepress-plugin-openspec'\n\nfunction writeFile(filePath: string, content: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, content, 'utf-8')\n}\n\n/**\n * Synchronously generates all VitePress Markdown pages from the openspec/\n * directory and writes them to disk.\n *\n * Call this at the top of your `docs/.vitepress/config.ts` **before**\n * `defineConfig()` so the files exist when VitePress scans the source\n * directory for routes.\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import path from 'node:path'\n * import { fileURLToPath } from 'node:url'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * const __dirname = path.dirname(fileURLToPath(import.meta.url))\n * const specDir = path.resolve(__dirname, '../../openspec')\n *\n * // Generate pages before VitePress scans srcDir for routes\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({ ... })\n * ```\n */\nexport function generateOpenSpecPages(userOptions: OpenSpecPluginOptions = {}): void {\n const specDir = userOptions.specDir ?? './openspec'\n const outDir = userOptions.outDir ?? 'openspec'\n const srcDir = userOptions.srcDir ?? process.cwd()\n const absoluteOutDir = path.resolve(srcDir, outDir)\n\n if (!fs.existsSync(path.resolve(specDir))) {\n console.warn(\n `${pc.bold(pc.yellow(`[${PLUGIN_NAME}]`))} openspec directory not found: ${path.relative(srcDir, path.resolve(specDir))} — skipping page generation`,\n )\n return\n }\n\n try {\n const folder = readOpenSpecFolder(specDir)\n\n // --- Spec pages ---\n for (const spec of folder.specs) {\n const dest = path.join(absoluteOutDir, 'specs', spec.name, 'index.md')\n writeFile(dest, generateSpecPage(spec))\n }\n writeFile(\n path.join(absoluteOutDir, 'specs', 'index.md'),\n generateSpecsIndexPage(folder.specs, outDir),\n )\n\n // --- Active change pages ---\n for (const change of folder.changes) {\n writeChangePage(change, absoluteOutDir, outDir, false, folder.dir)\n }\n\n // --- Archived change pages ---\n for (const change of folder.archivedChanges) {\n writeChangePage(change, absoluteOutDir, outDir, true, folder.dir)\n }\n\n // --- Changes index ---\n writeFile(\n path.join(absoluteOutDir, 'changes', 'index.md'),\n generateChangesIndexPage(folder, outDir),\n )\n\n // --- Root index ---\n const rootIndex = [\n '# Project Documentation',\n '',\n \"This section is generated from the project's [OpenSpec](https://openspec.dev/) folder.\",\n 'OpenSpec is a lightweight, file-based workflow for spec-driven development —',\n 'it structures your project\\'s capability specifications and change proposals as plain Markdown files.',\n '',\n `- [Specifications](/${outDir}/specs/) — canonical capability specs`,\n `- [Changes](/${outDir}/changes/) — active and archived change proposals`,\n '',\n ].join('\\n')\n writeFile(path.join(absoluteOutDir, 'index.md'), rootIndex)\n\n // Write a self-managed .gitignore so consumers don't need to add the\n // output directory to their project-level .gitignore manually.\n writeFile(\n path.join(absoluteOutDir, '.gitignore'),\n '# Generated by vitepress-plugin-openspec — do not commit generated files.\\n*\\n!.gitignore\\n',\n )\n\n console.log(\n `${pc.bold(pc.cyan(`[${PLUGIN_NAME}]`))} Generated docs from ${pc.cyan(specDir)}: ` +\n `${pc.green(String(folder.specs.length))} spec(s), ` +\n `${pc.green(String(folder.changes.length))} change(s), ` +\n `${pc.green(String(folder.archivedChanges.length))} archived`,\n )\n } catch (err) {\n console.error(\n `${pc.bold(pc.red(`[${PLUGIN_NAME}]`))} Failed to process openspec directory \"${specDir}\": ${String(err)}`,\n )\n }\n}\n\n/**\n * VitePress plugin that reads an openspec/ directory and generates structured\n * Markdown documentation pages inside the VitePress source directory.\n *\n * For the pages to be available on the first build (including CI), also call\n * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.\n *\n * @example\n * ```typescript\n * // .vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'\n *\n * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })\n *\n * export default defineConfig({\n * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },\n * })\n * ```\n */\nexport function openspec(userOptions: OpenSpecPluginOptions = {}): Plugin {\n return {\n name: PLUGIN_NAME,\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n const vpConfig = (resolvedConfig as unknown as { vitepress?: { srcDir?: string } }).vitepress\n const srcDir =\n userOptions.srcDir ?? vpConfig?.srcDir ?? resolvedConfig.root ?? process.cwd()\n generateOpenSpecPages({ ...userOptions, srcDir })\n },\n }\n}\n\nfunction writeChangePage(\n change: Change,\n absoluteOutDir: string,\n outDir: string,\n isArchived: boolean,\n openspecRootDir: string,\n): void {\n const subPath = isArchived\n ? path.join('changes', 'archive', `${change.archivedDate}-${change.name}`)\n : path.join('changes', change.name)\n const changeOutDir = path.join(absoluteOutDir, subPath)\n\n // Write index page\n writeFile(path.join(changeOutDir, 'index.md'), generateChangeIndexPage(change, outDir))\n\n // Copy artifact files, rewriting relative links to absolute VitePress paths\n for (const artifact of change.artifacts) {\n const srcFile = path.join(change.dir, `${artifact}.md`)\n const destFile = path.join(changeOutDir, `${artifact}.md`)\n const content = fs.readFileSync(srcFile, 'utf-8')\n writeFile(destFile, rewriteRelativeLinks(content, srcFile, openspecRootDir, outDir))\n }\n}\n\n/**\n * One-call VitePress config helper that wires up the full openspec integration.\n *\n * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans\n * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section\n * into the provided config object.\n *\n * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to\n * the array without replacing it:\n *\n * @example\n * ```typescript\n * // docs/.vitepress/config.ts\n * import { defineConfig } from 'vitepress'\n * import { withOpenSpec } from 'vitepress-plugin-openspec'\n *\n * export default defineConfig(\n * withOpenSpec({\n * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved\n * themeConfig: { nav: [], sidebar: {} },\n * })\n * )\n * ```\n *\n * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).\n * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.\n */\nexport function withOpenSpec<T extends Record<string, unknown>>(\n config: T,\n options: WithOpenSpecOptions = {},\n): T {\n const specDir = options.specDir ?? './openspec'\n const outDir = options.outDir ?? 'openspec'\n const srcDir = options.srcDir ?? process.cwd()\n\n generateOpenSpecPages({ specDir, outDir, srcDir })\n\n const result = { ...config } as Record<string, unknown>\n\n // --- Vite plugin ---\n const vite = (result.vite ?? {}) as Record<string, unknown>\n const existingPlugins = (vite.plugins as unknown[]) ?? []\n result.vite = { ...vite, plugins: [...existingPlugins, openspec({ specDir, outDir, srcDir })] }\n\n const themeConfig = (result.themeConfig ?? {}) as Record<string, unknown>\n\n // --- Nav ---\n if (options.nav !== false) {\n const navEntry = openspecNav(specDir, { outDir })\n const existingNav = (themeConfig.nav as unknown[]) ?? []\n themeConfig.nav = navEntry ? [navEntry, ...existingNav] : existingNav\n }\n\n // --- Sidebar ---\n if (options.sidebar !== false && !Array.isArray(themeConfig.sidebar)) {\n const sidebarKey = `/${outDir}/`\n const existingSidebar = (themeConfig.sidebar ?? {}) as Record<string, unknown>\n if (!existingSidebar[sidebarKey]) {\n themeConfig.sidebar = {\n ...existingSidebar,\n [sidebarKey]: generateOpenSpecSidebar(specDir, { outDir }),\n }\n }\n }\n\n result.themeConfig = themeConfig\n\n return result as T\n}\n\nexport default openspec\n"]}
@@ -0,0 +1,79 @@
1
+ import type { Plugin } from 'vite';
2
+ import type { OpenSpecPluginOptions, WithOpenSpecOptions } from './types.js';
3
+ /**
4
+ * Synchronously generates all VitePress Markdown pages from the openspec/
5
+ * directory and writes them to disk.
6
+ *
7
+ * Call this at the top of your `docs/.vitepress/config.ts` **before**
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
+ * ```
27
+ */
28
+ export declare function generateOpenSpecPages(userOptions?: OpenSpecPluginOptions): void;
29
+ /**
30
+ * VitePress plugin that reads an openspec/ directory and generates structured
31
+ * Markdown documentation pages inside the VitePress source directory.
32
+ *
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
+ * ```
48
+ */
49
+ export declare function openspec(userOptions?: OpenSpecPluginOptions): Plugin;
50
+ /**
51
+ * One-call VitePress config helper that wires up the full openspec integration.
52
+ *
53
+ * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans
54
+ * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section
55
+ * into the provided config object.
56
+ *
57
+ * 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'
65
+ *
66
+ * export default defineConfig(
67
+ * withOpenSpec({
68
+ * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved
69
+ * themeConfig: { nav: [], sidebar: {} },
70
+ * })
71
+ * )
72
+ * ```
73
+ *
74
+ * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).
75
+ * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.
76
+ */
77
+ export declare function withOpenSpec<T extends Record<string, unknown>>(config: T, options?: WithOpenSpecOptions): T;
78
+ export default openspec;
79
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Options for the `withOpenSpec()` config helper.
3
+ * Extends `OpenSpecPluginOptions` with optional nav/sidebar merge controls.
4
+ */
5
+ export interface WithOpenSpecOptions extends OpenSpecPluginOptions {
6
+ /**
7
+ * Whether to prepend an openspec nav entry to `themeConfig.nav`.
8
+ * @default true
9
+ */
10
+ nav?: boolean;
11
+ /**
12
+ * Whether to inject the openspec sidebar section into `themeConfig.sidebar`.
13
+ * @default true
14
+ */
15
+ sidebar?: boolean;
16
+ }
17
+ /**
18
+ * Configuration options for the vitepress-plugin-openspec plugin.
19
+ */
20
+ export interface OpenSpecPluginOptions {
21
+ /**
22
+ * Path to the openspec/ directory of the project.
23
+ *
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/`).
26
+ *
27
+ * If the directory does not exist a warning is printed and the build continues
28
+ * without generating any pages or nav/sidebar entries — no error is thrown.
29
+ *
30
+ * @default './openspec'
31
+ * @example
32
+ * // Resolving from docs/.vitepress/config.ts
33
+ * import path from 'node:path'
34
+ * import { fileURLToPath } from 'node:url'
35
+ * const __dirname = path.dirname(fileURLToPath(import.meta.url))
36
+ * const specDir = path.resolve(__dirname, '../../openspec')
37
+ */
38
+ specDir?: string;
39
+ /**
40
+ * Output directory (relative to VitePress `srcDir`) where the generated
41
+ * Markdown pages will be written.
42
+ * @default 'openspec'
43
+ */
44
+ outDir?: string;
45
+ /**
46
+ * 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.
49
+ *
50
+ * @default process.cwd()
51
+ * @example path.resolve(__dirname, '..') // from docs/.vitepress/config.ts
52
+ */
53
+ srcDir?: string;
54
+ }
55
+ /**
56
+ * A canonical capability specification from openspec/specs/<name>/spec.md
57
+ */
58
+ export interface CapabilitySpec {
59
+ /** Folder name (kebab-case capability identifier) */
60
+ name: string;
61
+ /** Optional display title from spec.md frontmatter. Overrides humanized name. */
62
+ title?: string;
63
+ /** Absolute path to the spec.md file */
64
+ specPath: string;
65
+ /** Raw Markdown content of the spec */
66
+ content: string;
67
+ }
68
+ /**
69
+ * A single artifact (file) belonging to a Change.
70
+ */
71
+ export type ChangeArtifact = 'proposal' | 'design' | 'tasks';
72
+ /**
73
+ * An OpenSpec change (active or archived).
74
+ */
75
+ export interface Change {
76
+ /** Change directory name (e.g. "my-feature" or for archived: "my-feature" extracted from "2026-03-10-my-feature") */
77
+ name: string;
78
+ /** Optional display title from .openspec.yaml. Overrides humanized name. */
79
+ title?: string;
80
+ /** Absolute path to the change directory */
81
+ dir: string;
82
+ /** Which artifact files are present */
83
+ artifacts: ChangeArtifact[];
84
+ /** Creation date from .openspec.yaml, if available */
85
+ createdDate?: string;
86
+ /** For archived changes: the archive date (YYYY-MM-DD) parsed from directory name */
87
+ archivedDate?: string;
88
+ /**
89
+ * For archived changes: the original archive folder name (e.g. "2026-01-15-my-feature" or
90
+ * "legacy-feature" for non-standard names). Used to build correct archive URLs.
91
+ */
92
+ archiveFolderName?: string;
93
+ }
94
+ /**
95
+ * The full parsed structure of an openspec/ directory.
96
+ */
97
+ export interface OpenSpecFolder {
98
+ /** Absolute path to the openspec/ root */
99
+ dir: string;
100
+ /** Canonical capability specs from openspec/specs/ */
101
+ specs: CapabilitySpec[];
102
+ /** Active changes from openspec/changes/ (excluding archive/) */
103
+ changes: Change[];
104
+ /** Archived changes from openspec/changes/archive/ */
105
+ archivedChanges: Change[];
106
+ }
107
+ /**
108
+ * A nav item compatible with VitePress `DefaultTheme.NavItem`.
109
+ */
110
+ export interface NavItem {
111
+ text: string;
112
+ link: string;
113
+ }
114
+ /**
115
+ * A sidebar item compatible with VitePress `DefaultTheme.SidebarItem`.
116
+ */
117
+ export interface SidebarItem {
118
+ text: string;
119
+ link?: string;
120
+ collapsed?: boolean;
121
+ items?: SidebarItem[];
122
+ }
123
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,60 @@
1
+ import type { CapabilitySpec, Change, NavItem, OpenSpecFolder, SidebarItem } from './types.js';
2
+ /**
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.
7
+ */
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;
60
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stritti/vitepress-plugin-openspec",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "A VitePress plugin that integrates OpenSpec documentation into your VitePress site",
5
5
  "keywords": [
6
6
  "openspec",
@@ -32,7 +32,7 @@
32
32
  }
33
33
  },
34
34
  "scripts": {
35
- "build": "tsup",
35
+ "build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist",
36
36
  "dev": "tsup --watch",
37
37
  "lint": "tsc --noEmit",
38
38
  "prepublishOnly": "npm run build",
@@ -42,7 +42,7 @@
42
42
  "docs:build": "cd docs && bun run build"
43
43
  },
44
44
  "dependencies": {
45
- "js-yaml": "^4.1.1",
45
+ "js-yaml": "^5.4.2",
46
46
  "picocolors": "^1.1.1"
47
47
  },
48
48
  "devDependencies": {
@@ -54,8 +54,8 @@
54
54
  "@types/node": "^25.4.0",
55
55
  "semantic-release": "^25.0.3",
56
56
  "tsup": "^8.5.1",
57
- "typescript": "^5.9.3",
58
- "vite": "^7.3.1",
57
+ "typescript": "^7.0.2",
58
+ "vite": "^8.0.5",
59
59
  "vitepress": "^1.6.4",
60
60
  "vitest": "^4.0.18"
61
61
  },
package/dist/index.d.cts DELETED
@@ -1,217 +0,0 @@
1
- import { Plugin } from 'vite';
2
-
3
- /**
4
- * Options for the `withOpenSpec()` config helper.
5
- * Extends `OpenSpecPluginOptions` with optional nav/sidebar merge controls.
6
- */
7
- interface WithOpenSpecOptions extends OpenSpecPluginOptions {
8
- /**
9
- * Whether to prepend an openspec nav entry to `themeConfig.nav`.
10
- * @default true
11
- */
12
- nav?: boolean;
13
- /**
14
- * Whether to inject the openspec sidebar section into `themeConfig.sidebar`.
15
- * @default true
16
- */
17
- sidebar?: boolean;
18
- }
19
- /**
20
- * Configuration options for the vitepress-plugin-openspec plugin.
21
- */
22
- interface OpenSpecPluginOptions {
23
- /**
24
- * Path to the openspec/ directory of the project.
25
- *
26
- * Use an explicit path when your `openspec/` folder is not at the project root
27
- * (e.g. when `config.ts` lives inside `docs/.vitepress/`).
28
- *
29
- * If the directory does not exist a warning is printed and the build continues
30
- * without generating any pages or nav/sidebar entries — no error is thrown.
31
- *
32
- * @default './openspec'
33
- * @example
34
- * // Resolving from docs/.vitepress/config.ts
35
- * import path from 'node:path'
36
- * import { fileURLToPath } from 'node:url'
37
- * const __dirname = path.dirname(fileURLToPath(import.meta.url))
38
- * const specDir = path.resolve(__dirname, '../../openspec')
39
- */
40
- specDir?: string;
41
- /**
42
- * Output directory (relative to VitePress `srcDir`) where the generated
43
- * Markdown pages will be written.
44
- * @default 'openspec'
45
- */
46
- outDir?: string;
47
- /**
48
- * VitePress source directory — the directory containing your `.md` files
49
- * (i.e. the `docs/` folder). Required when calling `generateOpenSpecPages()`
50
- * at config evaluation time so it knows where to write the generated files.
51
- *
52
- * @default process.cwd()
53
- * @example path.resolve(__dirname, '..') // from docs/.vitepress/config.ts
54
- */
55
- srcDir?: string;
56
- }
57
- /**
58
- * A canonical capability specification from openspec/specs/<name>/spec.md
59
- */
60
- interface CapabilitySpec {
61
- /** Folder name (kebab-case capability identifier) */
62
- name: string;
63
- /** Optional display title from spec.md frontmatter. Overrides humanized name. */
64
- title?: string;
65
- /** Absolute path to the spec.md file */
66
- specPath: string;
67
- /** Raw Markdown content of the spec */
68
- content: string;
69
- }
70
- /**
71
- * A single artifact (file) belonging to a Change.
72
- */
73
- type ChangeArtifact = 'proposal' | 'design' | 'tasks';
74
- /**
75
- * An OpenSpec change (active or archived).
76
- */
77
- interface Change {
78
- /** Change directory name (e.g. "my-feature" or for archived: "my-feature" extracted from "2026-03-10-my-feature") */
79
- name: string;
80
- /** Optional display title from .openspec.yaml. Overrides humanized name. */
81
- title?: string;
82
- /** Absolute path to the change directory */
83
- dir: string;
84
- /** Which artifact files are present */
85
- artifacts: ChangeArtifact[];
86
- /** Creation date from .openspec.yaml, if available */
87
- createdDate?: string;
88
- /** For archived changes: the archive date (YYYY-MM-DD) parsed from directory name */
89
- archivedDate?: string;
90
- /**
91
- * For archived changes: the original archive folder name (e.g. "2026-01-15-my-feature" or
92
- * "legacy-feature" for non-standard names). Used to build correct archive URLs.
93
- */
94
- archiveFolderName?: string;
95
- }
96
- /**
97
- * The full parsed structure of an openspec/ directory.
98
- */
99
- interface OpenSpecFolder {
100
- /** Absolute path to the openspec/ root */
101
- dir: string;
102
- /** Canonical capability specs from openspec/specs/ */
103
- specs: CapabilitySpec[];
104
- /** Active changes from openspec/changes/ (excluding archive/) */
105
- changes: Change[];
106
- /** Archived changes from openspec/changes/archive/ */
107
- archivedChanges: Change[];
108
- }
109
- /**
110
- * A nav item compatible with VitePress `DefaultTheme.NavItem`.
111
- */
112
- interface NavItem {
113
- text: string;
114
- link: string;
115
- }
116
- /**
117
- * A sidebar item compatible with VitePress `DefaultTheme.SidebarItem`.
118
- */
119
- interface SidebarItem {
120
- text: string;
121
- link?: string;
122
- collapsed?: boolean;
123
- items?: SidebarItem[];
124
- }
125
-
126
- /**
127
- * Synchronously generates all VitePress Markdown pages from the openspec/
128
- * directory and writes them to disk.
129
- *
130
- * Call this at the top of your `docs/.vitepress/config.ts` **before**
131
- * `defineConfig()` so the files exist when VitePress scans the source
132
- * directory for routes.
133
- *
134
- * @example
135
- * ```typescript
136
- * // docs/.vitepress/config.ts
137
- * import { defineConfig } from 'vitepress'
138
- * import path from 'node:path'
139
- * import { fileURLToPath } from 'node:url'
140
- * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'
141
- *
142
- * const __dirname = path.dirname(fileURLToPath(import.meta.url))
143
- * const specDir = path.resolve(__dirname, '../../openspec')
144
- *
145
- * // Generate pages before VitePress scans srcDir for routes
146
- * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })
147
- *
148
- * export default defineConfig({ ... })
149
- * ```
150
- */
151
- declare function generateOpenSpecPages(userOptions?: OpenSpecPluginOptions): void;
152
- /**
153
- * VitePress plugin that reads an openspec/ directory and generates structured
154
- * Markdown documentation pages inside the VitePress source directory.
155
- *
156
- * For the pages to be available on the first build (including CI), also call
157
- * `generateOpenSpecPages()` at the top of your `config.ts` before `defineConfig`.
158
- *
159
- * @example
160
- * ```typescript
161
- * // .vitepress/config.ts
162
- * import { defineConfig } from 'vitepress'
163
- * import openspec, { generateOpenSpecPages } from 'vitepress-plugin-openspec'
164
- *
165
- * generateOpenSpecPages({ specDir, outDir: 'openspec', srcDir: path.resolve(__dirname, '..') })
166
- *
167
- * export default defineConfig({
168
- * vite: { plugins: [openspec({ specDir: './openspec', outDir: 'project-docs' })] },
169
- * })
170
- * ```
171
- */
172
- declare function openspec(userOptions?: OpenSpecPluginOptions): Plugin;
173
- /**
174
- * One-call VitePress config helper that wires up the full openspec integration.
175
- *
176
- * Calls `generateOpenSpecPages()` synchronously (required before VitePress scans
177
- * for routes), then merges the openspec Vite plugin, nav entry, and sidebar section
178
- * into the provided config object.
179
- *
180
- * Other Vite plugins go into `vite.plugins` as usual — `withOpenSpec` appends to
181
- * the array without replacing it:
182
- *
183
- * @example
184
- * ```typescript
185
- * // docs/.vitepress/config.ts
186
- * import { defineConfig } from 'vitepress'
187
- * import { withOpenSpec } from 'vitepress-plugin-openspec'
188
- *
189
- * export default defineConfig(
190
- * withOpenSpec({
191
- * vite: { plugins: [myOtherPlugin()] }, // other plugins are preserved
192
- * themeConfig: { nav: [], sidebar: {} },
193
- * })
194
- * )
195
- * ```
196
- *
197
- * @param config - Your VitePress `UserConfig` object (same as what `defineConfig` accepts).
198
- * @param options - OpenSpec options. All fields are optional; defaults match `generateOpenSpecPages`.
199
- */
200
- declare function withOpenSpec<T extends Record<string, unknown>>(config: T, options?: WithOpenSpecOptions): T;
201
-
202
- /**
203
- * Returns a VitePress sidebar configuration for the OpenSpec documentation.
204
- * Includes groups for Specifications, active Changes, and archived Changes.
205
- */
206
- declare function generateOpenSpecSidebar(specDir: string, options?: {
207
- outDir?: string;
208
- }): SidebarItem[];
209
- /**
210
- * Returns a VitePress nav entry for the OpenSpec documentation section.
211
- */
212
- declare function openspecNav(specDir: string, options?: {
213
- outDir?: string;
214
- text?: string;
215
- }): NavItem | null;
216
-
217
- export { type CapabilitySpec, type Change, type ChangeArtifact, type NavItem, type OpenSpecFolder, type OpenSpecPluginOptions, type SidebarItem, type WithOpenSpecOptions, openspec as default, generateOpenSpecPages, generateOpenSpecSidebar, openspec, openspecNav, withOpenSpec };