@docyrus/docyrus 0.0.43 → 0.0.45

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/main.js CHANGED
@@ -111,17 +111,17 @@ var require_visit = __commonJS({
111
111
  visit2.BREAK = BREAK;
112
112
  visit2.SKIP = SKIP2;
113
113
  visit2.REMOVE = REMOVE;
114
- function visit_(key, node2, visitor, path7) {
115
- const ctrl = callVisitor(key, node2, visitor, path7);
114
+ function visit_(key, node2, visitor, path6) {
115
+ const ctrl = callVisitor(key, node2, visitor, path6);
116
116
  if (identity3.isNode(ctrl) || identity3.isPair(ctrl)) {
117
- replaceNode(key, path7, ctrl);
118
- return visit_(key, ctrl, visitor, path7);
117
+ replaceNode(key, path6, ctrl);
118
+ return visit_(key, ctrl, visitor, path6);
119
119
  }
120
120
  if (typeof ctrl !== "symbol") {
121
121
  if (identity3.isCollection(node2)) {
122
- path7 = Object.freeze(path7.concat(node2));
122
+ path6 = Object.freeze(path6.concat(node2));
123
123
  for (let i2 = 0; i2 < node2.items.length; ++i2) {
124
- const ci = visit_(i2, node2.items[i2], visitor, path7);
124
+ const ci = visit_(i2, node2.items[i2], visitor, path6);
125
125
  if (typeof ci === "number")
126
126
  i2 = ci - 1;
127
127
  else if (ci === BREAK)
@@ -132,13 +132,13 @@ var require_visit = __commonJS({
132
132
  }
133
133
  }
134
134
  } else if (identity3.isPair(node2)) {
135
- path7 = Object.freeze(path7.concat(node2));
136
- const ck = visit_("key", node2.key, visitor, path7);
135
+ path6 = Object.freeze(path6.concat(node2));
136
+ const ck = visit_("key", node2.key, visitor, path6);
137
137
  if (ck === BREAK)
138
138
  return BREAK;
139
139
  else if (ck === REMOVE)
140
140
  node2.key = null;
141
- const cv = visit_("value", node2.value, visitor, path7);
141
+ const cv = visit_("value", node2.value, visitor, path6);
142
142
  if (cv === BREAK)
143
143
  return BREAK;
144
144
  else if (cv === REMOVE)
@@ -159,17 +159,17 @@ var require_visit = __commonJS({
159
159
  visitAsync.BREAK = BREAK;
160
160
  visitAsync.SKIP = SKIP2;
161
161
  visitAsync.REMOVE = REMOVE;
162
- async function visitAsync_(key, node2, visitor, path7) {
163
- const ctrl = await callVisitor(key, node2, visitor, path7);
162
+ async function visitAsync_(key, node2, visitor, path6) {
163
+ const ctrl = await callVisitor(key, node2, visitor, path6);
164
164
  if (identity3.isNode(ctrl) || identity3.isPair(ctrl)) {
165
- replaceNode(key, path7, ctrl);
166
- return visitAsync_(key, ctrl, visitor, path7);
165
+ replaceNode(key, path6, ctrl);
166
+ return visitAsync_(key, ctrl, visitor, path6);
167
167
  }
168
168
  if (typeof ctrl !== "symbol") {
169
169
  if (identity3.isCollection(node2)) {
170
- path7 = Object.freeze(path7.concat(node2));
170
+ path6 = Object.freeze(path6.concat(node2));
171
171
  for (let i2 = 0; i2 < node2.items.length; ++i2) {
172
- const ci = await visitAsync_(i2, node2.items[i2], visitor, path7);
172
+ const ci = await visitAsync_(i2, node2.items[i2], visitor, path6);
173
173
  if (typeof ci === "number")
174
174
  i2 = ci - 1;
175
175
  else if (ci === BREAK)
@@ -180,13 +180,13 @@ var require_visit = __commonJS({
180
180
  }
181
181
  }
182
182
  } else if (identity3.isPair(node2)) {
183
- path7 = Object.freeze(path7.concat(node2));
184
- const ck = await visitAsync_("key", node2.key, visitor, path7);
183
+ path6 = Object.freeze(path6.concat(node2));
184
+ const ck = await visitAsync_("key", node2.key, visitor, path6);
185
185
  if (ck === BREAK)
186
186
  return BREAK;
187
187
  else if (ck === REMOVE)
188
188
  node2.key = null;
189
- const cv = await visitAsync_("value", node2.value, visitor, path7);
189
+ const cv = await visitAsync_("value", node2.value, visitor, path6);
190
190
  if (cv === BREAK)
191
191
  return BREAK;
192
192
  else if (cv === REMOVE)
@@ -213,23 +213,23 @@ var require_visit = __commonJS({
213
213
  }
214
214
  return visitor;
215
215
  }
216
- function callVisitor(key, node2, visitor, path7) {
216
+ function callVisitor(key, node2, visitor, path6) {
217
217
  if (typeof visitor === "function")
218
- return visitor(key, node2, path7);
218
+ return visitor(key, node2, path6);
219
219
  if (identity3.isMap(node2))
220
- return visitor.Map?.(key, node2, path7);
220
+ return visitor.Map?.(key, node2, path6);
221
221
  if (identity3.isSeq(node2))
222
- return visitor.Seq?.(key, node2, path7);
222
+ return visitor.Seq?.(key, node2, path6);
223
223
  if (identity3.isPair(node2))
224
- return visitor.Pair?.(key, node2, path7);
224
+ return visitor.Pair?.(key, node2, path6);
225
225
  if (identity3.isScalar(node2))
226
- return visitor.Scalar?.(key, node2, path7);
226
+ return visitor.Scalar?.(key, node2, path6);
227
227
  if (identity3.isAlias(node2))
228
- return visitor.Alias?.(key, node2, path7);
228
+ return visitor.Alias?.(key, node2, path6);
229
229
  return void 0;
230
230
  }
231
- function replaceNode(key, path7, node2) {
232
- const parent = path7[path7.length - 1];
231
+ function replaceNode(key, path6, node2) {
232
+ const parent = path6[path6.length - 1];
233
233
  if (identity3.isCollection(parent)) {
234
234
  parent.items[key] = node2;
235
235
  } else if (identity3.isPair(parent)) {
@@ -837,10 +837,10 @@ var require_Collection = __commonJS({
837
837
  var createNode = require_createNode();
838
838
  var identity3 = require_identity();
839
839
  var Node2 = require_Node();
840
- function collectionFromPath(schema, path7, value2) {
840
+ function collectionFromPath(schema, path6, value2) {
841
841
  let v = value2;
842
- for (let i2 = path7.length - 1; i2 >= 0; --i2) {
843
- const k = path7[i2];
842
+ for (let i2 = path6.length - 1; i2 >= 0; --i2) {
843
+ const k = path6[i2];
844
844
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
845
845
  const a = [];
846
846
  a[k] = v;
@@ -859,7 +859,7 @@ var require_Collection = __commonJS({
859
859
  sourceObjects: /* @__PURE__ */ new Map()
860
860
  });
861
861
  }
862
- var isEmptyPath = (path7) => path7 == null || typeof path7 === "object" && !!path7[Symbol.iterator]().next().done;
862
+ var isEmptyPath = (path6) => path6 == null || typeof path6 === "object" && !!path6[Symbol.iterator]().next().done;
863
863
  var Collection = class extends Node2.NodeBase {
864
864
  constructor(type, schema) {
865
865
  super(type);
@@ -889,11 +889,11 @@ var require_Collection = __commonJS({
889
889
  * be a Pair instance or a `{ key, value }` object, which may not have a key
890
890
  * that already exists in the map.
891
891
  */
892
- addIn(path7, value2) {
893
- if (isEmptyPath(path7))
892
+ addIn(path6, value2) {
893
+ if (isEmptyPath(path6))
894
894
  this.add(value2);
895
895
  else {
896
- const [key, ...rest] = path7;
896
+ const [key, ...rest] = path6;
897
897
  const node2 = this.get(key, true);
898
898
  if (identity3.isCollection(node2))
899
899
  node2.addIn(rest, value2);
@@ -907,8 +907,8 @@ var require_Collection = __commonJS({
907
907
  * Removes a value from the collection.
908
908
  * @returns `true` if the item was found and removed.
909
909
  */
910
- deleteIn(path7) {
911
- const [key, ...rest] = path7;
910
+ deleteIn(path6) {
911
+ const [key, ...rest] = path6;
912
912
  if (rest.length === 0)
913
913
  return this.delete(key);
914
914
  const node2 = this.get(key, true);
@@ -922,8 +922,8 @@ var require_Collection = __commonJS({
922
922
  * scalar values from their surrounding node; to disable set `keepScalar` to
923
923
  * `true` (collections are always returned intact).
924
924
  */
925
- getIn(path7, keepScalar) {
926
- const [key, ...rest] = path7;
925
+ getIn(path6, keepScalar) {
926
+ const [key, ...rest] = path6;
927
927
  const node2 = this.get(key, true);
928
928
  if (rest.length === 0)
929
929
  return !keepScalar && identity3.isScalar(node2) ? node2.value : node2;
@@ -941,8 +941,8 @@ var require_Collection = __commonJS({
941
941
  /**
942
942
  * Checks if the collection includes a value with the key `key`.
943
943
  */
944
- hasIn(path7) {
945
- const [key, ...rest] = path7;
944
+ hasIn(path6) {
945
+ const [key, ...rest] = path6;
946
946
  if (rest.length === 0)
947
947
  return this.has(key);
948
948
  const node2 = this.get(key, true);
@@ -952,8 +952,8 @@ var require_Collection = __commonJS({
952
952
  * Sets a value in this collection. For `!!set`, `value` needs to be a
953
953
  * boolean to add/remove the item from the set.
954
954
  */
955
- setIn(path7, value2) {
956
- const [key, ...rest] = path7;
955
+ setIn(path6, value2) {
956
+ const [key, ...rest] = path6;
957
957
  if (rest.length === 0) {
958
958
  this.set(key, value2);
959
959
  } else {
@@ -3465,9 +3465,9 @@ var require_Document = __commonJS({
3465
3465
  this.contents.add(value2);
3466
3466
  }
3467
3467
  /** Adds a value to the document. */
3468
- addIn(path7, value2) {
3468
+ addIn(path6, value2) {
3469
3469
  if (assertCollection(this.contents))
3470
- this.contents.addIn(path7, value2);
3470
+ this.contents.addIn(path6, value2);
3471
3471
  }
3472
3472
  /**
3473
3473
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3542,14 +3542,14 @@ var require_Document = __commonJS({
3542
3542
  * Removes a value from the document.
3543
3543
  * @returns `true` if the item was found and removed.
3544
3544
  */
3545
- deleteIn(path7) {
3546
- if (Collection.isEmptyPath(path7)) {
3545
+ deleteIn(path6) {
3546
+ if (Collection.isEmptyPath(path6)) {
3547
3547
  if (this.contents == null)
3548
3548
  return false;
3549
3549
  this.contents = null;
3550
3550
  return true;
3551
3551
  }
3552
- return assertCollection(this.contents) ? this.contents.deleteIn(path7) : false;
3552
+ return assertCollection(this.contents) ? this.contents.deleteIn(path6) : false;
3553
3553
  }
3554
3554
  /**
3555
3555
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3564,10 +3564,10 @@ var require_Document = __commonJS({
3564
3564
  * scalar values from their surrounding node; to disable set `keepScalar` to
3565
3565
  * `true` (collections are always returned intact).
3566
3566
  */
3567
- getIn(path7, keepScalar) {
3568
- if (Collection.isEmptyPath(path7))
3567
+ getIn(path6, keepScalar) {
3568
+ if (Collection.isEmptyPath(path6))
3569
3569
  return !keepScalar && identity3.isScalar(this.contents) ? this.contents.value : this.contents;
3570
- return identity3.isCollection(this.contents) ? this.contents.getIn(path7, keepScalar) : void 0;
3570
+ return identity3.isCollection(this.contents) ? this.contents.getIn(path6, keepScalar) : void 0;
3571
3571
  }
3572
3572
  /**
3573
3573
  * Checks if the document includes a value with the key `key`.
@@ -3578,10 +3578,10 @@ var require_Document = __commonJS({
3578
3578
  /**
3579
3579
  * Checks if the document includes a value at `path`.
3580
3580
  */
3581
- hasIn(path7) {
3582
- if (Collection.isEmptyPath(path7))
3581
+ hasIn(path6) {
3582
+ if (Collection.isEmptyPath(path6))
3583
3583
  return this.contents !== void 0;
3584
- return identity3.isCollection(this.contents) ? this.contents.hasIn(path7) : false;
3584
+ return identity3.isCollection(this.contents) ? this.contents.hasIn(path6) : false;
3585
3585
  }
3586
3586
  /**
3587
3587
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3598,13 +3598,13 @@ var require_Document = __commonJS({
3598
3598
  * Sets a value in this document. For `!!set`, `value` needs to be a
3599
3599
  * boolean to add/remove the item from the set.
3600
3600
  */
3601
- setIn(path7, value2) {
3602
- if (Collection.isEmptyPath(path7)) {
3601
+ setIn(path6, value2) {
3602
+ if (Collection.isEmptyPath(path6)) {
3603
3603
  this.contents = value2;
3604
3604
  } else if (this.contents == null) {
3605
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path7), value2);
3605
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path6), value2);
3606
3606
  } else if (assertCollection(this.contents)) {
3607
- this.contents.setIn(path7, value2);
3607
+ this.contents.setIn(path6, value2);
3608
3608
  }
3609
3609
  }
3610
3610
  /**
@@ -5561,9 +5561,9 @@ var require_cst_visit = __commonJS({
5561
5561
  visit2.BREAK = BREAK;
5562
5562
  visit2.SKIP = SKIP2;
5563
5563
  visit2.REMOVE = REMOVE;
5564
- visit2.itemAtPath = (cst, path7) => {
5564
+ visit2.itemAtPath = (cst, path6) => {
5565
5565
  let item = cst;
5566
- for (const [field, index2] of path7) {
5566
+ for (const [field, index2] of path6) {
5567
5567
  const tok = item?.[field];
5568
5568
  if (tok && "items" in tok) {
5569
5569
  item = tok.items[index2];
@@ -5572,23 +5572,23 @@ var require_cst_visit = __commonJS({
5572
5572
  }
5573
5573
  return item;
5574
5574
  };
5575
- visit2.parentCollection = (cst, path7) => {
5576
- const parent = visit2.itemAtPath(cst, path7.slice(0, -1));
5577
- const field = path7[path7.length - 1][0];
5575
+ visit2.parentCollection = (cst, path6) => {
5576
+ const parent = visit2.itemAtPath(cst, path6.slice(0, -1));
5577
+ const field = path6[path6.length - 1][0];
5578
5578
  const coll = parent?.[field];
5579
5579
  if (coll && "items" in coll)
5580
5580
  return coll;
5581
5581
  throw new Error("Parent collection not found");
5582
5582
  };
5583
- function _visit(path7, item, visitor) {
5584
- let ctrl = visitor(item, path7);
5583
+ function _visit(path6, item, visitor) {
5584
+ let ctrl = visitor(item, path6);
5585
5585
  if (typeof ctrl === "symbol")
5586
5586
  return ctrl;
5587
5587
  for (const field of ["key", "value"]) {
5588
5588
  const token = item[field];
5589
5589
  if (token && "items" in token) {
5590
5590
  for (let i2 = 0; i2 < token.items.length; ++i2) {
5591
- const ci = _visit(Object.freeze(path7.concat([[field, i2]])), token.items[i2], visitor);
5591
+ const ci = _visit(Object.freeze(path6.concat([[field, i2]])), token.items[i2], visitor);
5592
5592
  if (typeof ci === "number")
5593
5593
  i2 = ci - 1;
5594
5594
  else if (ci === BREAK)
@@ -5599,10 +5599,10 @@ var require_cst_visit = __commonJS({
5599
5599
  }
5600
5600
  }
5601
5601
  if (typeof ctrl === "function" && field === "key")
5602
- ctrl = ctrl(item, path7);
5602
+ ctrl = ctrl(item, path6);
5603
5603
  }
5604
5604
  }
5605
- return typeof ctrl === "function" ? ctrl(item, path7) : ctrl;
5605
+ return typeof ctrl === "function" ? ctrl(item, path6) : ctrl;
5606
5606
  }
5607
5607
  exports2.visit = visit2;
5608
5608
  }
@@ -10529,8 +10529,8 @@ var require_utils = __commonJS({
10529
10529
  }
10530
10530
  return ind;
10531
10531
  }
10532
- function removeDotSegments(path7) {
10533
- let input = path7;
10532
+ function removeDotSegments(path6) {
10533
+ let input = path6;
10534
10534
  const output = [];
10535
10535
  let nextSlash = -1;
10536
10536
  let len = 0;
@@ -10729,8 +10729,8 @@ var require_schemes = __commonJS({
10729
10729
  wsComponent.secure = void 0;
10730
10730
  }
10731
10731
  if (wsComponent.resourceName) {
10732
- const [path7, query] = wsComponent.resourceName.split("?");
10733
- wsComponent.path = path7 && path7 !== "/" ? path7 : void 0;
10732
+ const [path6, query] = wsComponent.resourceName.split("?");
10733
+ wsComponent.path = path6 && path6 !== "/" ? path6 : void 0;
10734
10734
  wsComponent.query = query;
10735
10735
  wsComponent.resourceName = void 0;
10736
10736
  }
@@ -61639,15 +61639,15 @@ var require_route = __commonJS({
61639
61639
  };
61640
61640
  }
61641
61641
  function wrapConversion(toModel, graph) {
61642
- const path7 = [graph[toModel].parent, toModel];
61642
+ const path6 = [graph[toModel].parent, toModel];
61643
61643
  let fn = conversions[graph[toModel].parent][toModel];
61644
61644
  let cur = graph[toModel].parent;
61645
61645
  while (graph[cur].parent) {
61646
- path7.unshift(graph[cur].parent);
61646
+ path6.unshift(graph[cur].parent);
61647
61647
  fn = link3(conversions[graph[cur].parent][cur], fn);
61648
61648
  cur = graph[cur].parent;
61649
61649
  }
61650
- fn.conversion = path7;
61650
+ fn.conversion = path6;
61651
61651
  return fn;
61652
61652
  }
61653
61653
  module2.exports = function(fromModel) {
@@ -76272,11 +76272,11 @@ var require_commonjs3 = __commonJS({
76272
76272
  return (f) => f.length === len && f !== "." && f !== "..";
76273
76273
  };
76274
76274
  var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
76275
- var path7 = {
76275
+ var path6 = {
76276
76276
  win32: { sep: "\\" },
76277
76277
  posix: { sep: "/" }
76278
76278
  };
76279
- exports2.sep = defaultPlatform === "win32" ? path7.win32.sep : path7.posix.sep;
76279
+ exports2.sep = defaultPlatform === "win32" ? path6.win32.sep : path6.posix.sep;
76280
76280
  exports2.minimatch.sep = exports2.sep;
76281
76281
  exports2.GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
76282
76282
  exports2.minimatch.GLOBSTAR = exports2.GLOBSTAR;
@@ -77047,7 +77047,7 @@ var require_lib4 = __commonJS({
77047
77047
  "../../node_modules/.pnpm/ignore-walk@8.0.0/node_modules/ignore-walk/lib/index.js"(exports2, module2) {
77048
77048
  "use strict";
77049
77049
  var fs7 = require("fs");
77050
- var path7 = require("path");
77050
+ var path6 = require("path");
77051
77051
  var EE = require("events").EventEmitter;
77052
77052
  var Minimatch = require_commonjs3().Minimatch;
77053
77053
  var Walker = class _Walker extends EE {
@@ -77056,7 +77056,7 @@ var require_lib4 = __commonJS({
77056
77056
  super(opts);
77057
77057
  this.isSymbolicLink = opts.isSymbolicLink;
77058
77058
  this.path = opts.path || process.cwd();
77059
- this.basename = path7.basename(this.path);
77059
+ this.basename = path6.basename(this.path);
77060
77060
  this.ignoreFiles = opts.ignoreFiles || [".ignore"];
77061
77061
  this.ignoreRules = {};
77062
77062
  this.parent = opts.parent || null;
@@ -77122,7 +77122,7 @@ var require_lib4 = __commonJS({
77122
77122
  newIg.forEach((e) => this.addIgnoreFile(e, then));
77123
77123
  }
77124
77124
  addIgnoreFile(file2, then) {
77125
- const ig = path7.resolve(this.path, file2);
77125
+ const ig = path6.resolve(this.path, file2);
77126
77126
  fs7.readFile(ig, "utf8", (er, data) => er ? this.emit("error", er) : this.onReadIgnoreFile(file2, data, then));
77127
77127
  }
77128
77128
  onReadIgnoreFile(file2, data, then) {
@@ -77244,7 +77244,7 @@ var require_lib4 = __commonJS({
77244
77244
  return this;
77245
77245
  }
77246
77246
  addIgnoreFile(file2, then) {
77247
- const ig = path7.resolve(this.path, file2);
77247
+ const ig = path6.resolve(this.path, file2);
77248
77248
  this.onReadIgnoreFile(file2, fs7.readFileSync(ig, "utf8"), then);
77249
77249
  }
77250
77250
  stat({ entry, file: file2, dir }, then) {
@@ -85621,8 +85621,8 @@ function assertNonEmpty(part, name2) {
85621
85621
  throw new Error("`" + name2 + "` cannot be empty");
85622
85622
  }
85623
85623
  }
85624
- function assertPath(path7, name2) {
85625
- if (!path7) {
85624
+ function assertPath(path6, name2) {
85625
+ if (!path6) {
85626
85626
  throw new Error("Setting `" + name2 + "` requires `path` to be set too");
85627
85627
  }
85628
85628
  }
@@ -85808,13 +85808,13 @@ var init_lib10 = __esm({
85808
85808
  * @returns {undefined}
85809
85809
  * Nothing.
85810
85810
  */
85811
- set path(path7) {
85812
- if (isUrl(path7)) {
85813
- path7 = (0, import_node_url.fileURLToPath)(path7);
85811
+ set path(path6) {
85812
+ if (isUrl(path6)) {
85813
+ path6 = (0, import_node_url.fileURLToPath)(path6);
85814
85814
  }
85815
- assertNonEmpty(path7, "path");
85816
- if (this.path !== path7) {
85817
- this.history.push(path7);
85815
+ assertNonEmpty(path6, "path");
85816
+ if (this.path !== path6) {
85817
+ this.history.push(path6);
85818
85818
  }
85819
85819
  }
85820
85820
  /**
@@ -88717,14 +88717,14 @@ var require_util3 = __commonJS({
88717
88717
  }
88718
88718
  const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
88719
88719
  let origin = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
88720
- let path7 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
88720
+ let path6 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
88721
88721
  if (origin[origin.length - 1] === "/") {
88722
88722
  origin = origin.slice(0, origin.length - 1);
88723
88723
  }
88724
- if (path7 && path7[0] !== "/") {
88725
- path7 = `/${path7}`;
88724
+ if (path6 && path6[0] !== "/") {
88725
+ path6 = `/${path6}`;
88726
88726
  }
88727
- return new URL(`${origin}${path7}`);
88727
+ return new URL(`${origin}${path6}`);
88728
88728
  }
88729
88729
  if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
88730
88730
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -89545,9 +89545,9 @@ var require_diagnostics = __commonJS({
89545
89545
  "undici:client:sendHeaders",
89546
89546
  (evt) => {
89547
89547
  const {
89548
- request: { method, path: path7, origin }
89548
+ request: { method, path: path6, origin }
89549
89549
  } = evt;
89550
- debugLog("sending request to %s %s%s", method, origin, path7);
89550
+ debugLog("sending request to %s %s%s", method, origin, path6);
89551
89551
  }
89552
89552
  );
89553
89553
  }
@@ -89565,14 +89565,14 @@ var require_diagnostics = __commonJS({
89565
89565
  "undici:request:headers",
89566
89566
  (evt) => {
89567
89567
  const {
89568
- request: { method, path: path7, origin },
89568
+ request: { method, path: path6, origin },
89569
89569
  response: { statusCode }
89570
89570
  } = evt;
89571
89571
  debugLog(
89572
89572
  "received response to %s %s%s - HTTP %d",
89573
89573
  method,
89574
89574
  origin,
89575
- path7,
89575
+ path6,
89576
89576
  statusCode
89577
89577
  );
89578
89578
  }
@@ -89581,23 +89581,23 @@ var require_diagnostics = __commonJS({
89581
89581
  "undici:request:trailers",
89582
89582
  (evt) => {
89583
89583
  const {
89584
- request: { method, path: path7, origin }
89584
+ request: { method, path: path6, origin }
89585
89585
  } = evt;
89586
- debugLog("trailers received from %s %s%s", method, origin, path7);
89586
+ debugLog("trailers received from %s %s%s", method, origin, path6);
89587
89587
  }
89588
89588
  );
89589
89589
  diagnosticsChannel.subscribe(
89590
89590
  "undici:request:error",
89591
89591
  (evt) => {
89592
89592
  const {
89593
- request: { method, path: path7, origin },
89593
+ request: { method, path: path6, origin },
89594
89594
  error: error48
89595
89595
  } = evt;
89596
89596
  debugLog(
89597
89597
  "request to %s %s%s errored - %s",
89598
89598
  method,
89599
89599
  origin,
89600
- path7,
89600
+ path6,
89601
89601
  error48.message
89602
89602
  );
89603
89603
  }
@@ -89700,7 +89700,7 @@ var require_request = __commonJS({
89700
89700
  var kHandler = /* @__PURE__ */ Symbol("handler");
89701
89701
  var Request = class {
89702
89702
  constructor(origin, {
89703
- path: path7,
89703
+ path: path6,
89704
89704
  method,
89705
89705
  body: body2,
89706
89706
  headers,
@@ -89717,11 +89717,11 @@ var require_request = __commonJS({
89717
89717
  maxRedirections,
89718
89718
  typeOfService
89719
89719
  }, handler2) {
89720
- if (typeof path7 !== "string") {
89720
+ if (typeof path6 !== "string") {
89721
89721
  throw new InvalidArgumentError("path must be a string");
89722
- } else if (path7[0] !== "/" && !(path7.startsWith("http://") || path7.startsWith("https://")) && method !== "CONNECT") {
89722
+ } else if (path6[0] !== "/" && !(path6.startsWith("http://") || path6.startsWith("https://")) && method !== "CONNECT") {
89723
89723
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
89724
- } else if (invalidPathRegex.test(path7)) {
89724
+ } else if (invalidPathRegex.test(path6)) {
89725
89725
  throw new InvalidArgumentError("invalid request path");
89726
89726
  }
89727
89727
  if (typeof method !== "string") {
@@ -89796,7 +89796,7 @@ var require_request = __commonJS({
89796
89796
  this.completed = false;
89797
89797
  this.aborted = false;
89798
89798
  this.upgrade = upgrade || null;
89799
- this.path = query ? serializePathWithQuery(path7, query) : path7;
89799
+ this.path = query ? serializePathWithQuery(path6, query) : path6;
89800
89800
  this.origin = origin;
89801
89801
  this.protocol = getProtocolFromUrlString(origin);
89802
89802
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -94835,7 +94835,7 @@ var require_client_h1 = __commonJS({
94835
94835
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
94836
94836
  }
94837
94837
  function writeH1(client, request) {
94838
- const { method, path: path7, host, upgrade, blocking, reset } = request;
94838
+ const { method, path: path6, host, upgrade, blocking, reset } = request;
94839
94839
  let { body: body2, headers, contentLength } = request;
94840
94840
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
94841
94841
  if (util2.isFormDataLike(body2)) {
@@ -94904,7 +94904,7 @@ var require_client_h1 = __commonJS({
94904
94904
  if (socket.setTypeOfService) {
94905
94905
  socket.setTypeOfService(request.typeOfService);
94906
94906
  }
94907
- let header = `${method} ${path7} HTTP/1.1\r
94907
+ let header = `${method} ${path6} HTTP/1.1\r
94908
94908
  `;
94909
94909
  if (typeof host === "string") {
94910
94910
  header += `host: ${host}\r
@@ -95557,7 +95557,7 @@ var require_client_h2 = __commonJS({
95557
95557
  function writeH2(client, request) {
95558
95558
  const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout];
95559
95559
  const session = client[kHTTP2Session];
95560
- const { method, path: path7, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
95560
+ const { method, path: path6, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
95561
95561
  let { body: body2 } = request;
95562
95562
  if (upgrade != null && upgrade !== "websocket") {
95563
95563
  util2.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -95625,7 +95625,7 @@ var require_client_h2 = __commonJS({
95625
95625
  }
95626
95626
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
95627
95627
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
95628
- headers[HTTP2_HEADER_PATH] = path7;
95628
+ headers[HTTP2_HEADER_PATH] = path6;
95629
95629
  if (protocol === "ws:" || protocol === "wss:") {
95630
95630
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
95631
95631
  } else {
@@ -95666,7 +95666,7 @@ var require_client_h2 = __commonJS({
95666
95666
  stream.setTimeout(requestTimeout);
95667
95667
  return true;
95668
95668
  }
95669
- headers[HTTP2_HEADER_PATH] = path7;
95669
+ headers[HTTP2_HEADER_PATH] = path6;
95670
95670
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
95671
95671
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
95672
95672
  if (body2 && typeof body2.read === "function") {
@@ -97968,10 +97968,10 @@ var require_proxy_agent = __commonJS({
97968
97968
  };
97969
97969
  const {
97970
97970
  origin,
97971
- path: path7 = "/",
97971
+ path: path6 = "/",
97972
97972
  headers = {}
97973
97973
  } = opts;
97974
- opts.path = origin + path7;
97974
+ opts.path = origin + path6;
97975
97975
  if (!("host" in headers) && !("Host" in headers)) {
97976
97976
  const { host } = new URL(origin);
97977
97977
  headers.host = host;
@@ -100034,20 +100034,20 @@ var require_mock_utils = __commonJS({
100034
100034
  }
100035
100035
  return normalizedQp;
100036
100036
  }
100037
- function safeUrl(path7) {
100038
- if (typeof path7 !== "string") {
100039
- return path7;
100037
+ function safeUrl(path6) {
100038
+ if (typeof path6 !== "string") {
100039
+ return path6;
100040
100040
  }
100041
- const pathSegments = path7.split("?", 3);
100041
+ const pathSegments = path6.split("?", 3);
100042
100042
  if (pathSegments.length !== 2) {
100043
- return path7;
100043
+ return path6;
100044
100044
  }
100045
100045
  const qp = new URLSearchParams(pathSegments.pop());
100046
100046
  qp.sort();
100047
100047
  return [...pathSegments, qp.toString()].join("?");
100048
100048
  }
100049
- function matchKey(mockDispatch2, { path: path7, method, body: body2, headers }) {
100050
- const pathMatch = matchValue(mockDispatch2.path, path7);
100049
+ function matchKey(mockDispatch2, { path: path6, method, body: body2, headers }) {
100050
+ const pathMatch = matchValue(mockDispatch2.path, path6);
100051
100051
  const methodMatch = matchValue(mockDispatch2.method, method);
100052
100052
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body2) : true;
100053
100053
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -100072,8 +100072,8 @@ var require_mock_utils = __commonJS({
100072
100072
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
100073
100073
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
100074
100074
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
100075
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path7, ignoreTrailingSlash }) => {
100076
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path7)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path7), resolvedPath);
100075
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path6, ignoreTrailingSlash }) => {
100076
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path6)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path6), resolvedPath);
100077
100077
  });
100078
100078
  if (matchedMockDispatches.length === 0) {
100079
100079
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -100112,19 +100112,19 @@ var require_mock_utils = __commonJS({
100112
100112
  mockDispatches.splice(index2, 1);
100113
100113
  }
100114
100114
  }
100115
- function removeTrailingSlash(path7) {
100116
- while (path7.endsWith("/")) {
100117
- path7 = path7.slice(0, -1);
100115
+ function removeTrailingSlash(path6) {
100116
+ while (path6.endsWith("/")) {
100117
+ path6 = path6.slice(0, -1);
100118
100118
  }
100119
- if (path7.length === 0) {
100120
- path7 = "/";
100119
+ if (path6.length === 0) {
100120
+ path6 = "/";
100121
100121
  }
100122
- return path7;
100122
+ return path6;
100123
100123
  }
100124
100124
  function buildKey(opts) {
100125
- const { path: path7, method, body: body2, headers, query } = opts;
100125
+ const { path: path6, method, body: body2, headers, query } = opts;
100126
100126
  return {
100127
- path: path7,
100127
+ path: path6,
100128
100128
  method,
100129
100129
  body: body2,
100130
100130
  headers,
@@ -100814,10 +100814,10 @@ var require_pending_interceptors_formatter = __commonJS({
100814
100814
  }
100815
100815
  format(pendingInterceptors) {
100816
100816
  const withPrettyHeaders = pendingInterceptors.map(
100817
- ({ method, path: path7, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
100817
+ ({ method, path: path6, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
100818
100818
  Method: method,
100819
100819
  Origin: origin,
100820
- Path: path7,
100820
+ Path: path6,
100821
100821
  "Status code": statusCode,
100822
100822
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
100823
100823
  Invocations: timesInvoked,
@@ -100899,9 +100899,9 @@ var require_mock_agent = __commonJS({
100899
100899
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
100900
100900
  const dispatchOpts = { ...opts };
100901
100901
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
100902
- const [path7, searchParams] = dispatchOpts.path.split("?");
100902
+ const [path6, searchParams] = dispatchOpts.path.split("?");
100903
100903
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
100904
- dispatchOpts.path = `${path7}?${normalizedSearchParams}`;
100904
+ dispatchOpts.path = `${path6}?${normalizedSearchParams}`;
100905
100905
  }
100906
100906
  return this[kAgent].dispatch(dispatchOpts, handler2);
100907
100907
  }
@@ -101302,12 +101302,12 @@ var require_snapshot_recorder = __commonJS({
101302
101302
  * @return {Promise<void>} - Resolves when snapshots are loaded
101303
101303
  */
101304
101304
  async loadSnapshots(filePath) {
101305
- const path7 = filePath || this.#snapshotPath;
101306
- if (!path7) {
101305
+ const path6 = filePath || this.#snapshotPath;
101306
+ if (!path6) {
101307
101307
  throw new InvalidArgumentError("Snapshot path is required");
101308
101308
  }
101309
101309
  try {
101310
- const data = await readFile17(resolve2(path7), "utf8");
101310
+ const data = await readFile17(resolve2(path6), "utf8");
101311
101311
  const parsed = JSON.parse(data);
101312
101312
  if (Array.isArray(parsed)) {
101313
101313
  this.#snapshots.clear();
@@ -101321,7 +101321,7 @@ var require_snapshot_recorder = __commonJS({
101321
101321
  if (error48.code === "ENOENT") {
101322
101322
  this.#snapshots.clear();
101323
101323
  } else {
101324
- throw new UndiciError(`Failed to load snapshots from ${path7}`, { cause: error48 });
101324
+ throw new UndiciError(`Failed to load snapshots from ${path6}`, { cause: error48 });
101325
101325
  }
101326
101326
  }
101327
101327
  }
@@ -101332,11 +101332,11 @@ var require_snapshot_recorder = __commonJS({
101332
101332
  * @returns {Promise<void>} - Resolves when snapshots are saved
101333
101333
  */
101334
101334
  async saveSnapshots(filePath) {
101335
- const path7 = filePath || this.#snapshotPath;
101336
- if (!path7) {
101335
+ const path6 = filePath || this.#snapshotPath;
101336
+ if (!path6) {
101337
101337
  throw new InvalidArgumentError("Snapshot path is required");
101338
101338
  }
101339
- const resolvedPath = resolve2(path7);
101339
+ const resolvedPath = resolve2(path6);
101340
101340
  await mkdir10(dirname13(resolvedPath), { recursive: true });
101341
101341
  const data = Array.from(this.#snapshots.entries()).map(([hash3, snapshot]) => ({
101342
101342
  hash: hash3,
@@ -101961,15 +101961,15 @@ var require_redirect_handler = __commonJS({
101961
101961
  return;
101962
101962
  }
101963
101963
  const { origin, pathname, search: search2 } = util2.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
101964
- const path7 = search2 ? `${pathname}${search2}` : pathname;
101965
- const redirectUrlString = `${origin}${path7}`;
101964
+ const path6 = search2 ? `${pathname}${search2}` : pathname;
101965
+ const redirectUrlString = `${origin}${path6}`;
101966
101966
  for (const historyUrl of this.history) {
101967
101967
  if (historyUrl.toString() === redirectUrlString) {
101968
101968
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
101969
101969
  }
101970
101970
  }
101971
101971
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
101972
- this.opts.path = path7;
101972
+ this.opts.path = path6;
101973
101973
  this.opts.origin = origin;
101974
101974
  this.opts.query = null;
101975
101975
  }
@@ -108176,11 +108176,11 @@ var require_fetch = __commonJS({
108176
108176
  function dispatch({ body: body2 }) {
108177
108177
  const url2 = requestCurrentURL(request);
108178
108178
  const agent = fetchParams.controller.dispatcher;
108179
- const path7 = url2.pathname + url2.search;
108179
+ const path6 = url2.pathname + url2.search;
108180
108180
  const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
108181
108181
  return new Promise((resolve2, reject) => agent.dispatch(
108182
108182
  {
108183
- path: hasTrailingQuestionMark ? `${path7}?` : path7,
108183
+ path: hasTrailingQuestionMark ? `${path6}?` : path6,
108184
108184
  origin: url2.origin,
108185
108185
  method: request.method,
108186
108186
  body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body2,
@@ -109127,9 +109127,9 @@ var require_util6 = __commonJS({
109127
109127
  }
109128
109128
  }
109129
109129
  }
109130
- function validateCookiePath(path7) {
109131
- for (let i2 = 0; i2 < path7.length; ++i2) {
109132
- const code = path7.charCodeAt(i2);
109130
+ function validateCookiePath(path6) {
109131
+ for (let i2 = 0; i2 < path6.length; ++i2) {
109132
+ const code = path6.charCodeAt(i2);
109133
109133
  if (code < 32 || // exclude CTLs (0-31)
109134
109134
  code === 127 || // DEL
109135
109135
  code === 59) {
@@ -112299,11 +112299,11 @@ var require_undici = __commonJS({
112299
112299
  if (typeof opts.path !== "string") {
112300
112300
  throw new InvalidArgumentError("invalid opts.path");
112301
112301
  }
112302
- let path7 = opts.path;
112302
+ let path6 = opts.path;
112303
112303
  if (!opts.path.startsWith("/")) {
112304
- path7 = `/${path7}`;
112304
+ path6 = `/${path6}`;
112305
112305
  }
112306
- url2 = new URL(util2.parseOrigin(url2).origin + path7);
112306
+ url2 = new URL(util2.parseOrigin(url2).origin + path6);
112307
112307
  } else {
112308
112308
  if (!opts) {
112309
112309
  opts = typeof url2 === "object" ? url2 : {};
@@ -113187,10 +113187,10 @@ function mergeDefs(...defs) {
113187
113187
  function cloneDef(schema) {
113188
113188
  return mergeDefs(schema._zod.def);
113189
113189
  }
113190
- function getElementAtPath(obj, path7) {
113191
- if (!path7)
113190
+ function getElementAtPath(obj, path6) {
113191
+ if (!path6)
113192
113192
  return obj;
113193
- return path7.reduce((acc, key) => acc?.[key], obj);
113193
+ return path6.reduce((acc, key) => acc?.[key], obj);
113194
113194
  }
113195
113195
  function promiseAllObject(promisesObj) {
113196
113196
  const keys = Object.keys(promisesObj);
@@ -113573,11 +113573,11 @@ function aborted(x, startIndex = 0) {
113573
113573
  }
113574
113574
  return false;
113575
113575
  }
113576
- function prefixIssues(path7, issues) {
113576
+ function prefixIssues(path6, issues) {
113577
113577
  return issues.map((iss) => {
113578
113578
  var _a2;
113579
113579
  (_a2 = iss).path ?? (_a2.path = []);
113580
- iss.path.unshift(path7);
113580
+ iss.path.unshift(path6);
113581
113581
  return iss;
113582
113582
  });
113583
113583
  }
@@ -113760,7 +113760,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
113760
113760
  }
113761
113761
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
113762
113762
  const result = { errors: [] };
113763
- const processError = (error49, path7 = []) => {
113763
+ const processError = (error49, path6 = []) => {
113764
113764
  var _a2, _b;
113765
113765
  for (const issue2 of error49.issues) {
113766
113766
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -113770,7 +113770,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
113770
113770
  } else if (issue2.code === "invalid_element") {
113771
113771
  processError({ issues: issue2.issues }, issue2.path);
113772
113772
  } else {
113773
- const fullpath = [...path7, ...issue2.path];
113773
+ const fullpath = [...path6, ...issue2.path];
113774
113774
  if (fullpath.length === 0) {
113775
113775
  result.errors.push(mapper(issue2));
113776
113776
  continue;
@@ -113802,8 +113802,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
113802
113802
  }
113803
113803
  function toDotPath(_path) {
113804
113804
  const segs = [];
113805
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
113806
- for (const seg of path7) {
113805
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
113806
+ for (const seg of path6) {
113807
113807
  if (typeof seg === "number")
113808
113808
  segs.push(`[${seg}]`);
113809
113809
  else if (typeof seg === "symbol")
@@ -125780,13 +125780,13 @@ function resolveRef(ref, ctx) {
125780
125780
  if (!ref.startsWith("#")) {
125781
125781
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
125782
125782
  }
125783
- const path7 = ref.slice(1).split("/").filter(Boolean);
125784
- if (path7.length === 0) {
125783
+ const path6 = ref.slice(1).split("/").filter(Boolean);
125784
+ if (path6.length === 0) {
125785
125785
  return ctx.rootSchema;
125786
125786
  }
125787
125787
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
125788
- if (path7[0] === defsKey) {
125789
- const key = path7[1];
125788
+ if (path6[0] === defsKey) {
125789
+ const key = path6[1];
125790
125790
  if (!key || !ctx.defs[key]) {
125791
125791
  throw new Error(`Reference not found: ${ref}`);
125792
125792
  }
@@ -126626,26 +126626,26 @@ function applyReplacer(root, replacer) {
126626
126626
  if (replacedRoot === void 0) return transformChildren(root, replacer, []);
126627
126627
  return transformChildren(normalizeValue(replacedRoot), replacer, []);
126628
126628
  }
126629
- function transformChildren(value2, replacer, path7) {
126630
- if (isJsonObject(value2)) return transformObject(value2, replacer, path7);
126631
- if (isJsonArray(value2)) return transformArray(value2, replacer, path7);
126629
+ function transformChildren(value2, replacer, path6) {
126630
+ if (isJsonObject(value2)) return transformObject(value2, replacer, path6);
126631
+ if (isJsonArray(value2)) return transformArray(value2, replacer, path6);
126632
126632
  return value2;
126633
126633
  }
126634
- function transformObject(obj, replacer, path7) {
126634
+ function transformObject(obj, replacer, path6) {
126635
126635
  const result = {};
126636
126636
  for (const [key, value2] of Object.entries(obj)) {
126637
- const childPath = [...path7, key];
126637
+ const childPath = [...path6, key];
126638
126638
  const replacedValue = replacer(key, value2, childPath);
126639
126639
  if (replacedValue === void 0) continue;
126640
126640
  result[key] = transformChildren(normalizeValue(replacedValue), replacer, childPath);
126641
126641
  }
126642
126642
  return result;
126643
126643
  }
126644
- function transformArray(arr, replacer, path7) {
126644
+ function transformArray(arr, replacer, path6) {
126645
126645
  const result = [];
126646
126646
  for (let i2 = 0; i2 < arr.length; i2++) {
126647
126647
  const value2 = arr[i2];
126648
- const childPath = [...path7, i2];
126648
+ const childPath = [...path6, i2];
126649
126649
  const replacedValue = replacer(String(i2), value2, childPath);
126650
126650
  if (replacedValue === void 0) continue;
126651
126651
  const normalizedValue = normalizeValue(replacedValue);
@@ -126713,33 +126713,33 @@ function columnarTable(items) {
126713
126713
  const keys = [...new Set(items.flatMap(Object.keys))];
126714
126714
  return table(keys, items.map((item) => keys.map((k) => String(item[k] ?? ""))));
126715
126715
  }
126716
- function formatMarkdown(value2, path7 = []) {
126716
+ function formatMarkdown(value2, path6 = []) {
126717
126717
  if (isScalar(value2)) {
126718
- if (path7.length === 0)
126718
+ if (path6.length === 0)
126719
126719
  return String(value2);
126720
- return `## ${path7.join(".")}
126720
+ return `## ${path6.join(".")}
126721
126721
 
126722
126722
  ${String(value2)}`;
126723
126723
  }
126724
126724
  if (Array.isArray(value2)) {
126725
126725
  if (isArrayOfObjects2(value2)) {
126726
126726
  const table2 = columnarTable(value2);
126727
- if (path7.length === 0)
126727
+ if (path6.length === 0)
126728
126728
  return table2;
126729
- return `## ${path7.join(".")}
126729
+ return `## ${path6.join(".")}
126730
126730
 
126731
126731
  ${table2}`;
126732
126732
  }
126733
- return formatMarkdown(String(value2), path7);
126733
+ return formatMarkdown(String(value2), path6);
126734
126734
  }
126735
126735
  const obj = value2;
126736
126736
  const entries = Object.entries(obj);
126737
- if (path7.length === 0 && isFlat(obj))
126737
+ if (path6.length === 0 && isFlat(obj))
126738
126738
  return kvTable(obj);
126739
- const needsHeadings = path7.length > 0 || entries.length > 1 || entries.some(([, v]) => !isScalar(v));
126739
+ const needsHeadings = path6.length > 0 || entries.length > 1 || entries.some(([, v]) => !isScalar(v));
126740
126740
  if (needsHeadings) {
126741
126741
  const sections = entries.map(([key, val]) => {
126742
- const childPath = [...path7, key];
126742
+ const childPath = [...path6, key];
126743
126743
  if (isScalar(val))
126744
126744
  return `## ${childPath.join(".")}
126745
126745
 
@@ -127353,8 +127353,8 @@ function getErrorMap2() {
127353
127353
 
127354
127354
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/parseUtil.js
127355
127355
  var makeIssue = (params) => {
127356
- const { data, path: path7, errorMaps, issueData } = params;
127357
- const fullPath = [...path7, ...issueData.path || []];
127356
+ const { data, path: path6, errorMaps, issueData } = params;
127357
+ const fullPath = [...path6, ...issueData.path || []];
127358
127358
  const fullIssue = {
127359
127359
  ...issueData,
127360
127360
  path: fullPath
@@ -127469,11 +127469,11 @@ var errorUtil;
127469
127469
 
127470
127470
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/types.js
127471
127471
  var ParseInputLazyPath = class {
127472
- constructor(parent, value2, path7, key) {
127472
+ constructor(parent, value2, path6, key) {
127473
127473
  this._cachedPath = [];
127474
127474
  this.parent = parent;
127475
127475
  this.data = value2;
127476
- this._path = path7;
127476
+ this._path = path6;
127477
127477
  this._key = key;
127478
127478
  }
127479
127479
  get path() {
@@ -136608,12 +136608,12 @@ function isAsyncGenerator(value2) {
136608
136608
  function collectTools(commands, prefix) {
136609
136609
  const result = [];
136610
136610
  for (const [name2, entry] of commands) {
136611
- const path7 = [...prefix, name2];
136611
+ const path6 = [...prefix, name2];
136612
136612
  if ("_group" in entry && entry._group)
136613
- result.push(...collectTools(entry.commands, path7));
136613
+ result.push(...collectTools(entry.commands, path6));
136614
136614
  else {
136615
136615
  result.push({
136616
- name: path7.join("_"),
136616
+ name: path6.join("_"),
136617
136617
  description: entry.description,
136618
136618
  inputSchema: buildToolSchema(entry.args, entry.options),
136619
136619
  command: entry
@@ -137758,7 +137758,7 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137758
137758
  exit2(1);
137759
137759
  return;
137760
137760
  }
137761
- const { command, path: path7, rest } = effective;
137761
+ const { command, path: path6, rest } = effective;
137762
137762
  try {
137763
137763
  const { args: args2, options: parsedOptions } = parse3(rest, {
137764
137764
  alias: command.alias,
@@ -137784,7 +137784,7 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137784
137784
  if (isAsyncGenerator2(result)) {
137785
137785
  await handleStreaming(result, {
137786
137786
  name: name2,
137787
- path: path7,
137787
+ path: path6,
137788
137788
  start: start2,
137789
137789
  format: format2,
137790
137790
  formatExplicit,
@@ -137805,7 +137805,7 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137805
137805
  ok: true,
137806
137806
  data: awaited.data,
137807
137807
  meta: {
137808
- command: path7,
137808
+ command: path6,
137809
137809
  duration: `${Math.round(performance.now() - start2)}ms`,
137810
137810
  ...cta ? { cta } : void 0
137811
137811
  }
@@ -137819,7 +137819,7 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137819
137819
  ...awaited.retryable !== void 0 ? { retryable: awaited.retryable } : void 0
137820
137820
  },
137821
137821
  meta: {
137822
- command: path7,
137822
+ command: path6,
137823
137823
  duration: `${Math.round(performance.now() - start2)}ms`,
137824
137824
  ...cta ? { cta } : void 0
137825
137825
  }
@@ -137831,7 +137831,7 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137831
137831
  ok: true,
137832
137832
  data: awaited,
137833
137833
  meta: {
137834
- command: path7,
137834
+ command: path6,
137835
137835
  duration: `${Math.round(performance.now() - start2)}ms`
137836
137836
  }
137837
137837
  });
@@ -137846,12 +137846,12 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137846
137846
  ...error48 instanceof ValidationError ? { fieldErrors: error48.fieldErrors } : void 0
137847
137847
  },
137848
137848
  meta: {
137849
- command: path7,
137849
+ command: path6,
137850
137850
  duration: `${Math.round(performance.now() - start2)}ms`
137851
137851
  }
137852
137852
  };
137853
137853
  if (human && !formatExplicit && error48 instanceof ValidationError) {
137854
- writeln(formatHumanValidationError(name2, path7, command, error48));
137854
+ writeln(formatHumanValidationError(name2, path6, command, error48));
137855
137855
  exit2(1);
137856
137856
  return;
137857
137857
  }
@@ -137859,13 +137859,13 @@ async function serveImpl(name2, commands, argv, options2 = {}) {
137859
137859
  exit2(1);
137860
137860
  }
137861
137861
  }
137862
- function formatHumanValidationError(cli2, path7, command, error48) {
137862
+ function formatHumanValidationError(cli2, path6, command, error48) {
137863
137863
  const lines = [];
137864
137864
  for (const fe of error48.fieldErrors)
137865
137865
  lines.push(`Error: missing required argument <${fe.path}>`);
137866
137866
  lines.push("See below for usage.");
137867
137867
  lines.push("");
137868
- lines.push(formatCommand(path7 === cli2 ? cli2 : `${cli2} ${path7}`, {
137868
+ lines.push(formatCommand(path6 === cli2 ? cli2 : `${cli2} ${path6}`, {
137869
137869
  alias: command.alias,
137870
137870
  description: command.description,
137871
137871
  args: command.args,
@@ -137882,7 +137882,7 @@ function resolveCommand(commands, tokens) {
137882
137882
  if (!first || !commands.has(first))
137883
137883
  return { error: first ?? "(none)", path: "" };
137884
137884
  let entry = commands.get(first);
137885
- const path7 = [first];
137885
+ const path6 = [first];
137886
137886
  let remaining = rest;
137887
137887
  let inheritedOutputPolicy;
137888
137888
  while (isGroup(entry)) {
@@ -137892,22 +137892,22 @@ function resolveCommand(commands, tokens) {
137892
137892
  if (!next)
137893
137893
  return {
137894
137894
  help: true,
137895
- path: path7.join(" "),
137895
+ path: path6.join(" "),
137896
137896
  description: entry.description,
137897
137897
  commands: entry.commands
137898
137898
  };
137899
137899
  const child = entry.commands.get(next);
137900
137900
  if (!child) {
137901
- return { error: next, path: path7.join(" ") };
137901
+ return { error: next, path: path6.join(" ") };
137902
137902
  }
137903
- path7.push(next);
137903
+ path6.push(next);
137904
137904
  remaining = remaining.slice(1);
137905
137905
  entry = child;
137906
137906
  }
137907
137907
  const outputPolicy = entry.outputPolicy ?? inheritedOutputPolicy;
137908
137908
  return {
137909
137909
  command: entry,
137910
- path: path7.join(" "),
137910
+ path: path6.join(" "),
137911
137911
  rest: remaining,
137912
137912
  ...outputPolicy ? { outputPolicy } : void 0
137913
137913
  };
@@ -138172,11 +138172,11 @@ function buildManifest(commands, prefix = []) {
138172
138172
  function collectCommands(commands, prefix) {
138173
138173
  const result = [];
138174
138174
  for (const [name2, entry] of commands) {
138175
- const path7 = [...prefix, name2];
138175
+ const path6 = [...prefix, name2];
138176
138176
  if (isGroup(entry)) {
138177
- result.push(...collectCommands(entry.commands, path7));
138177
+ result.push(...collectCommands(entry.commands, path6));
138178
138178
  } else {
138179
- const cmd = { name: path7.join(" ") };
138179
+ const cmd = { name: path6.join(" ") };
138180
138180
  if (entry.description)
138181
138181
  cmd.description = entry.description;
138182
138182
  const inputSchema = buildInputSchema(entry.args, entry.env, entry.options);
@@ -138194,7 +138194,7 @@ function collectCommands(commands, prefix) {
138194
138194
  }
138195
138195
  const examples = formatExamples(entry.examples);
138196
138196
  if (examples) {
138197
- const cmdName = path7.join(" ");
138197
+ const cmdName = path6.join(" ");
138198
138198
  cmd.examples = examples.map((e) => ({
138199
138199
  ...e,
138200
138200
  command: e.command ? `${cmdName} ${e.command}` : cmdName
@@ -138208,13 +138208,13 @@ function collectCommands(commands, prefix) {
138208
138208
  function collectSkillCommands(commands, prefix, groups) {
138209
138209
  const result = [];
138210
138210
  for (const [name2, entry] of commands) {
138211
- const path7 = [...prefix, name2];
138211
+ const path6 = [...prefix, name2];
138212
138212
  if (isGroup(entry)) {
138213
138213
  if (entry.description)
138214
- groups.set(path7.join(" "), entry.description);
138215
- result.push(...collectSkillCommands(entry.commands, path7, groups));
138214
+ groups.set(path6.join(" "), entry.description);
138215
+ result.push(...collectSkillCommands(entry.commands, path6, groups));
138216
138216
  } else {
138217
- const cmd = { name: path7.join(" ") };
138217
+ const cmd = { name: path6.join(" ") };
138218
138218
  if (entry.description)
138219
138219
  cmd.description = entry.description;
138220
138220
  if (entry.args)
@@ -138229,7 +138229,7 @@ function collectSkillCommands(commands, prefix, groups) {
138229
138229
  cmd.output = entry.output;
138230
138230
  const examples = formatExamples(entry.examples);
138231
138231
  if (examples) {
138232
- const cmdName = path7.join(" ");
138232
+ const cmdName = path6.join(" ");
138233
138233
  cmd.examples = examples.map((e) => ({
138234
138234
  ...e,
138235
138235
  command: e.command ? `${cmdName} ${e.command}` : cmdName
@@ -138273,7 +138273,7 @@ function buildInputSchema(args2, env2, options2) {
138273
138273
  // package.json
138274
138274
  var package_default = {
138275
138275
  name: "@docyrus/docyrus",
138276
- version: "0.0.43",
138276
+ version: "0.0.45",
138277
138277
  private: false,
138278
138278
  description: "Docyrus API CLI",
138279
138279
  main: "./main.js",
@@ -138731,7 +138731,7 @@ function createConnectCli(dependencies) {
138731
138731
  const apiClient = dependencies.createApiClient(apiBaseUrl);
138732
138732
  const { appSlug, actionKey } = context.args;
138733
138733
  const body2 = context.options.params ? parseJsonParams(context.options.params) : {};
138734
- const path7 = `/v1/apps/${encodeURIComponent(appSlug)}/actions/${encodeURIComponent(actionKey)}/run`;
138734
+ const path6 = `/v1/apps/${encodeURIComponent(appSlug)}/actions/${encodeURIComponent(actionKey)}/run`;
138735
138735
  const headers = {};
138736
138736
  if (context.options.connectionId) {
138737
138737
  headers["x-connection-id"] = context.options.connectionId;
@@ -138746,7 +138746,7 @@ function createConnectCli(dependencies) {
138746
138746
  payload: {
138747
138747
  dryRun: true,
138748
138748
  method: "POST",
138749
- path: path7,
138749
+ path: path6,
138750
138750
  headers: Object.keys(headers).length > 0 ? headers : void 0,
138751
138751
  body: body2
138752
138752
  }
@@ -138754,7 +138754,7 @@ function createConnectCli(dependencies) {
138754
138754
  }
138755
138755
  const response = await apiClient.request({
138756
138756
  method: "POST",
138757
- path: path7,
138757
+ path: path6,
138758
138758
  headers: Object.keys(headers).length > 0 ? headers : void 0,
138759
138759
  body: body2
138760
138760
  });
@@ -138918,10 +138918,10 @@ function createAiCli(dependencies) {
138918
138918
  const deploymentId = context.options.deploymentId?.trim() || void 0;
138919
138919
  const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
138920
138920
  const apiClient = dependencies.createApiClient(apiBaseUrl);
138921
- const path7 = deploymentId ? `/ai/agents/${agentId}/deployments/${deploymentId}/chat` : `/ai/agents/${agentId}/chat`;
138921
+ const path6 = deploymentId ? `/ai/agents/${agentId}/deployments/${deploymentId}/chat` : `/ai/agents/${agentId}/chat`;
138922
138922
  const response = await apiClient.request({
138923
138923
  method: "POST",
138924
- path: path7,
138924
+ path: path6,
138925
138925
  body: {
138926
138926
  messages: [
138927
138927
  {
@@ -139901,7 +139901,7 @@ async function readDataInput(params) {
139901
139901
  data,
139902
139902
  fromFile,
139903
139903
  readStdin: readStdin2 = readStdinText,
139904
- readFileFn = async (path7, encoding) => await (0, import_promises2.readFile)(path7, encoding)
139904
+ readFileFn = async (path6, encoding) => await (0, import_promises2.readFile)(path6, encoding)
139905
139905
  } = params;
139906
139906
  const trimmedData = data?.trim();
139907
139907
  const trimmedFromFile = fromFile?.trim();
@@ -140598,8 +140598,8 @@ function getEntities(document4) {
140598
140598
  }
140599
140599
  function extractNamespaces(paths) {
140600
140600
  const namespaces = /* @__PURE__ */ new Set();
140601
- for (const path7 of Object.keys(paths)) {
140602
- const segments = path7.split("/").map((item) => item.trim()).filter((item) => item.length > 0);
140601
+ for (const path6 of Object.keys(paths)) {
140602
+ const segments = path6.split("/").map((item) => item.trim()).filter((item) => item.length > 0);
140603
140603
  if (segments.length === 0) {
140604
140604
  continue;
140605
140605
  }
@@ -140621,8 +140621,8 @@ function getPathOperation(pathItem, method) {
140621
140621
  function toEndpointMethodEntries(paths, pathFilter) {
140622
140622
  const entries = [];
140623
140623
  const sortedPaths = Object.keys(paths).filter(pathFilter).sort((left, right) => left.localeCompare(right));
140624
- for (const path7 of sortedPaths) {
140625
- const pathItem = paths[path7];
140624
+ for (const path6 of sortedPaths) {
140625
+ const pathItem = paths[path6];
140626
140626
  if (!isRecord2(pathItem)) {
140627
140627
  continue;
140628
140628
  }
@@ -140635,7 +140635,7 @@ function toEndpointMethodEntries(paths, pathFilter) {
140635
140635
  const summaryValue = operation.summary;
140636
140636
  const description = typeof descriptionValue === "string" ? descriptionValue : typeof summaryValue === "string" ? summaryValue : void 0;
140637
140637
  entries.push({
140638
- path: toOutputPath(path7),
140638
+ path: toOutputPath(path6),
140639
140639
  method,
140640
140640
  description
140641
140641
  });
@@ -140761,7 +140761,7 @@ function createDiscoverCli(dependencies) {
140761
140761
  const candidates = buildPathCandidates(context.args.prefix);
140762
140762
  const endpoints = toEndpointMethodEntries(
140763
140763
  paths,
140764
- (path7) => candidates.some((candidate) => path7.startsWith(candidate))
140764
+ (path6) => candidates.some((candidate) => path6.startsWith(candidate))
140765
140765
  );
140766
140766
  return await injectContext({
140767
140767
  apiBaseUrl,
@@ -140858,7 +140858,7 @@ function createDiscoverCli(dependencies) {
140858
140858
  const loweredTerm = term.toLowerCase();
140859
140859
  const matchingEndpoints = toEndpointMethodEntries(
140860
140860
  pathMap,
140861
- (path7) => path7.toLowerCase().includes(loweredTerm)
140861
+ (path6) => path6.toLowerCase().includes(loweredTerm)
140862
140862
  );
140863
140863
  const matchingEntities = entityNames.filter((entityName) => entityName.toLowerCase().includes(loweredTerm));
140864
140864
  return {
@@ -143227,11 +143227,11 @@ var Module2 = (() => {
143227
143227
  throw toThrow;
143228
143228
  }, "quit_");
143229
143229
  var scriptDirectory = "";
143230
- function locateFile(path7) {
143230
+ function locateFile(path6) {
143231
143231
  if (Module["locateFile"]) {
143232
- return Module["locateFile"](path7, scriptDirectory);
143232
+ return Module["locateFile"](path6, scriptDirectory);
143233
143233
  }
143234
- return scriptDirectory + path7;
143234
+ return scriptDirectory + path6;
143235
143235
  }
143236
143236
  __name(locateFile, "locateFile");
143237
143237
  var readAsync, readBinary;
@@ -146388,6 +146388,23 @@ function normalizeDeploymentName(params) {
146388
146388
  return params.defaultModel;
146389
146389
  }
146390
146390
  async function resolveKnowledgeProviderFromAgentRuntime(params) {
146391
+ if (params.docyrusApi) {
146392
+ const { apiBaseUrl, accessToken } = params.docyrusApi;
146393
+ const gatewayBase = apiBaseUrl.replace(/\/+$/u, "") + "/ai/gateway";
146394
+ return {
146395
+ provider: {
146396
+ providerId: "docyrus-api",
146397
+ apiBase: gatewayBase,
146398
+ model: DEFAULT_EMBEDDING_MODEL,
146399
+ dimensions: DEFAULT_DIMENSIONS,
146400
+ key: accessToken,
146401
+ headers: (key) => ({
146402
+ Authorization: `Bearer ${key}`,
146403
+ "Content-Type": "application/json"
146404
+ })
146405
+ }
146406
+ };
146407
+ }
146391
146408
  const agentRootPath = resolveDocyrusPiAgentRootPath(params.settingsRootPath);
146392
146409
  const authState = readJsonFile((0, import_node_path14.join)(agentRootPath, "auth.json")) || {};
146393
146410
  const envStore = new AgentEnvStore((0, import_node_path14.join)(agentRootPath, "env.json"));
@@ -146704,9 +146721,9 @@ function shouldUseKnowledgeColors() {
146704
146721
  }
146705
146722
 
146706
146723
  // src/knowledge/init.ts
146707
- var import_node_fs10 = require("node:fs");
146708
- var import_promises14 = require("node:fs/promises");
146709
- var import_node_path18 = require("node:path");
146724
+ var import_node_fs8 = require("node:fs");
146725
+ var import_promises12 = require("node:fs/promises");
146726
+ var import_node_path16 = require("node:path");
146710
146727
  init_graph();
146711
146728
 
146712
146729
  // src/knowledge/bootstrap.ts
@@ -147118,754 +147135,6 @@ async function generateInitialKnowledge(params) {
147118
147135
  };
147119
147136
  }
147120
147137
 
147121
- // src/project-plan/graph.ts
147122
- var import_node_crypto5 = require("node:crypto");
147123
- var import_node_fs9 = require("node:fs");
147124
- var import_promises13 = __toESM(require("node:fs/promises"));
147125
- var import_node_path17 = __toESM(require("node:path"));
147126
- init_graph();
147127
-
147128
- // src/project-plan/localTodos.ts
147129
- var import_node_crypto4 = __toESM(require("node:crypto"));
147130
- var import_node_fs8 = require("node:fs");
147131
- var import_promises12 = __toESM(require("node:fs/promises"));
147132
- var import_node_path16 = __toESM(require("node:path"));
147133
- var TODO_DIR_NAME = ".pi/todos";
147134
- var TODO_PATH_ENV = "PI_TODO_PATH";
147135
- function resolveTodosDirectory(root) {
147136
- const overridePath = process.env[TODO_PATH_ENV]?.trim();
147137
- if (overridePath) {
147138
- return import_node_path16.default.resolve(root, overridePath);
147139
- }
147140
- return import_node_path16.default.resolve(root, TODO_DIR_NAME);
147141
- }
147142
- function getTodoFilePath(todosDir, id) {
147143
- return import_node_path16.default.join(todosDir, `${id}.md`);
147144
- }
147145
- function splitFrontMatter(content3) {
147146
- if (!content3.startsWith("{")) {
147147
- return {
147148
- frontMatter: "",
147149
- body: content3
147150
- };
147151
- }
147152
- let depth = 0;
147153
- let inString = false;
147154
- let escaped = false;
147155
- let endIndex = -1;
147156
- for (let index2 = 0; index2 < content3.length; index2 += 1) {
147157
- const char = content3[index2];
147158
- if (inString) {
147159
- if (escaped) {
147160
- escaped = false;
147161
- continue;
147162
- }
147163
- if (char === "\\") {
147164
- escaped = true;
147165
- continue;
147166
- }
147167
- if (char === '"') {
147168
- inString = false;
147169
- }
147170
- continue;
147171
- }
147172
- if (char === '"') {
147173
- inString = true;
147174
- continue;
147175
- }
147176
- if (char === "{") {
147177
- depth += 1;
147178
- continue;
147179
- }
147180
- if (char === "}") {
147181
- depth -= 1;
147182
- if (depth === 0) {
147183
- endIndex = index2;
147184
- break;
147185
- }
147186
- }
147187
- }
147188
- if (endIndex === -1) {
147189
- return {
147190
- frontMatter: "",
147191
- body: content3
147192
- };
147193
- }
147194
- return {
147195
- frontMatter: content3.slice(0, endIndex + 1),
147196
- body: content3.slice(endIndex + 1).replace(/^\r?\n+/u, "")
147197
- };
147198
- }
147199
- function parseLocalTodoFrontMatter(frontMatter, idFallback) {
147200
- const base = {
147201
- id: idFallback,
147202
- title: "",
147203
- tags: [],
147204
- status: "open",
147205
- created_at: ""
147206
- };
147207
- if (!frontMatter.trim()) {
147208
- return base;
147209
- }
147210
- try {
147211
- const parsed = JSON.parse(frontMatter);
147212
- return {
147213
- id: typeof parsed.id === "string" && parsed.id.trim() ? parsed.id.trim() : idFallback,
147214
- title: typeof parsed.title === "string" ? parsed.title : "",
147215
- tags: Array.isArray(parsed.tags) ? parsed.tags.filter((value2) => typeof value2 === "string") : [],
147216
- status: typeof parsed.status === "string" && parsed.status.trim() ? parsed.status.trim() : "open",
147217
- created_at: typeof parsed.created_at === "string" ? parsed.created_at : "",
147218
- assigned_to_session: typeof parsed.assigned_to_session === "string" && parsed.assigned_to_session.trim() ? parsed.assigned_to_session.trim() : void 0,
147219
- parent_task_id: typeof parsed.parent_task_id === "string" && parsed.parent_task_id.trim() ? parsed.parent_task_id.trim() : void 0
147220
- };
147221
- } catch {
147222
- return base;
147223
- }
147224
- }
147225
- function serializeLocalTodo(record2) {
147226
- const frontMatter = JSON.stringify(
147227
- {
147228
- id: record2.id,
147229
- title: record2.title,
147230
- tags: record2.tags,
147231
- status: record2.status,
147232
- created_at: record2.created_at,
147233
- assigned_to_session: record2.assigned_to_session || void 0,
147234
- parent_task_id: record2.parent_task_id || void 0
147235
- },
147236
- null,
147237
- 2
147238
- );
147239
- const trimmedBody = record2.body.trim();
147240
- return trimmedBody ? `${frontMatter}
147241
-
147242
- ${trimmedBody}
147243
- ` : `${frontMatter}
147244
- `;
147245
- }
147246
- async function generateTodoId(todosDir) {
147247
- for (let attempt = 0; attempt < 10; attempt += 1) {
147248
- const id = import_node_crypto4.default.randomBytes(4).toString("hex");
147249
- if (!(0, import_node_fs8.existsSync)(getTodoFilePath(todosDir, id))) {
147250
- return id;
147251
- }
147252
- }
147253
- throw new Error("Failed to generate linked todo id.");
147254
- }
147255
- async function listLinkedTodosByTask(root) {
147256
- const todosDir = resolveTodosDirectory(root);
147257
- const result = /* @__PURE__ */ new Map();
147258
- let entries = [];
147259
- try {
147260
- entries = await import_promises12.default.readdir(todosDir);
147261
- } catch {
147262
- return result;
147263
- }
147264
- for (const entry of entries) {
147265
- if (!entry.endsWith(".md")) {
147266
- continue;
147267
- }
147268
- const id = entry.slice(0, -3);
147269
- const filePath = getTodoFilePath(todosDir, id);
147270
- try {
147271
- const raw = await import_promises12.default.readFile(filePath, "utf8");
147272
- const { frontMatter } = splitFrontMatter(raw);
147273
- const parsed = parseLocalTodoFrontMatter(frontMatter, id);
147274
- if (!parsed.parent_task_id) {
147275
- continue;
147276
- }
147277
- const existing = result.get(parsed.parent_task_id) || [];
147278
- existing.push({
147279
- id,
147280
- title: parsed.title,
147281
- status: parsed.status,
147282
- filePath: import_node_path16.default.relative(root, filePath),
147283
- parentTaskId: parsed.parent_task_id
147284
- });
147285
- result.set(parsed.parent_task_id, existing);
147286
- } catch {
147287
- }
147288
- }
147289
- for (const linkedTodos of result.values()) {
147290
- linkedTodos.sort((left, right) => left.title.localeCompare(right.title) || left.id.localeCompare(right.id));
147291
- }
147292
- return result;
147293
- }
147294
- async function createLinkedTodo(params) {
147295
- const todosDir = resolveTodosDirectory(params.root);
147296
- await import_promises12.default.mkdir(todosDir, {
147297
- recursive: true
147298
- });
147299
- const id = await generateTodoId(todosDir);
147300
- const filePath = getTodoFilePath(todosDir, id);
147301
- const todo = {
147302
- id,
147303
- title: params.title,
147304
- tags: [],
147305
- status: "open",
147306
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
147307
- parent_task_id: params.parentTaskId,
147308
- body: params.body ?? ""
147309
- };
147310
- await import_promises12.default.writeFile(filePath, serializeLocalTodo(todo), "utf8");
147311
- return {
147312
- id,
147313
- title: todo.title,
147314
- status: todo.status,
147315
- filePath: import_node_path16.default.relative(params.root, filePath),
147316
- parentTaskId: params.parentTaskId
147317
- };
147318
- }
147319
-
147320
- // src/project-plan/types.ts
147321
- var PROJECT_TASK_TYPES = [
147322
- "bug-fix",
147323
- "new-implementation",
147324
- "api-test",
147325
- "browser-automation-test",
147326
- "work"
147327
- ];
147328
- var PROJECT_TASK_ASSIGNEES = [
147329
- "agent",
147330
- "user"
147331
- ];
147332
- var PROJECT_TASK_STATUSES = [
147333
- "planned",
147334
- "in_progress",
147335
- "blocked",
147336
- "done"
147337
- ];
147338
-
147339
- // src/project-plan/graph.ts
147340
- var PROJECT_PLAN_DIR_SEGMENTS = ["docyrus", "project-plan"];
147341
- var PROJECT_PLAN_JSON_FILE_NAME = "project-plan.json";
147342
- var PROJECT_PLAN_MARKDOWN_FILE_NAME = "PROJECT_PLAN.md";
147343
- var DEFAULT_ROUTE_TARGETS = {
147344
- features: {
147345
- heading: "Features",
147346
- filePathSuffix: "docyrus/knowledge/features/features.md"
147347
- },
147348
- testing: {
147349
- heading: "Testing",
147350
- filePathSuffix: "docyrus/knowledge/testing/testing.md"
147351
- },
147352
- architecture: {
147353
- heading: "Architecture",
147354
- filePathSuffix: "docyrus/knowledge/architecture/architecture.md"
147355
- },
147356
- workflows: {
147357
- heading: "Workflows",
147358
- filePathSuffix: "docyrus/knowledge/workflows/workflows.md"
147359
- }
147360
- };
147361
- function isRecord3(value2) {
147362
- return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
147363
- }
147364
- function isNonEmptyString(value2) {
147365
- return typeof value2 === "string" && value2.trim().length > 0;
147366
- }
147367
- function normalizeStringArray(value2) {
147368
- if (!Array.isArray(value2)) {
147369
- return [];
147370
- }
147371
- return value2.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
147372
- }
147373
- function slugify2(value2) {
147374
- const slug = value2.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 80);
147375
- return slug || "item";
147376
- }
147377
- function hashParts(parts2) {
147378
- return (0, import_node_crypto5.createHash)("sha1").update(parts2.join("::")).digest("hex").slice(0, 12);
147379
- }
147380
- function normalizeFeatureId(sectionId, slug) {
147381
- return `feature-${hashParts([sectionId, slug])}`;
147382
- }
147383
- function normalizeTaskId(featureId, type, title) {
147384
- return `task-${hashParts([featureId, type, slugify2(title)])}`;
147385
- }
147386
- function compareStrings(left, right) {
147387
- return left.localeCompare(right);
147388
- }
147389
- function sortGraph(graph) {
147390
- return {
147391
- version: 1,
147392
- sections: [...graph.sections].sort((left, right) => compareStrings(left.sectionId, right.sectionId)),
147393
- features: [...graph.features].sort((left, right) => {
147394
- return compareStrings(left.sectionId, right.sectionId) || compareStrings(left.title, right.title) || compareStrings(left.id, right.id);
147395
- }),
147396
- tasks: [...graph.tasks].sort((left, right) => {
147397
- return compareStrings(left.sectionId, right.sectionId) || compareStrings(left.featureId, right.featureId) || compareStrings(left.title, right.title) || compareStrings(left.id, right.id);
147398
- })
147399
- };
147400
- }
147401
- function resolveProjectPlanDirectory(root) {
147402
- return import_node_path17.default.join(root, ...PROJECT_PLAN_DIR_SEGMENTS);
147403
- }
147404
- function resolveProjectPlanGraphPath(root) {
147405
- return import_node_path17.default.join(resolveProjectPlanDirectory(root), PROJECT_PLAN_JSON_FILE_NAME);
147406
- }
147407
- function resolveProjectPlanMarkdownPath(root) {
147408
- return import_node_path17.default.join(resolveProjectPlanDirectory(root), PROJECT_PLAN_MARKDOWN_FILE_NAME);
147409
- }
147410
- function createEmptyProjectPlanGraph() {
147411
- return {
147412
- version: 1,
147413
- sections: [],
147414
- features: [],
147415
- tasks: []
147416
- };
147417
- }
147418
- async function readKnowledgeSections(root) {
147419
- const knowledgeDir = import_node_path17.default.join(root, "docyrus", "knowledge");
147420
- if (!(0, import_node_fs9.existsSync)(knowledgeDir)) {
147421
- return [];
147422
- }
147423
- return flattenSections(await loadAllSections(knowledgeDir));
147424
- }
147425
- function parseProjectPlanGraph(rawValue) {
147426
- if (!isRecord3(rawValue)) {
147427
- return createEmptyProjectPlanGraph();
147428
- }
147429
- const sections = Array.isArray(rawValue.sections) ? rawValue.sections.filter((value2) => isRecord3(value2)).map((value2) => ({
147430
- sectionId: isNonEmptyString(value2.sectionId) ? value2.sectionId.trim() : ""
147431
- })).filter((value2) => value2.sectionId.length > 0) : [];
147432
- const features = Array.isArray(rawValue.features) ? rawValue.features.filter((value2) => isRecord3(value2)).map((value2) => ({
147433
- id: isNonEmptyString(value2.id) ? value2.id.trim() : "",
147434
- title: isNonEmptyString(value2.title) ? value2.title.trim() : "",
147435
- slug: isNonEmptyString(value2.slug) ? value2.slug.trim() : "",
147436
- summary: typeof value2.summary === "string" ? value2.summary.trim() : "",
147437
- sectionId: isNonEmptyString(value2.sectionId) ? value2.sectionId.trim() : ""
147438
- })).filter((value2) => value2.id.length > 0) : [];
147439
- const tasks = Array.isArray(rawValue.tasks) ? rawValue.tasks.filter((value2) => isRecord3(value2)).map((value2) => ({
147440
- id: isNonEmptyString(value2.id) ? value2.id.trim() : "",
147441
- title: isNonEmptyString(value2.title) ? value2.title.trim() : "",
147442
- summary: typeof value2.summary === "string" ? value2.summary.trim() : "",
147443
- type: typeof value2.type === "string" ? value2.type : "work",
147444
- assignee: typeof value2.assignee === "string" ? value2.assignee : "agent",
147445
- status: typeof value2.status === "string" ? value2.status : "planned",
147446
- acceptanceCriteria: normalizeStringArray(value2.acceptanceCriteria),
147447
- featureId: isNonEmptyString(value2.featureId) ? value2.featureId.trim() : "",
147448
- sectionId: isNonEmptyString(value2.sectionId) ? value2.sectionId.trim() : ""
147449
- })).filter((value2) => value2.id.length > 0) : [];
147450
- return sortGraph({
147451
- version: 1,
147452
- sections,
147453
- features,
147454
- tasks
147455
- });
147456
- }
147457
- async function readProjectPlanGraph(root) {
147458
- const graphPath = resolveProjectPlanGraphPath(root);
147459
- if (!(0, import_node_fs9.existsSync)(graphPath)) {
147460
- return createEmptyProjectPlanGraph();
147461
- }
147462
- const raw = await import_promises13.default.readFile(graphPath, "utf8");
147463
- return parseProjectPlanGraph(JSON.parse(raw));
147464
- }
147465
- function deriveFeatureStatus(tasks) {
147466
- if (tasks.length === 0) {
147467
- return "planned";
147468
- }
147469
- if (tasks.every((task) => task.status === "done")) {
147470
- return "done";
147471
- }
147472
- if (tasks.some((task) => task.status === "in_progress")) {
147473
- return "in_progress";
147474
- }
147475
- if (tasks.some((task) => task.status === "blocked")) {
147476
- return "blocked";
147477
- }
147478
- return "planned";
147479
- }
147480
- function deriveSectionStatus(features) {
147481
- if (features.length === 0) {
147482
- return "planned";
147483
- }
147484
- if (features.every((feature) => feature.status === "done")) {
147485
- return "done";
147486
- }
147487
- if (features.some((feature) => feature.status === "in_progress")) {
147488
- return "in_progress";
147489
- }
147490
- if (features.some((feature) => feature.status === "blocked")) {
147491
- return "blocked";
147492
- }
147493
- return "planned";
147494
- }
147495
- function findKnowledgeSectionTitle(knowledgeSections, sectionId) {
147496
- const section2 = knowledgeSections.find((item) => item.id === sectionId);
147497
- if (!section2) {
147498
- return {
147499
- heading: sectionId,
147500
- filePath: ""
147501
- };
147502
- }
147503
- return {
147504
- heading: section2.heading,
147505
- filePath: section2.filePath
147506
- };
147507
- }
147508
- async function buildProjectPlanHierarchy(root, graph) {
147509
- const knowledgeSections = await readKnowledgeSections(root);
147510
- const currentGraph = graph ?? await readProjectPlanGraph(root);
147511
- const linkedTodos = await listLinkedTodosByTask(root);
147512
- const featureMap = /* @__PURE__ */ new Map();
147513
- for (const feature of currentGraph.features) {
147514
- const featureTasks = currentGraph.tasks.filter((task) => task.featureId === feature.id).map((task) => {
147515
- const taskLinkedTodos = linkedTodos.get(task.id) || [];
147516
- return {
147517
- ...task,
147518
- linkedTodos: taskLinkedTodos,
147519
- linkedTodoCount: taskLinkedTodos.length
147520
- };
147521
- });
147522
- featureMap.set(feature.id, {
147523
- ...feature,
147524
- status: deriveFeatureStatus(featureTasks),
147525
- taskCount: featureTasks.length,
147526
- tasks: featureTasks
147527
- });
147528
- }
147529
- const sections = currentGraph.sections.map((section2) => {
147530
- const features = currentGraph.features.filter((feature) => feature.sectionId === section2.sectionId).map((feature) => featureMap.get(feature.id)).filter((feature) => Boolean(feature));
147531
- const knowledgeMetadata = findKnowledgeSectionTitle(knowledgeSections, section2.sectionId);
147532
- const taskCount = features.reduce((count, feature) => count + feature.taskCount, 0);
147533
- return {
147534
- sectionId: section2.sectionId,
147535
- heading: knowledgeMetadata.heading,
147536
- filePath: knowledgeMetadata.filePath,
147537
- status: deriveSectionStatus(features),
147538
- featureCount: features.length,
147539
- taskCount,
147540
- features
147541
- };
147542
- });
147543
- return {
147544
- sections
147545
- };
147546
- }
147547
- function formatAcceptanceCriteria(criteria) {
147548
- if (criteria.length === 0) {
147549
- return ["- None yet"];
147550
- }
147551
- return criteria.map((item) => `- ${item}`);
147552
- }
147553
- async function renderProjectPlanMarkdown(root, graph) {
147554
- const hierarchy = await buildProjectPlanHierarchy(root, graph);
147555
- const lines = [
147556
- "# Project Plan",
147557
- "",
147558
- "This file is derived from `docyrus/project-plan/project-plan.json`.",
147559
- ""
147560
- ];
147561
- const populatedSections = hierarchy.sections.filter((section2) => section2.features.length > 0);
147562
- if (populatedSections.length === 0) {
147563
- lines.push("No planned features or tasks yet.");
147564
- lines.push("");
147565
- return `${lines.join("\n")}`;
147566
- }
147567
- for (const section2 of populatedSections) {
147568
- lines.push(`## ${section2.heading}`);
147569
- lines.push("");
147570
- lines.push(`- Section ID: \`${section2.sectionId}\``);
147571
- lines.push(`- Status: \`${section2.status}\``);
147572
- lines.push(`- Features: ${section2.featureCount}`);
147573
- lines.push(`- Tasks: ${section2.taskCount}`);
147574
- lines.push("");
147575
- for (const feature of section2.features) {
147576
- lines.push(`### ${feature.title}`);
147577
- lines.push("");
147578
- lines.push(`- Feature ID: \`${feature.id}\``);
147579
- lines.push(`- Status: \`${feature.status}\``);
147580
- lines.push(`- Slug: \`${feature.slug}\``);
147581
- if (feature.summary) {
147582
- lines.push(`- Summary: ${feature.summary}`);
147583
- }
147584
- lines.push("");
147585
- for (const task of feature.tasks) {
147586
- lines.push(`#### ${task.title}`);
147587
- lines.push("");
147588
- lines.push(`- Task ID: \`${task.id}\``);
147589
- lines.push(`- Type: \`${task.type}\``);
147590
- lines.push(`- Assignee: \`${task.assignee}\``);
147591
- lines.push(`- Status: \`${task.status}\``);
147592
- if (task.summary) {
147593
- lines.push(`- Summary: ${task.summary}`);
147594
- }
147595
- lines.push("- Acceptance Criteria:");
147596
- lines.push(...formatAcceptanceCriteria(task.acceptanceCriteria));
147597
- lines.push("");
147598
- }
147599
- }
147600
- }
147601
- return `${lines.join("\n").trimEnd()}
147602
- `;
147603
- }
147604
- async function writeProjectPlanFiles(root, graph) {
147605
- const graphPath = resolveProjectPlanGraphPath(root);
147606
- const markdownPath = resolveProjectPlanMarkdownPath(root);
147607
- await import_promises13.default.mkdir(import_node_path17.default.dirname(graphPath), {
147608
- recursive: true
147609
- });
147610
- const sortedGraph = sortGraph(graph);
147611
- await import_promises13.default.writeFile(graphPath, `${JSON.stringify(sortedGraph, null, 2)}
147612
- `, "utf8");
147613
- await import_promises13.default.writeFile(markdownPath, await renderProjectPlanMarkdown(root, sortedGraph), "utf8");
147614
- return {
147615
- graph: sortedGraph,
147616
- graphPath,
147617
- markdownPath
147618
- };
147619
- }
147620
- function buildProjectPlanCheckError(code, message, target) {
147621
- return {
147622
- code,
147623
- message,
147624
- target
147625
- };
147626
- }
147627
- async function validateProjectPlanGraph(root, graph) {
147628
- const currentGraph = graph ?? await readProjectPlanGraph(root);
147629
- const errors = [];
147630
- const knowledgeSections = await readKnowledgeSections(root);
147631
- const knowledgeSectionIds = new Set(knowledgeSections.map((section2) => section2.id));
147632
- const sectionIds = /* @__PURE__ */ new Set();
147633
- const featureIds = /* @__PURE__ */ new Set();
147634
- const featureMap = /* @__PURE__ */ new Map();
147635
- for (const section2 of currentGraph.sections) {
147636
- if (!section2.sectionId) {
147637
- errors.push(buildProjectPlanCheckError("section_missing_id", "Project plan section is missing `sectionId`."));
147638
- continue;
147639
- }
147640
- if (sectionIds.has(section2.sectionId)) {
147641
- errors.push(buildProjectPlanCheckError("duplicate_section", `Duplicate section id "${section2.sectionId}"`, section2.sectionId));
147642
- continue;
147643
- }
147644
- sectionIds.add(section2.sectionId);
147645
- if (!knowledgeSectionIds.has(section2.sectionId)) {
147646
- errors.push(buildProjectPlanCheckError(
147647
- "unknown_knowledge_section",
147648
- `Project plan section "${section2.sectionId}" does not exist in docyrus/knowledge.`,
147649
- section2.sectionId
147650
- ));
147651
- }
147652
- }
147653
- const allowedTypes = new Set(PROJECT_TASK_TYPES);
147654
- const allowedAssignees = new Set(PROJECT_TASK_ASSIGNEES);
147655
- const allowedStatuses = new Set(PROJECT_TASK_STATUSES);
147656
- for (const feature of currentGraph.features) {
147657
- if (!feature.id) {
147658
- errors.push(buildProjectPlanCheckError("feature_missing_id", "Project plan feature is missing `id`."));
147659
- continue;
147660
- }
147661
- if (featureIds.has(feature.id)) {
147662
- errors.push(buildProjectPlanCheckError("duplicate_feature", `Duplicate feature id "${feature.id}"`, feature.id));
147663
- continue;
147664
- }
147665
- featureIds.add(feature.id);
147666
- featureMap.set(feature.id, feature);
147667
- if (!feature.sectionId) {
147668
- errors.push(buildProjectPlanCheckError("feature_missing_section", `Feature "${feature.id}" is missing \`sectionId\`.`, feature.id));
147669
- continue;
147670
- }
147671
- if (!sectionIds.has(feature.sectionId)) {
147672
- errors.push(buildProjectPlanCheckError(
147673
- "feature_unknown_section",
147674
- `Feature "${feature.id}" references unknown section "${feature.sectionId}".`,
147675
- feature.id
147676
- ));
147677
- }
147678
- if (!feature.title.trim()) {
147679
- errors.push(buildProjectPlanCheckError("feature_missing_title", `Feature "${feature.id}" is missing a title.`, feature.id));
147680
- }
147681
- if (!feature.slug.trim()) {
147682
- errors.push(buildProjectPlanCheckError("feature_missing_slug", `Feature "${feature.id}" is missing a slug.`, feature.id));
147683
- }
147684
- }
147685
- const taskIds = /* @__PURE__ */ new Set();
147686
- for (const task of currentGraph.tasks) {
147687
- if (!task.id) {
147688
- errors.push(buildProjectPlanCheckError("task_missing_id", "Project plan task is missing `id`."));
147689
- continue;
147690
- }
147691
- if (taskIds.has(task.id)) {
147692
- errors.push(buildProjectPlanCheckError("duplicate_task", `Duplicate task id "${task.id}"`, task.id));
147693
- continue;
147694
- }
147695
- taskIds.add(task.id);
147696
- const feature = featureMap.get(task.featureId);
147697
- if (!feature) {
147698
- errors.push(buildProjectPlanCheckError(
147699
- "task_unknown_feature",
147700
- `Task "${task.id}" references unknown feature "${task.featureId}".`,
147701
- task.id
147702
- ));
147703
- continue;
147704
- }
147705
- if (!task.title.trim()) {
147706
- errors.push(buildProjectPlanCheckError("task_missing_title", `Task "${task.id}" is missing a title.`, task.id));
147707
- }
147708
- if (!allowedTypes.has(task.type)) {
147709
- errors.push(buildProjectPlanCheckError(
147710
- "task_invalid_type",
147711
- `Task "${task.id}" has invalid type "${task.type}".`,
147712
- task.id
147713
- ));
147714
- }
147715
- if (!allowedAssignees.has(task.assignee)) {
147716
- errors.push(buildProjectPlanCheckError(
147717
- "task_invalid_assignee",
147718
- `Task "${task.id}" has invalid assignee "${task.assignee}".`,
147719
- task.id
147720
- ));
147721
- }
147722
- if (!allowedStatuses.has(task.status)) {
147723
- errors.push(buildProjectPlanCheckError(
147724
- "task_invalid_status",
147725
- `Task "${task.id}" has invalid status "${task.status}".`,
147726
- task.id
147727
- ));
147728
- }
147729
- if (!sectionIds.has(task.sectionId)) {
147730
- errors.push(buildProjectPlanCheckError(
147731
- "task_unknown_section",
147732
- `Task "${task.id}" references unknown section "${task.sectionId}".`,
147733
- task.id
147734
- ));
147735
- }
147736
- if (task.sectionId !== feature.sectionId) {
147737
- errors.push(buildProjectPlanCheckError(
147738
- "task_section_mismatch",
147739
- `Task "${task.id}" section "${task.sectionId}" does not match feature "${feature.id}" section "${feature.sectionId}".`,
147740
- task.id
147741
- ));
147742
- }
147743
- }
147744
- return {
147745
- ok: errors.length === 0,
147746
- errors
147747
- };
147748
- }
147749
- async function resolveKnowledgeSectionIds(root) {
147750
- const sections = await readKnowledgeSections(root);
147751
- return sections.map((section2) => section2.id).sort(compareStrings);
147752
- }
147753
- async function syncProjectPlanSectionsFromKnowledge(root) {
147754
- const currentGraph = await readProjectPlanGraph(root);
147755
- const knowledgeSectionIds = await resolveKnowledgeSectionIds(root);
147756
- const syncedGraph = {
147757
- ...currentGraph,
147758
- sections: knowledgeSectionIds.map((sectionId) => ({
147759
- sectionId
147760
- }))
147761
- };
147762
- return writeProjectPlanFiles(root, syncedGraph);
147763
- }
147764
- async function ensureProjectPlanGraph(root) {
147765
- const graphPath = resolveProjectPlanGraphPath(root);
147766
- if (!(0, import_node_fs9.existsSync)(graphPath)) {
147767
- return syncProjectPlanSectionsFromKnowledge(root);
147768
- }
147769
- const graph = await readProjectPlanGraph(root);
147770
- return writeProjectPlanFiles(root, graph);
147771
- }
147772
- async function upsertProjectPlanFeature(params) {
147773
- const state = await ensureProjectPlanGraph(params.root);
147774
- const slug = slugify2(params.slug?.trim() || params.title);
147775
- const featureId = params.featureId?.trim() || normalizeFeatureId(params.sectionId, slug);
147776
- const graph = state.graph;
147777
- const existing = graph.features.find((feature) => feature.id === featureId) || graph.features.find((feature) => feature.sectionId === params.sectionId && feature.slug === slug);
147778
- const nextFeature = {
147779
- id: existing?.id || featureId,
147780
- title: params.title.trim(),
147781
- slug,
147782
- summary: params.summary?.trim() || "",
147783
- sectionId: params.sectionId
147784
- };
147785
- const nextFeatures = existing ? graph.features.map((feature) => feature.id === existing.id ? nextFeature : feature) : [...graph.features, nextFeature];
147786
- await writeProjectPlanFiles(params.root, {
147787
- ...graph,
147788
- features: nextFeatures
147789
- });
147790
- return nextFeature;
147791
- }
147792
- async function getProjectPlanTask(params) {
147793
- const graph = await readProjectPlanGraph(params.root);
147794
- const linkedTodos = await listLinkedTodosByTask(params.root);
147795
- const task = graph.tasks.find((item) => item.id === params.taskId);
147796
- if (!task) {
147797
- return null;
147798
- }
147799
- const taskLinkedTodos = linkedTodos.get(task.id) || [];
147800
- return {
147801
- ...task,
147802
- linkedTodos: taskLinkedTodos,
147803
- linkedTodoCount: taskLinkedTodos.length
147804
- };
147805
- }
147806
- async function upsertProjectPlanTask(params) {
147807
- const state = await ensureProjectPlanGraph(params.root);
147808
- const graph = state.graph;
147809
- const feature = graph.features.find((item) => item.id === params.featureId);
147810
- if (!feature) {
147811
- throw new Error(`Feature "${params.featureId}" not found.`);
147812
- }
147813
- const sectionId = params.sectionId?.trim() || feature.sectionId;
147814
- const taskId = params.taskId?.trim() || normalizeTaskId(feature.id, params.type, params.title);
147815
- const existing = graph.tasks.find((task) => task.id === taskId) || graph.tasks.find((task) => task.featureId === feature.id && task.type === params.type && task.title === params.title.trim());
147816
- const nextTask = {
147817
- id: existing?.id || taskId,
147818
- title: params.title.trim(),
147819
- summary: params.summary?.trim() || "",
147820
- type: params.type,
147821
- assignee: params.assignee,
147822
- status: params.status || "planned",
147823
- acceptanceCriteria: [...new Set((params.acceptanceCriteria || []).map((item) => item.trim()).filter(Boolean))],
147824
- featureId: feature.id,
147825
- sectionId
147826
- };
147827
- const nextTasks = existing ? graph.tasks.map((task) => task.id === existing.id ? nextTask : task) : [...graph.tasks, nextTask];
147828
- await writeProjectPlanFiles(params.root, {
147829
- ...graph,
147830
- tasks: nextTasks
147831
- });
147832
- return nextTask;
147833
- }
147834
- async function updateProjectPlanTaskStatus(params) {
147835
- const graph = await readProjectPlanGraph(params.root);
147836
- const task = graph.tasks.find((item) => item.id === params.taskId);
147837
- if (!task) {
147838
- throw new Error(`Task "${params.taskId}" not found.`);
147839
- }
147840
- const nextTask = {
147841
- ...task,
147842
- status: params.status
147843
- };
147844
- await writeProjectPlanFiles(params.root, {
147845
- ...graph,
147846
- tasks: graph.tasks.map((item) => item.id === task.id ? nextTask : item)
147847
- });
147848
- return nextTask;
147849
- }
147850
- async function resolveDefaultProjectPlanRoutes(root) {
147851
- const sections = await readKnowledgeSections(root);
147852
- const resolveRoute = (key) => {
147853
- const candidate = sections.find((section2) => {
147854
- return section2.heading === DEFAULT_ROUTE_TARGETS[key].heading && section2.filePath === DEFAULT_ROUTE_TARGETS[key].filePathSuffix && section2.depth === 1;
147855
- }) || sections.find((section2) => section2.heading === DEFAULT_ROUTE_TARGETS[key].heading);
147856
- if (!candidate) {
147857
- throw new Error(`Unable to resolve the default knowledge section for ${key}.`);
147858
- }
147859
- return candidate.id;
147860
- };
147861
- return {
147862
- featuresSectionId: resolveRoute("features"),
147863
- testingSectionId: resolveRoute("testing"),
147864
- architectureSectionId: resolveRoute("architecture"),
147865
- workflowsSectionId: resolveRoute("workflows")
147866
- };
147867
- }
147868
-
147869
147138
  // src/knowledge/init.ts
147870
147139
  var MARKER_BEGIN = "%% docyrus-knowledge:begin %%";
147871
147140
  var MARKER_END = "%% docyrus-knowledge:end %%";
@@ -147877,60 +147146,60 @@ ${content3}${content3.endsWith("\n") ? "" : "\n"}${MARKER_END}
147877
147146
  `;
147878
147147
  }
147879
147148
  async function ensureDirectory(pathValue) {
147880
- await (0, import_promises14.mkdir)(pathValue, {
147149
+ await (0, import_promises12.mkdir)(pathValue, {
147881
147150
  recursive: true,
147882
147151
  mode: 493
147883
147152
  });
147884
147153
  }
147885
147154
  async function writeIfMissing(filePath, content3) {
147886
- if ((0, import_node_fs10.existsSync)(filePath)) {
147155
+ if ((0, import_node_fs8.existsSync)(filePath)) {
147887
147156
  return "kept";
147888
147157
  }
147889
- await ensureDirectory((0, import_node_path18.dirname)(filePath));
147890
- await (0, import_promises14.writeFile)(filePath, content3, "utf8");
147158
+ await ensureDirectory((0, import_node_path16.dirname)(filePath));
147159
+ await (0, import_promises12.writeFile)(filePath, content3, "utf8");
147891
147160
  return "created";
147892
147161
  }
147893
147162
  async function writeOrUpdate(filePath, content3) {
147894
- if (!(0, import_node_fs10.existsSync)(filePath)) {
147895
- await ensureDirectory((0, import_node_path18.dirname)(filePath));
147896
- await (0, import_promises14.writeFile)(filePath, content3, "utf8");
147163
+ if (!(0, import_node_fs8.existsSync)(filePath)) {
147164
+ await ensureDirectory((0, import_node_path16.dirname)(filePath));
147165
+ await (0, import_promises12.writeFile)(filePath, content3, "utf8");
147897
147166
  return "created";
147898
147167
  }
147899
- const current = await (0, import_promises14.readFile)(filePath, "utf8");
147168
+ const current = await (0, import_promises12.readFile)(filePath, "utf8");
147900
147169
  if (current === content3) {
147901
147170
  return "kept";
147902
147171
  }
147903
- await ensureDirectory((0, import_node_path18.dirname)(filePath));
147904
- await (0, import_promises14.writeFile)(filePath, content3, "utf8");
147172
+ await ensureDirectory((0, import_node_path16.dirname)(filePath));
147173
+ await (0, import_promises12.writeFile)(filePath, content3, "utf8");
147905
147174
  return "updated";
147906
147175
  }
147907
147176
  async function upsertManagedBlock(filePath, content3) {
147908
147177
  const wrapped = wrapManagedBlock(content3);
147909
- if (!(0, import_node_fs10.existsSync)(filePath)) {
147910
- await ensureDirectory((0, import_node_path18.dirname)(filePath));
147911
- await (0, import_promises14.writeFile)(filePath, wrapped, "utf8");
147178
+ if (!(0, import_node_fs8.existsSync)(filePath)) {
147179
+ await ensureDirectory((0, import_node_path16.dirname)(filePath));
147180
+ await (0, import_promises12.writeFile)(filePath, wrapped, "utf8");
147912
147181
  return "created";
147913
147182
  }
147914
- const current = await (0, import_promises14.readFile)(filePath, "utf8");
147183
+ const current = await (0, import_promises12.readFile)(filePath, "utf8");
147915
147184
  const beginIndex = current.indexOf(MARKER_BEGIN);
147916
147185
  const endIndex = current.indexOf(MARKER_END);
147917
147186
  if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
147918
147187
  const replaceEnd = current[endIndex + MARKER_END.length] === "\n" ? endIndex + MARKER_END.length + 1 : endIndex + MARKER_END.length;
147919
147188
  const updated = `${current.slice(0, beginIndex)}${wrapped}${current.slice(replaceEnd)}`;
147920
- await (0, import_promises14.writeFile)(filePath, updated, "utf8");
147189
+ await (0, import_promises12.writeFile)(filePath, updated, "utf8");
147921
147190
  return "updated";
147922
147191
  }
147923
147192
  const separator = current.endsWith("\n") ? "\n" : "\n\n";
147924
- await (0, import_promises14.writeFile)(filePath, `${current}${separator}${wrapped}`, "utf8");
147193
+ await (0, import_promises12.writeFile)(filePath, `${current}${separator}${wrapped}`, "utf8");
147925
147194
  return "appended";
147926
147195
  }
147927
147196
  function normalizeObject(value2) {
147928
147197
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? { ...value2 } : {};
147929
147198
  }
147930
147199
  async function updateJsonFile(filePath, updater) {
147931
- const current = (0, import_node_fs10.existsSync)(filePath) ? normalizeObject(JSON.parse((0, import_node_fs10.readFileSync)(filePath, "utf8"))) : {};
147932
- await ensureDirectory((0, import_node_path18.dirname)(filePath));
147933
- await (0, import_promises14.writeFile)(filePath, `${JSON.stringify(updater(current), null, 2)}
147200
+ const current = (0, import_node_fs8.existsSync)(filePath) ? normalizeObject(JSON.parse((0, import_node_fs8.readFileSync)(filePath, "utf8"))) : {};
147201
+ await ensureDirectory((0, import_node_path16.dirname)(filePath));
147202
+ await (0, import_promises12.writeFile)(filePath, `${JSON.stringify(updater(current), null, 2)}
147934
147203
  `, "utf8");
147935
147204
  }
147936
147205
  function wrapHookBlock(content3) {
@@ -147940,17 +147209,17 @@ ${content3}${content3.endsWith("\n") ? "" : "\n"}${HOOK_MARKER_END}
147940
147209
  }
147941
147210
  async function upsertShellHook(filePath, content3, shellHeader) {
147942
147211
  const wrapped = wrapHookBlock(content3);
147943
- if (!(0, import_node_fs10.existsSync)(filePath)) {
147944
- await ensureDirectory((0, import_node_path18.dirname)(filePath));
147212
+ if (!(0, import_node_fs8.existsSync)(filePath)) {
147213
+ await ensureDirectory((0, import_node_path16.dirname)(filePath));
147945
147214
  const initial = `${shellHeader || ""}${wrapped}`;
147946
- await (0, import_promises14.writeFile)(filePath, initial, {
147215
+ await (0, import_promises12.writeFile)(filePath, initial, {
147947
147216
  encoding: "utf8",
147948
147217
  mode: 493
147949
147218
  });
147950
- await (0, import_promises14.chmod)(filePath, 493);
147219
+ await (0, import_promises12.chmod)(filePath, 493);
147951
147220
  return "created";
147952
147221
  }
147953
- const current = await (0, import_promises14.readFile)(filePath, "utf8");
147222
+ const current = await (0, import_promises12.readFile)(filePath, "utf8");
147954
147223
  const beginIndex = current.indexOf(HOOK_MARKER_BEGIN);
147955
147224
  const endIndex = current.indexOf(HOOK_MARKER_END);
147956
147225
  if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
@@ -147959,13 +147228,13 @@ async function upsertShellHook(filePath, content3, shellHeader) {
147959
147228
  if (nextContent === current) {
147960
147229
  return "kept";
147961
147230
  }
147962
- await (0, import_promises14.writeFile)(filePath, nextContent, "utf8");
147963
- await (0, import_promises14.chmod)(filePath, 493);
147231
+ await (0, import_promises12.writeFile)(filePath, nextContent, "utf8");
147232
+ await (0, import_promises12.chmod)(filePath, 493);
147964
147233
  return "updated";
147965
147234
  }
147966
147235
  const separator = current.endsWith("\n") ? "\n" : "\n\n";
147967
- await (0, import_promises14.writeFile)(filePath, `${current}${separator}${wrapped}`, "utf8");
147968
- await (0, import_promises14.chmod)(filePath, 493);
147236
+ await (0, import_promises12.writeFile)(filePath, `${current}${separator}${wrapped}`, "utf8");
147237
+ await (0, import_promises12.chmod)(filePath, 493);
147969
147238
  return "appended";
147970
147239
  }
147971
147240
  function buildKnowledgeDocumentTemplate() {
@@ -148059,34 +147328,33 @@ function syncCursorHooks(settings, commandPrefix) {
148059
147328
  };
148060
147329
  }
148061
147330
  async function initializeKnowledgeRepo(params) {
148062
- const root = (0, import_node_path18.resolve)(params.root || process.cwd());
147331
+ const root = (0, import_node_path16.resolve)(params.root || process.cwd());
148063
147332
  const knowledgeDir = getKnowledgeDirectory(root);
148064
- const knowledgeFile = (0, import_node_path18.join)(knowledgeDir, "knowledge.md");
147333
+ const knowledgeFile = (0, import_node_path16.join)(knowledgeDir, "knowledge.md");
148065
147334
  await ensureDirectory(knowledgeDir);
148066
147335
  const knowledgeFileStatus = await writeIfMissing(knowledgeFile, `${buildKnowledgeDocumentTemplate()}
148067
147336
  `);
148068
- const agentsStatus = await upsertManagedBlock((0, import_node_path18.join)(root, "AGENTS.md"), buildAgentsTemplate(params.commandPrefix));
148069
- const claudeStatus = await upsertManagedBlock((0, import_node_path18.join)(root, "CLAUDE.md"), buildAgentsTemplate(params.commandPrefix));
148070
- const cursorRulesStatus = await writeOrUpdate((0, import_node_path18.join)(root, ".cursor", "rules", "docyrus-knowledge.md"), `${buildCursorRulesTemplate(params.commandPrefix)}
147337
+ const agentsStatus = await upsertManagedBlock((0, import_node_path16.join)(root, "AGENTS.md"), buildAgentsTemplate(params.commandPrefix));
147338
+ const claudeStatus = await upsertManagedBlock((0, import_node_path16.join)(root, "CLAUDE.md"), buildAgentsTemplate(params.commandPrefix));
147339
+ const cursorRulesStatus = await writeOrUpdate((0, import_node_path16.join)(root, ".cursor", "rules", "docyrus-knowledge.md"), `${buildCursorRulesTemplate(params.commandPrefix)}
148071
147340
  `);
148072
147341
  const bootstrap = (await generateInitialKnowledge({
148073
147342
  root,
148074
147343
  brief: params.brief
148075
147344
  })).files;
148076
- const projectPlan = await syncProjectPlanSectionsFromKnowledge(root);
148077
- await updateJsonFile((0, import_node_path18.join)(root, ".claude", "settings.json"), (value2) => syncClaudeHooks(value2, params.commandPrefix));
148078
- await updateJsonFile((0, import_node_path18.join)(root, ".cursor", "hooks.json"), (value2) => syncCursorHooks(value2, params.commandPrefix));
147345
+ await updateJsonFile((0, import_node_path16.join)(root, ".claude", "settings.json"), (value2) => syncClaudeHooks(value2, params.commandPrefix));
147346
+ await updateJsonFile((0, import_node_path16.join)(root, ".cursor", "hooks.json"), (value2) => syncCursorHooks(value2, params.commandPrefix));
148079
147347
  let huskyHookStatus;
148080
- const huskyDir = (0, import_node_path18.join)(root, ".husky");
148081
- if ((0, import_node_fs10.existsSync)(huskyDir)) {
148082
- const huskyHookPath = (0, import_node_path18.join)(huskyDir, "pre-commit");
148083
- const huskyHeader = (0, import_node_fs10.existsSync)((0, import_node_path18.join)(huskyDir, "_", "h")) ? '#!/usr/bin/env sh\n. "$(dirname -- "$0")/_/h"\n\n' : void 0;
147348
+ const huskyDir = (0, import_node_path16.join)(root, ".husky");
147349
+ if ((0, import_node_fs8.existsSync)(huskyDir)) {
147350
+ const huskyHookPath = (0, import_node_path16.join)(huskyDir, "pre-commit");
147351
+ const huskyHeader = (0, import_node_fs8.existsSync)((0, import_node_path16.join)(huskyDir, "_", "h")) ? '#!/usr/bin/env sh\n. "$(dirname -- "$0")/_/h"\n\n' : void 0;
148084
147352
  huskyHookStatus = await upsertShellHook(huskyHookPath, `${params.commandPrefix} knowledge pre-commit
148085
147353
  `, huskyHeader);
148086
147354
  }
148087
147355
  let gitHookStatus;
148088
147356
  if (!huskyHookStatus && params.installGitHook) {
148089
- const gitHookPath = (0, import_node_path18.join)(root, ".git", "hooks", "pre-commit");
147357
+ const gitHookPath = (0, import_node_path16.join)(root, ".git", "hooks", "pre-commit");
148090
147358
  gitHookStatus = await upsertShellHook(gitHookPath, `${params.commandPrefix} knowledge pre-commit
148091
147359
  `, "#!/usr/bin/env sh\n\n");
148092
147360
  }
@@ -148094,8 +147362,6 @@ async function initializeKnowledgeRepo(params) {
148094
147362
  root,
148095
147363
  knowledgeDir,
148096
147364
  knowledgeFile,
148097
- projectPlanGraphPath: projectPlan.graphPath,
148098
- projectPlanMarkdownPath: projectPlan.markdownPath,
148099
147365
  agentsStatus,
148100
147366
  claudeStatus,
148101
147367
  cursorRulesStatus,
@@ -148110,9 +147376,9 @@ async function initializeKnowledgeRepo(params) {
148110
147376
  init_graph();
148111
147377
 
148112
147378
  // src/knowledge/validation.ts
148113
- var import_node_fs11 = require("node:fs");
148114
- var import_promises15 = require("node:fs/promises");
148115
- var import_node_path19 = require("node:path");
147379
+ var import_node_fs9 = require("node:fs");
147380
+ var import_promises13 = require("node:fs/promises");
147381
+ var import_node_path17 = require("node:path");
148116
147382
  init_graph();
148117
147383
  var MAX_BODY_LENGTH = 250;
148118
147384
  function bodyTextLength(body2) {
@@ -148145,15 +147411,15 @@ async function tryResolveSourceRef(target, projectRoot) {
148145
147411
  const hashIndex = target.indexOf("#");
148146
147412
  const filePart = hashIndex === -1 ? target : target.slice(0, hashIndex);
148147
147413
  const symbolPart = hashIndex === -1 ? "" : target.slice(hashIndex + 1);
148148
- const extension2 = (0, import_node_path19.extname)(filePart);
147414
+ const extension2 = (0, import_node_path17.extname)(filePart);
148149
147415
  if (!SOURCE_EXTENSIONS.has(extension2)) {
148150
147416
  if (extension2 && hashIndex !== -1) {
148151
147417
  return `broken link [[${target}]] - unsupported file extension "${extension2}"`;
148152
147418
  }
148153
147419
  return `broken link [[${target}]] - no matching section found`;
148154
147420
  }
148155
- const absolutePath = (0, import_node_path19.join)(projectRoot, filePart);
148156
- if (!(0, import_node_fs11.existsSync)(absolutePath)) {
147421
+ const absolutePath = (0, import_node_path17.join)(projectRoot, filePart);
147422
+ if (!(0, import_node_fs9.existsSync)(absolutePath)) {
148157
147423
  return `broken link [[${target}]] - file "${filePart}" not found`;
148158
147424
  }
148159
147425
  if (!symbolPart) {
@@ -148170,7 +147436,7 @@ async function tryResolveSourceRef(target, projectRoot) {
148170
147436
  }
148171
147437
  async function checkKnowledgeMarkdown(knowledgeDir) {
148172
147438
  clearSymbolCache();
148173
- const projectRoot = (0, import_node_path19.dirname)((0, import_node_path19.dirname)(knowledgeDir));
147439
+ const projectRoot = (0, import_node_path17.dirname)((0, import_node_path17.dirname)(knowledgeDir));
148174
147440
  const files = await listKnowledgeFiles(knowledgeDir);
148175
147441
  const sections = await loadAllSections(knowledgeDir);
148176
147442
  const flat = flattenSections(sections);
@@ -148179,9 +147445,9 @@ async function checkKnowledgeMarkdown(knowledgeDir) {
148179
147445
  const fileIndex = buildFileIndex(sections);
148180
147446
  const errors = [];
148181
147447
  for (const filePath of files) {
148182
- const content3 = await (0, import_promises15.readFile)(filePath, "utf8");
147448
+ const content3 = await (0, import_promises13.readFile)(filePath, "utf8");
148183
147449
  const refs = extractRefs(filePath, content3, projectRoot);
148184
- const displayPath = (0, import_node_path19.relative)(process.cwd(), filePath);
147450
+ const displayPath = (0, import_node_path17.relative)(process.cwd(), filePath);
148185
147451
  for (const ref of refs) {
148186
147452
  const resolved = resolveRef2(ref.target, sectionIds, fileIndex, canonicalSectionIds);
148187
147453
  if (resolved.ambiguous) {
@@ -148213,7 +147479,7 @@ async function checkKnowledgeMarkdown(knowledgeDir) {
148213
147479
  };
148214
147480
  }
148215
147481
  async function checkKnowledgeCodeRefs(knowledgeDir) {
148216
- const projectRoot = (0, import_node_path19.dirname)((0, import_node_path19.dirname)(knowledgeDir));
147482
+ const projectRoot = (0, import_node_path17.dirname)((0, import_node_path17.dirname)(knowledgeDir));
148217
147483
  const sections = await loadAllSections(knowledgeDir);
148218
147484
  const flat = flattenSections(sections);
148219
147485
  const sectionIds = new Set(flat.map((section2) => section2.id.toLowerCase()));
@@ -148225,7 +147491,7 @@ async function checkKnowledgeCodeRefs(knowledgeDir) {
148225
147491
  for (const ref of scan.refs) {
148226
147492
  const resolved = resolveRef2(ref.target, sectionIds, fileIndex, canonicalSectionIds);
148227
147493
  mentionedSections.add(resolved.resolved.toLowerCase());
148228
- const displayPath = (0, import_node_path19.relative)(process.cwd(), (0, import_node_path19.join)(projectRoot, ref.file));
147494
+ const displayPath = (0, import_node_path17.relative)(process.cwd(), (0, import_node_path17.join)(projectRoot, ref.file));
148229
147495
  if (resolved.ambiguous) {
148230
147496
  errors.push({
148231
147497
  file: displayPath,
@@ -148245,12 +147511,12 @@ async function checkKnowledgeCodeRefs(knowledgeDir) {
148245
147511
  }
148246
147512
  }
148247
147513
  for (const filePath of await listKnowledgeFiles(knowledgeDir)) {
148248
- const content3 = await (0, import_promises15.readFile)(filePath, "utf8");
147514
+ const content3 = await (0, import_promises13.readFile)(filePath, "utf8");
148249
147515
  if (!parseFrontmatter(content3).requireCodeMention) {
148250
147516
  continue;
148251
147517
  }
148252
147518
  const leafSections = flattenSections(parseSections(filePath, content3, projectRoot)).filter((section2) => section2.children.length === 0);
148253
- const displayPath = (0, import_node_path19.relative)(process.cwd(), filePath);
147519
+ const displayPath = (0, import_node_path17.relative)(process.cwd(), filePath);
148254
147520
  for (const section2 of leafSections) {
148255
147521
  if (!mentionedSections.has(section2.id.toLowerCase())) {
148256
147522
  errors.push({
@@ -148274,7 +147540,7 @@ async function checkKnowledgeIndex(knowledgeDir) {
148274
147540
  const name2 = pathValue.includes("/") ? pathValue.slice(pathValue.lastIndexOf("/") + 1) : pathValue;
148275
147541
  if (!name2.endsWith(".md")) {
148276
147542
  errors.push({
148277
- dir: `${(0, import_node_path19.basename)(knowledgeDir)}/`,
147543
+ dir: `${(0, import_node_path17.basename)(knowledgeDir)}/`,
148278
147544
  message: `"${pathValue}" is not a .md file - only markdown files belong in docyrus/knowledge/`
148279
147545
  });
148280
147546
  }
@@ -148288,7 +147554,7 @@ async function checkKnowledgeIndex(knowledgeDir) {
148288
147554
  }
148289
147555
  }
148290
147556
  for (const dir of dirs) {
148291
- const dirName = dir === "" ? (0, import_node_path19.basename)(knowledgeDir) : dir.split("/").pop() || (0, import_node_path19.basename)(knowledgeDir);
147557
+ const dirName = dir === "" ? (0, import_node_path17.basename)(knowledgeDir) : dir.split("/").pop() || (0, import_node_path17.basename)(knowledgeDir);
148292
147558
  const indexFileName = dirName.endsWith(".md") ? dirName : `${dirName}.md`;
148293
147559
  const indexRelPath = dir === "" ? indexFileName : `${dir}/${indexFileName}`;
148294
147560
  const prefix = dir === "" ? "" : `${dir}/`;
@@ -148297,11 +147563,11 @@ async function checkKnowledgeIndex(knowledgeDir) {
148297
147563
  if (children.length === 0) {
148298
147564
  continue;
148299
147565
  }
148300
- const indexFullPath = (0, import_node_path19.join)(knowledgeDir, indexRelPath);
148301
- const displayDir = dir === "" ? `${(0, import_node_path19.basename)(knowledgeDir)}/` : `${dir}/`;
147566
+ const indexFullPath = (0, import_node_path17.join)(knowledgeDir, indexRelPath);
147567
+ const displayDir = dir === "" ? `${(0, import_node_path17.basename)(knowledgeDir)}/` : `${dir}/`;
148302
147568
  let content3;
148303
147569
  try {
148304
- content3 = await (0, import_promises15.readFile)(indexFullPath, "utf8");
147570
+ content3 = await (0, import_promises13.readFile)(indexFullPath, "utf8");
148305
147571
  } catch {
148306
147572
  errors.push({
148307
147573
  dir: displayDir,
@@ -148337,12 +147603,12 @@ ${indexSnippet(missing)}`,
148337
147603
  return errors;
148338
147604
  }
148339
147605
  async function checkKnowledgeSections(knowledgeDir) {
148340
- const projectRoot = (0, import_node_path19.dirname)((0, import_node_path19.dirname)(knowledgeDir));
147606
+ const projectRoot = (0, import_node_path17.dirname)((0, import_node_path17.dirname)(knowledgeDir));
148341
147607
  const errors = [];
148342
147608
  for (const filePath of await listKnowledgeFiles(knowledgeDir)) {
148343
- const content3 = await (0, import_promises15.readFile)(filePath, "utf8");
147609
+ const content3 = await (0, import_promises13.readFile)(filePath, "utf8");
148344
147610
  const sections = flattenSections(parseSections(filePath, content3, projectRoot));
148345
- const displayPath = (0, import_node_path19.relative)(process.cwd(), filePath);
147611
+ const displayPath = (0, import_node_path17.relative)(process.cwd(), filePath);
148346
147612
  for (const section2 of sections) {
148347
147613
  if (!section2.firstParagraph) {
148348
147614
  errors.push({
@@ -148397,7 +147663,7 @@ function formatKnowledgeIndexErrors(errors, styler) {
148397
147663
 
148398
147664
  // src/knowledge/audit.ts
148399
147665
  var import_node_child_process4 = require("node:child_process");
148400
- var import_node_fs12 = require("node:fs");
147666
+ var import_node_fs10 = require("node:fs");
148401
147667
  init_graph();
148402
147668
  function runGit(projectRoot, args2) {
148403
147669
  return new Promise((resolve2) => {
@@ -148532,7 +147798,7 @@ async function analyzeKnowledgeImpacts(params) {
148532
147798
  const changedFiles = await getChangedFiles(params.projectRoot, params.mode);
148533
147799
  const knowledgeChangedFiles = changedFiles.filter((filePath) => filePath.startsWith("docyrus/knowledge/"));
148534
147800
  const diffStats = await getDiffStats(params.projectRoot, params.mode);
148535
- if (!params.knowledgeDir || !(0, import_node_fs12.existsSync)(params.knowledgeDir)) {
147801
+ if (!params.knowledgeDir || !(0, import_node_fs10.existsSync)(params.knowledgeDir)) {
148536
147802
  return {
148537
147803
  ok: true,
148538
147804
  mode: params.mode,
@@ -148638,7 +147904,7 @@ async function analyzeKnowledgeImpacts(params) {
148638
147904
  };
148639
147905
  }
148640
147906
  async function analyzeKnowledgeDoctor(params) {
148641
- if (!params.knowledgeDir || !(0, import_node_fs12.existsSync)(params.knowledgeDir)) {
147907
+ if (!params.knowledgeDir || !(0, import_node_fs10.existsSync)(params.knowledgeDir)) {
148642
147908
  return {
148643
147909
  ok: false,
148644
147910
  warnings: [{
@@ -148725,6 +147991,786 @@ async function analyzeKnowledgeDoctor(params) {
148725
147991
  };
148726
147992
  }
148727
147993
 
147994
+ // src/project-plan/graph.ts
147995
+ var import_node_crypto5 = require("node:crypto");
147996
+ var import_node_fs12 = require("node:fs");
147997
+ var import_promises15 = __toESM(require("node:fs/promises"));
147998
+ var import_node_path19 = __toESM(require("node:path"));
147999
+
148000
+ // src/project-plan/localTodos.ts
148001
+ var import_node_crypto4 = __toESM(require("node:crypto"));
148002
+ var import_node_fs11 = require("node:fs");
148003
+ var import_promises14 = __toESM(require("node:fs/promises"));
148004
+ var import_node_path18 = __toESM(require("node:path"));
148005
+ var TODO_DIR_NAME = ".pi/todos";
148006
+ var TODO_PATH_ENV = "PI_TODO_PATH";
148007
+ function resolveTodosDirectory(root) {
148008
+ const overridePath = process.env[TODO_PATH_ENV]?.trim();
148009
+ if (overridePath) {
148010
+ return import_node_path18.default.resolve(root, overridePath);
148011
+ }
148012
+ return import_node_path18.default.resolve(root, TODO_DIR_NAME);
148013
+ }
148014
+ function getTodoFilePath(todosDir, id) {
148015
+ return import_node_path18.default.join(todosDir, `${id}.md`);
148016
+ }
148017
+ function splitFrontMatter(content3) {
148018
+ if (!content3.startsWith("{")) {
148019
+ return {
148020
+ frontMatter: "",
148021
+ body: content3
148022
+ };
148023
+ }
148024
+ let depth = 0;
148025
+ let inString = false;
148026
+ let escaped = false;
148027
+ let endIndex = -1;
148028
+ for (let index2 = 0; index2 < content3.length; index2 += 1) {
148029
+ const char = content3[index2];
148030
+ if (inString) {
148031
+ if (escaped) {
148032
+ escaped = false;
148033
+ continue;
148034
+ }
148035
+ if (char === "\\") {
148036
+ escaped = true;
148037
+ continue;
148038
+ }
148039
+ if (char === '"') {
148040
+ inString = false;
148041
+ }
148042
+ continue;
148043
+ }
148044
+ if (char === '"') {
148045
+ inString = true;
148046
+ continue;
148047
+ }
148048
+ if (char === "{") {
148049
+ depth += 1;
148050
+ continue;
148051
+ }
148052
+ if (char === "}") {
148053
+ depth -= 1;
148054
+ if (depth === 0) {
148055
+ endIndex = index2;
148056
+ break;
148057
+ }
148058
+ }
148059
+ }
148060
+ if (endIndex === -1) {
148061
+ return {
148062
+ frontMatter: "",
148063
+ body: content3
148064
+ };
148065
+ }
148066
+ return {
148067
+ frontMatter: content3.slice(0, endIndex + 1),
148068
+ body: content3.slice(endIndex + 1).replace(/^\r?\n+/u, "")
148069
+ };
148070
+ }
148071
+ function parseLocalTodoFrontMatter(frontMatter, idFallback) {
148072
+ const base = {
148073
+ id: idFallback,
148074
+ title: "",
148075
+ tags: [],
148076
+ status: "open",
148077
+ created_at: ""
148078
+ };
148079
+ if (!frontMatter.trim()) {
148080
+ return base;
148081
+ }
148082
+ try {
148083
+ const parsed = JSON.parse(frontMatter);
148084
+ return {
148085
+ id: typeof parsed.id === "string" && parsed.id.trim() ? parsed.id.trim() : idFallback,
148086
+ title: typeof parsed.title === "string" ? parsed.title : "",
148087
+ tags: Array.isArray(parsed.tags) ? parsed.tags.filter((value2) => typeof value2 === "string") : [],
148088
+ status: typeof parsed.status === "string" && parsed.status.trim() ? parsed.status.trim() : "open",
148089
+ created_at: typeof parsed.created_at === "string" ? parsed.created_at : "",
148090
+ assigned_to_session: typeof parsed.assigned_to_session === "string" && parsed.assigned_to_session.trim() ? parsed.assigned_to_session.trim() : void 0,
148091
+ parent_task_id: typeof parsed.parent_task_id === "string" && parsed.parent_task_id.trim() ? parsed.parent_task_id.trim() : void 0
148092
+ };
148093
+ } catch {
148094
+ return base;
148095
+ }
148096
+ }
148097
+ function serializeLocalTodo(record2) {
148098
+ const frontMatter = JSON.stringify(
148099
+ {
148100
+ id: record2.id,
148101
+ title: record2.title,
148102
+ tags: record2.tags,
148103
+ status: record2.status,
148104
+ created_at: record2.created_at,
148105
+ assigned_to_session: record2.assigned_to_session || void 0,
148106
+ parent_task_id: record2.parent_task_id || void 0
148107
+ },
148108
+ null,
148109
+ 2
148110
+ );
148111
+ const trimmedBody = record2.body.trim();
148112
+ return trimmedBody ? `${frontMatter}
148113
+
148114
+ ${trimmedBody}
148115
+ ` : `${frontMatter}
148116
+ `;
148117
+ }
148118
+ async function generateTodoId(todosDir) {
148119
+ for (let attempt = 0; attempt < 10; attempt += 1) {
148120
+ const id = import_node_crypto4.default.randomBytes(4).toString("hex");
148121
+ if (!(0, import_node_fs11.existsSync)(getTodoFilePath(todosDir, id))) {
148122
+ return id;
148123
+ }
148124
+ }
148125
+ throw new Error("Failed to generate linked todo id.");
148126
+ }
148127
+ async function listLinkedTodosByTask(root) {
148128
+ const todosDir = resolveTodosDirectory(root);
148129
+ const result = /* @__PURE__ */ new Map();
148130
+ let entries = [];
148131
+ try {
148132
+ entries = await import_promises14.default.readdir(todosDir);
148133
+ } catch {
148134
+ return result;
148135
+ }
148136
+ for (const entry of entries) {
148137
+ if (!entry.endsWith(".md")) {
148138
+ continue;
148139
+ }
148140
+ const id = entry.slice(0, -3);
148141
+ const filePath = getTodoFilePath(todosDir, id);
148142
+ try {
148143
+ const raw = await import_promises14.default.readFile(filePath, "utf8");
148144
+ const { frontMatter } = splitFrontMatter(raw);
148145
+ const parsed = parseLocalTodoFrontMatter(frontMatter, id);
148146
+ if (!parsed.parent_task_id) {
148147
+ continue;
148148
+ }
148149
+ const existing = result.get(parsed.parent_task_id) || [];
148150
+ existing.push({
148151
+ id,
148152
+ title: parsed.title,
148153
+ status: parsed.status,
148154
+ filePath: import_node_path18.default.relative(root, filePath),
148155
+ parentTaskId: parsed.parent_task_id
148156
+ });
148157
+ result.set(parsed.parent_task_id, existing);
148158
+ } catch {
148159
+ }
148160
+ }
148161
+ for (const linkedTodos of result.values()) {
148162
+ linkedTodos.sort((left, right) => left.title.localeCompare(right.title) || left.id.localeCompare(right.id));
148163
+ }
148164
+ return result;
148165
+ }
148166
+ async function createLinkedTodo(params) {
148167
+ const todosDir = resolveTodosDirectory(params.root);
148168
+ await import_promises14.default.mkdir(todosDir, {
148169
+ recursive: true
148170
+ });
148171
+ const id = await generateTodoId(todosDir);
148172
+ const filePath = getTodoFilePath(todosDir, id);
148173
+ const todo = {
148174
+ id,
148175
+ title: params.title,
148176
+ tags: [],
148177
+ status: "open",
148178
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
148179
+ parent_task_id: params.parentTaskId,
148180
+ body: params.body ?? ""
148181
+ };
148182
+ await import_promises14.default.writeFile(filePath, serializeLocalTodo(todo), "utf8");
148183
+ return {
148184
+ id,
148185
+ title: todo.title,
148186
+ status: todo.status,
148187
+ filePath: import_node_path18.default.relative(params.root, filePath),
148188
+ parentTaskId: params.parentTaskId
148189
+ };
148190
+ }
148191
+
148192
+ // src/project-plan/types.ts
148193
+ var PROJECT_TASK_TYPES = [
148194
+ "bug-fix",
148195
+ "new-implementation",
148196
+ "api-test",
148197
+ "browser-automation-test",
148198
+ "work"
148199
+ ];
148200
+ var PROJECT_TASK_ASSIGNEES = [
148201
+ "agent",
148202
+ "user"
148203
+ ];
148204
+ var PROJECT_TASK_STATUSES = [
148205
+ "planned",
148206
+ "in_progress",
148207
+ "blocked",
148208
+ "done"
148209
+ ];
148210
+
148211
+ // src/project-plan/graph.ts
148212
+ var PROJECT_PLAN_DIR_SEGMENTS = ["docyrus", "project-plan"];
148213
+ var PROJECT_PLAN_JSON_FILE_NAME = "project-plan.json";
148214
+ var PROJECT_PLAN_MARKDOWN_FILE_NAME = "PROJECT_PLAN.md";
148215
+ var KNOWLEDGE_FEATURES_PATH_SEGMENTS = ["docyrus", "knowledge", "features", "features.md"];
148216
+ var FEATURES_MARKER_BEGIN = "<!-- docyrus-project-plan:features:begin -->";
148217
+ var FEATURES_MARKER_END = "<!-- docyrus-project-plan:features:end -->";
148218
+ function isRecord3(value2) {
148219
+ return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
148220
+ }
148221
+ function isNonEmptyString(value2) {
148222
+ return typeof value2 === "string" && value2.trim().length > 0;
148223
+ }
148224
+ function normalizeStringArray(value2) {
148225
+ if (!Array.isArray(value2)) {
148226
+ return [];
148227
+ }
148228
+ return value2.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
148229
+ }
148230
+ function slugify2(value2) {
148231
+ const slug = value2.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 80);
148232
+ return slug || "item";
148233
+ }
148234
+ function hashParts(parts2) {
148235
+ return (0, import_node_crypto5.createHash)("sha1").update(parts2.join("::")).digest("hex").slice(0, 12);
148236
+ }
148237
+ function normalizeSectionId(slug) {
148238
+ return `section-${hashParts([slug])}`;
148239
+ }
148240
+ function normalizeFeatureId(sectionId, slug) {
148241
+ return `feature-${hashParts([sectionId, slug])}`;
148242
+ }
148243
+ function normalizeTaskId(featureId, type, title) {
148244
+ return `task-${hashParts([featureId, type, slugify2(title)])}`;
148245
+ }
148246
+ function compareStrings(left, right) {
148247
+ return left.localeCompare(right);
148248
+ }
148249
+ function sortGraph(graph) {
148250
+ return {
148251
+ version: 1,
148252
+ sections: [...graph.sections].sort((left, right) => compareStrings(left.id, right.id)),
148253
+ features: [...graph.features].sort((left, right) => {
148254
+ return compareStrings(left.sectionId, right.sectionId) || compareStrings(left.title, right.title) || compareStrings(left.id, right.id);
148255
+ }),
148256
+ tasks: [...graph.tasks].sort((left, right) => {
148257
+ return compareStrings(left.sectionId, right.sectionId) || compareStrings(left.featureId, right.featureId) || compareStrings(left.title, right.title) || compareStrings(left.id, right.id);
148258
+ })
148259
+ };
148260
+ }
148261
+ function resolveProjectPlanDirectory(root) {
148262
+ return import_node_path19.default.join(root, ...PROJECT_PLAN_DIR_SEGMENTS);
148263
+ }
148264
+ function resolveProjectPlanGraphPath(root) {
148265
+ return import_node_path19.default.join(resolveProjectPlanDirectory(root), PROJECT_PLAN_JSON_FILE_NAME);
148266
+ }
148267
+ function resolveProjectPlanMarkdownPath(root) {
148268
+ return import_node_path19.default.join(resolveProjectPlanDirectory(root), PROJECT_PLAN_MARKDOWN_FILE_NAME);
148269
+ }
148270
+ function createEmptyProjectPlanGraph() {
148271
+ return {
148272
+ version: 1,
148273
+ sections: [],
148274
+ features: [],
148275
+ tasks: []
148276
+ };
148277
+ }
148278
+ function parseProjectPlanGraph(rawValue) {
148279
+ if (!isRecord3(rawValue)) {
148280
+ return createEmptyProjectPlanGraph();
148281
+ }
148282
+ const sections = Array.isArray(rawValue.sections) ? rawValue.sections.filter((value2) => isRecord3(value2)).map((value2) => ({
148283
+ id: isNonEmptyString(value2.id) ? value2.id.trim() : "",
148284
+ title: isNonEmptyString(value2.title) ? value2.title.trim() : "",
148285
+ slug: isNonEmptyString(value2.slug) ? value2.slug.trim() : "",
148286
+ summary: typeof value2.summary === "string" ? value2.summary.trim() : ""
148287
+ })).filter((value2) => value2.id.length > 0) : [];
148288
+ const features = Array.isArray(rawValue.features) ? rawValue.features.filter((value2) => isRecord3(value2)).map((value2) => ({
148289
+ id: isNonEmptyString(value2.id) ? value2.id.trim() : "",
148290
+ title: isNonEmptyString(value2.title) ? value2.title.trim() : "",
148291
+ slug: isNonEmptyString(value2.slug) ? value2.slug.trim() : "",
148292
+ summary: typeof value2.summary === "string" ? value2.summary.trim() : "",
148293
+ sectionId: isNonEmptyString(value2.sectionId) ? value2.sectionId.trim() : ""
148294
+ })).filter((value2) => value2.id.length > 0) : [];
148295
+ const tasks = Array.isArray(rawValue.tasks) ? rawValue.tasks.filter((value2) => isRecord3(value2)).map((value2) => ({
148296
+ id: isNonEmptyString(value2.id) ? value2.id.trim() : "",
148297
+ title: isNonEmptyString(value2.title) ? value2.title.trim() : "",
148298
+ summary: typeof value2.summary === "string" ? value2.summary.trim() : "",
148299
+ type: typeof value2.type === "string" ? value2.type : "work",
148300
+ assignee: typeof value2.assignee === "string" ? value2.assignee : "agent",
148301
+ status: typeof value2.status === "string" ? value2.status : "planned",
148302
+ acceptanceCriteria: normalizeStringArray(value2.acceptanceCriteria),
148303
+ featureId: isNonEmptyString(value2.featureId) ? value2.featureId.trim() : "",
148304
+ sectionId: isNonEmptyString(value2.sectionId) ? value2.sectionId.trim() : ""
148305
+ })).filter((value2) => value2.id.length > 0) : [];
148306
+ return sortGraph({
148307
+ version: 1,
148308
+ sections,
148309
+ features,
148310
+ tasks
148311
+ });
148312
+ }
148313
+ async function readProjectPlanGraph(root) {
148314
+ const graphPath = resolveProjectPlanGraphPath(root);
148315
+ if (!(0, import_node_fs12.existsSync)(graphPath)) {
148316
+ return createEmptyProjectPlanGraph();
148317
+ }
148318
+ const raw = await import_promises15.default.readFile(graphPath, "utf8");
148319
+ return parseProjectPlanGraph(JSON.parse(raw));
148320
+ }
148321
+ function deriveFeatureStatus(tasks) {
148322
+ if (tasks.length === 0) {
148323
+ return "planned";
148324
+ }
148325
+ if (tasks.every((task) => task.status === "done")) {
148326
+ return "done";
148327
+ }
148328
+ if (tasks.some((task) => task.status === "in_progress")) {
148329
+ return "in_progress";
148330
+ }
148331
+ if (tasks.some((task) => task.status === "blocked")) {
148332
+ return "blocked";
148333
+ }
148334
+ return "planned";
148335
+ }
148336
+ function deriveSectionStatus(features) {
148337
+ if (features.length === 0) {
148338
+ return "planned";
148339
+ }
148340
+ if (features.every((feature) => feature.status === "done")) {
148341
+ return "done";
148342
+ }
148343
+ if (features.some((feature) => feature.status === "in_progress")) {
148344
+ return "in_progress";
148345
+ }
148346
+ if (features.some((feature) => feature.status === "blocked")) {
148347
+ return "blocked";
148348
+ }
148349
+ return "planned";
148350
+ }
148351
+ async function buildProjectPlanHierarchy(root, graph) {
148352
+ const currentGraph = graph ?? await readProjectPlanGraph(root);
148353
+ const linkedTodos = await listLinkedTodosByTask(root);
148354
+ const featureMap = /* @__PURE__ */ new Map();
148355
+ for (const feature of currentGraph.features) {
148356
+ const featureTasks = currentGraph.tasks.filter((task) => task.featureId === feature.id).map((task) => {
148357
+ const taskLinkedTodos = linkedTodos.get(task.id) || [];
148358
+ return {
148359
+ ...task,
148360
+ linkedTodos: taskLinkedTodos,
148361
+ linkedTodoCount: taskLinkedTodos.length
148362
+ };
148363
+ });
148364
+ featureMap.set(feature.id, {
148365
+ ...feature,
148366
+ status: deriveFeatureStatus(featureTasks),
148367
+ taskCount: featureTasks.length,
148368
+ tasks: featureTasks
148369
+ });
148370
+ }
148371
+ const sections = currentGraph.sections.map((section2) => {
148372
+ const features = currentGraph.features.filter((feature) => feature.sectionId === section2.id).map((feature) => featureMap.get(feature.id)).filter((feature) => Boolean(feature));
148373
+ const taskCount = features.reduce((count, feature) => count + feature.taskCount, 0);
148374
+ return {
148375
+ id: section2.id,
148376
+ title: section2.title,
148377
+ slug: section2.slug,
148378
+ summary: section2.summary,
148379
+ status: deriveSectionStatus(features),
148380
+ featureCount: features.length,
148381
+ taskCount,
148382
+ features
148383
+ };
148384
+ });
148385
+ return {
148386
+ sections
148387
+ };
148388
+ }
148389
+ function formatAcceptanceCriteria(criteria) {
148390
+ if (criteria.length === 0) {
148391
+ return ["- None yet"];
148392
+ }
148393
+ return criteria.map((item) => `- ${item}`);
148394
+ }
148395
+ async function renderProjectPlanMarkdown(root, graph) {
148396
+ const hierarchy = await buildProjectPlanHierarchy(root, graph);
148397
+ const lines = [
148398
+ "# Project Plan",
148399
+ "",
148400
+ "This file is derived from `docyrus/project-plan/project-plan.json`.",
148401
+ ""
148402
+ ];
148403
+ const populatedSections = hierarchy.sections.filter((section2) => section2.features.length > 0);
148404
+ if (populatedSections.length === 0) {
148405
+ lines.push("No planned features or tasks yet.");
148406
+ lines.push("");
148407
+ return `${lines.join("\n")}`;
148408
+ }
148409
+ for (const section2 of populatedSections) {
148410
+ lines.push(`## ${section2.title}`);
148411
+ lines.push("");
148412
+ lines.push(`- Section ID: \`${section2.id}\``);
148413
+ lines.push(`- Status: \`${section2.status}\``);
148414
+ lines.push(`- Features: ${section2.featureCount}`);
148415
+ lines.push(`- Tasks: ${section2.taskCount}`);
148416
+ lines.push("");
148417
+ for (const feature of section2.features) {
148418
+ lines.push(`### ${feature.title}`);
148419
+ lines.push("");
148420
+ lines.push(`- Feature ID: \`${feature.id}\``);
148421
+ lines.push(`- Status: \`${feature.status}\``);
148422
+ lines.push(`- Slug: \`${feature.slug}\``);
148423
+ if (feature.summary) {
148424
+ lines.push(`- Summary: ${feature.summary}`);
148425
+ }
148426
+ lines.push("");
148427
+ for (const task of feature.tasks) {
148428
+ lines.push(`#### ${task.title}`);
148429
+ lines.push("");
148430
+ lines.push(`- Task ID: \`${task.id}\``);
148431
+ lines.push(`- Type: \`${task.type}\``);
148432
+ lines.push(`- Assignee: \`${task.assignee}\``);
148433
+ lines.push(`- Status: \`${task.status}\``);
148434
+ if (task.summary) {
148435
+ lines.push(`- Summary: ${task.summary}`);
148436
+ }
148437
+ lines.push("- Acceptance Criteria:");
148438
+ lines.push(...formatAcceptanceCriteria(task.acceptanceCriteria));
148439
+ lines.push("");
148440
+ }
148441
+ }
148442
+ }
148443
+ return `${lines.join("\n").trimEnd()}
148444
+ `;
148445
+ }
148446
+ function buildKnowledgeFeaturesSection(graph) {
148447
+ const sectionMap = new Map(graph.sections.map((section2) => [section2.id, section2]));
148448
+ const featuresBySection = /* @__PURE__ */ new Map();
148449
+ for (const feature of graph.features) {
148450
+ const list4 = featuresBySection.get(feature.sectionId) || [];
148451
+ list4.push(feature);
148452
+ featuresBySection.set(feature.sectionId, list4);
148453
+ }
148454
+ const lines = [
148455
+ "## Planned Features",
148456
+ "",
148457
+ "Features tracked in the project plan.",
148458
+ ""
148459
+ ];
148460
+ if (graph.features.length === 0) {
148461
+ lines.push("No planned features yet.");
148462
+ lines.push("");
148463
+ return lines.join("\n");
148464
+ }
148465
+ for (const section2 of graph.sections) {
148466
+ const features = featuresBySection.get(section2.id);
148467
+ if (!features || features.length === 0) {
148468
+ continue;
148469
+ }
148470
+ lines.push(`### ${section2.title}`);
148471
+ lines.push("");
148472
+ for (const feature of features) {
148473
+ const summary = feature.summary ? ` \u2014 ${feature.summary}` : "";
148474
+ lines.push(`- **${feature.title}**${summary}`);
148475
+ }
148476
+ lines.push("");
148477
+ }
148478
+ const ungrouped = graph.features.filter((feature) => !sectionMap.has(feature.sectionId));
148479
+ if (ungrouped.length > 0) {
148480
+ for (const feature of ungrouped) {
148481
+ const summary = feature.summary ? ` \u2014 ${feature.summary}` : "";
148482
+ lines.push(`- **${feature.title}**${summary}`);
148483
+ }
148484
+ lines.push("");
148485
+ }
148486
+ return lines.join("\n");
148487
+ }
148488
+ async function syncFeaturesToKnowledge(root, graph) {
148489
+ const featuresPath = import_node_path19.default.join(root, ...KNOWLEDGE_FEATURES_PATH_SEGMENTS);
148490
+ if (!(0, import_node_fs12.existsSync)(featuresPath)) {
148491
+ return;
148492
+ }
148493
+ const content3 = buildKnowledgeFeaturesSection(graph);
148494
+ const wrapped = `${FEATURES_MARKER_BEGIN}
148495
+ ${content3.trimEnd()}
148496
+
148497
+ ${FEATURES_MARKER_END}
148498
+ `;
148499
+ const current = await import_promises15.default.readFile(featuresPath, "utf8");
148500
+ const beginIndex = current.indexOf(FEATURES_MARKER_BEGIN);
148501
+ const endIndex = current.indexOf(FEATURES_MARKER_END);
148502
+ if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
148503
+ const replaceEnd = current[endIndex + FEATURES_MARKER_END.length] === "\n" ? endIndex + FEATURES_MARKER_END.length + 1 : endIndex + FEATURES_MARKER_END.length;
148504
+ const next = `${current.slice(0, beginIndex)}${wrapped}${current.slice(replaceEnd)}`;
148505
+ if (next !== current) {
148506
+ await import_promises15.default.writeFile(featuresPath, next, "utf8");
148507
+ }
148508
+ return;
148509
+ }
148510
+ const separator = current.endsWith("\n") ? "\n" : "\n\n";
148511
+ await import_promises15.default.writeFile(featuresPath, `${current}${separator}${wrapped}`, "utf8");
148512
+ }
148513
+ async function writeProjectPlanFiles(root, graph) {
148514
+ const graphPath = resolveProjectPlanGraphPath(root);
148515
+ const markdownPath = resolveProjectPlanMarkdownPath(root);
148516
+ await import_promises15.default.mkdir(import_node_path19.default.dirname(graphPath), {
148517
+ recursive: true
148518
+ });
148519
+ const sortedGraph = sortGraph(graph);
148520
+ await import_promises15.default.writeFile(graphPath, `${JSON.stringify(sortedGraph, null, 2)}
148521
+ `, "utf8");
148522
+ await import_promises15.default.writeFile(markdownPath, await renderProjectPlanMarkdown(root, sortedGraph), "utf8");
148523
+ await syncFeaturesToKnowledge(root, sortedGraph);
148524
+ return {
148525
+ graph: sortedGraph,
148526
+ graphPath,
148527
+ markdownPath
148528
+ };
148529
+ }
148530
+ function buildProjectPlanCheckError(code, message, target) {
148531
+ return {
148532
+ code,
148533
+ message,
148534
+ target
148535
+ };
148536
+ }
148537
+ async function validateProjectPlanGraph(root, graph) {
148538
+ const currentGraph = graph ?? await readProjectPlanGraph(root);
148539
+ const errors = [];
148540
+ const sectionIds = /* @__PURE__ */ new Set();
148541
+ const featureIds = /* @__PURE__ */ new Set();
148542
+ const featureMap = /* @__PURE__ */ new Map();
148543
+ for (const section2 of currentGraph.sections) {
148544
+ if (!section2.id) {
148545
+ errors.push(buildProjectPlanCheckError("section_missing_id", "Project plan section is missing `id`."));
148546
+ continue;
148547
+ }
148548
+ if (sectionIds.has(section2.id)) {
148549
+ errors.push(buildProjectPlanCheckError("duplicate_section", `Duplicate section id "${section2.id}"`, section2.id));
148550
+ continue;
148551
+ }
148552
+ sectionIds.add(section2.id);
148553
+ if (!section2.title.trim()) {
148554
+ errors.push(buildProjectPlanCheckError("section_missing_title", `Section "${section2.id}" is missing a title.`, section2.id));
148555
+ }
148556
+ if (!section2.slug.trim()) {
148557
+ errors.push(buildProjectPlanCheckError("section_missing_slug", `Section "${section2.id}" is missing a slug.`, section2.id));
148558
+ }
148559
+ }
148560
+ const allowedTypes = new Set(PROJECT_TASK_TYPES);
148561
+ const allowedAssignees = new Set(PROJECT_TASK_ASSIGNEES);
148562
+ const allowedStatuses = new Set(PROJECT_TASK_STATUSES);
148563
+ for (const feature of currentGraph.features) {
148564
+ if (!feature.id) {
148565
+ errors.push(buildProjectPlanCheckError("feature_missing_id", "Project plan feature is missing `id`."));
148566
+ continue;
148567
+ }
148568
+ if (featureIds.has(feature.id)) {
148569
+ errors.push(buildProjectPlanCheckError("duplicate_feature", `Duplicate feature id "${feature.id}"`, feature.id));
148570
+ continue;
148571
+ }
148572
+ featureIds.add(feature.id);
148573
+ featureMap.set(feature.id, feature);
148574
+ if (!feature.sectionId) {
148575
+ errors.push(buildProjectPlanCheckError("feature_missing_section", `Feature "${feature.id}" is missing \`sectionId\`.`, feature.id));
148576
+ continue;
148577
+ }
148578
+ if (!sectionIds.has(feature.sectionId)) {
148579
+ errors.push(buildProjectPlanCheckError(
148580
+ "feature_unknown_section",
148581
+ `Feature "${feature.id}" references unknown section "${feature.sectionId}".`,
148582
+ feature.id
148583
+ ));
148584
+ }
148585
+ if (!feature.title.trim()) {
148586
+ errors.push(buildProjectPlanCheckError("feature_missing_title", `Feature "${feature.id}" is missing a title.`, feature.id));
148587
+ }
148588
+ if (!feature.slug.trim()) {
148589
+ errors.push(buildProjectPlanCheckError("feature_missing_slug", `Feature "${feature.id}" is missing a slug.`, feature.id));
148590
+ }
148591
+ }
148592
+ const taskIds = /* @__PURE__ */ new Set();
148593
+ for (const task of currentGraph.tasks) {
148594
+ if (!task.id) {
148595
+ errors.push(buildProjectPlanCheckError("task_missing_id", "Project plan task is missing `id`."));
148596
+ continue;
148597
+ }
148598
+ if (taskIds.has(task.id)) {
148599
+ errors.push(buildProjectPlanCheckError("duplicate_task", `Duplicate task id "${task.id}"`, task.id));
148600
+ continue;
148601
+ }
148602
+ taskIds.add(task.id);
148603
+ const feature = featureMap.get(task.featureId);
148604
+ if (!feature) {
148605
+ errors.push(buildProjectPlanCheckError(
148606
+ "task_unknown_feature",
148607
+ `Task "${task.id}" references unknown feature "${task.featureId}".`,
148608
+ task.id
148609
+ ));
148610
+ continue;
148611
+ }
148612
+ if (!task.title.trim()) {
148613
+ errors.push(buildProjectPlanCheckError("task_missing_title", `Task "${task.id}" is missing a title.`, task.id));
148614
+ }
148615
+ if (!allowedTypes.has(task.type)) {
148616
+ errors.push(buildProjectPlanCheckError(
148617
+ "task_invalid_type",
148618
+ `Task "${task.id}" has invalid type "${task.type}".`,
148619
+ task.id
148620
+ ));
148621
+ }
148622
+ if (!allowedAssignees.has(task.assignee)) {
148623
+ errors.push(buildProjectPlanCheckError(
148624
+ "task_invalid_assignee",
148625
+ `Task "${task.id}" has invalid assignee "${task.assignee}".`,
148626
+ task.id
148627
+ ));
148628
+ }
148629
+ if (!allowedStatuses.has(task.status)) {
148630
+ errors.push(buildProjectPlanCheckError(
148631
+ "task_invalid_status",
148632
+ `Task "${task.id}" has invalid status "${task.status}".`,
148633
+ task.id
148634
+ ));
148635
+ }
148636
+ if (!sectionIds.has(task.sectionId)) {
148637
+ errors.push(buildProjectPlanCheckError(
148638
+ "task_unknown_section",
148639
+ `Task "${task.id}" references unknown section "${task.sectionId}".`,
148640
+ task.id
148641
+ ));
148642
+ }
148643
+ if (task.sectionId !== feature.sectionId) {
148644
+ errors.push(buildProjectPlanCheckError(
148645
+ "task_section_mismatch",
148646
+ `Task "${task.id}" section "${task.sectionId}" does not match feature "${feature.id}" section "${feature.sectionId}".`,
148647
+ task.id
148648
+ ));
148649
+ }
148650
+ }
148651
+ return {
148652
+ ok: errors.length === 0,
148653
+ errors
148654
+ };
148655
+ }
148656
+ async function ensureProjectPlanGraph(root) {
148657
+ const graphPath = resolveProjectPlanGraphPath(root);
148658
+ if (!(0, import_node_fs12.existsSync)(graphPath)) {
148659
+ return writeProjectPlanFiles(root, createEmptyProjectPlanGraph());
148660
+ }
148661
+ const graph = await readProjectPlanGraph(root);
148662
+ return writeProjectPlanFiles(root, graph);
148663
+ }
148664
+ async function upsertProjectPlanSection(params) {
148665
+ const state = await ensureProjectPlanGraph(params.root);
148666
+ const slug = slugify2(params.slug?.trim() || params.title);
148667
+ const sectionId = params.id?.trim() || normalizeSectionId(slug);
148668
+ const graph = state.graph;
148669
+ const existing = graph.sections.find((section2) => section2.id === sectionId) || graph.sections.find((section2) => section2.slug === slug);
148670
+ const nextSection = {
148671
+ id: existing?.id || sectionId,
148672
+ title: params.title.trim(),
148673
+ slug,
148674
+ summary: params.summary?.trim() || ""
148675
+ };
148676
+ const nextSections = existing ? graph.sections.map((section2) => section2.id === existing.id ? nextSection : section2) : [...graph.sections, nextSection];
148677
+ await writeProjectPlanFiles(params.root, {
148678
+ ...graph,
148679
+ sections: nextSections
148680
+ });
148681
+ return nextSection;
148682
+ }
148683
+ async function ensureDefaultProjectPlanSections(root) {
148684
+ const features = await upsertProjectPlanSection({ root, title: "Features", slug: "features" });
148685
+ const testing = await upsertProjectPlanSection({ root, title: "Testing", slug: "testing" });
148686
+ const architecture = await upsertProjectPlanSection({ root, title: "Architecture", slug: "architecture" });
148687
+ const workflows = await upsertProjectPlanSection({ root, title: "Workflows", slug: "workflows" });
148688
+ return {
148689
+ featuresSectionId: features.id,
148690
+ testingSectionId: testing.id,
148691
+ architectureSectionId: architecture.id,
148692
+ workflowsSectionId: workflows.id
148693
+ };
148694
+ }
148695
+ async function upsertProjectPlanFeature(params) {
148696
+ const state = await ensureProjectPlanGraph(params.root);
148697
+ const slug = slugify2(params.slug?.trim() || params.title);
148698
+ const featureId = params.featureId?.trim() || normalizeFeatureId(params.sectionId, slug);
148699
+ const graph = state.graph;
148700
+ const existing = graph.features.find((feature) => feature.id === featureId) || graph.features.find((feature) => feature.sectionId === params.sectionId && feature.slug === slug);
148701
+ const nextFeature = {
148702
+ id: existing?.id || featureId,
148703
+ title: params.title.trim(),
148704
+ slug,
148705
+ summary: params.summary?.trim() || "",
148706
+ sectionId: params.sectionId
148707
+ };
148708
+ const nextFeatures = existing ? graph.features.map((feature) => feature.id === existing.id ? nextFeature : feature) : [...graph.features, nextFeature];
148709
+ await writeProjectPlanFiles(params.root, {
148710
+ ...graph,
148711
+ features: nextFeatures
148712
+ });
148713
+ return nextFeature;
148714
+ }
148715
+ async function getProjectPlanTask(params) {
148716
+ const graph = await readProjectPlanGraph(params.root);
148717
+ const linkedTodos = await listLinkedTodosByTask(params.root);
148718
+ const task = graph.tasks.find((item) => item.id === params.taskId);
148719
+ if (!task) {
148720
+ return null;
148721
+ }
148722
+ const taskLinkedTodos = linkedTodos.get(task.id) || [];
148723
+ return {
148724
+ ...task,
148725
+ linkedTodos: taskLinkedTodos,
148726
+ linkedTodoCount: taskLinkedTodos.length
148727
+ };
148728
+ }
148729
+ async function upsertProjectPlanTask(params) {
148730
+ const state = await ensureProjectPlanGraph(params.root);
148731
+ const graph = state.graph;
148732
+ const feature = graph.features.find((item) => item.id === params.featureId);
148733
+ if (!feature) {
148734
+ throw new Error(`Feature "${params.featureId}" not found.`);
148735
+ }
148736
+ const sectionId = params.sectionId?.trim() || feature.sectionId;
148737
+ const taskId = params.taskId?.trim() || normalizeTaskId(feature.id, params.type, params.title);
148738
+ const existing = graph.tasks.find((task) => task.id === taskId) || graph.tasks.find((task) => task.featureId === feature.id && task.type === params.type && task.title === params.title.trim());
148739
+ const nextTask = {
148740
+ id: existing?.id || taskId,
148741
+ title: params.title.trim(),
148742
+ summary: params.summary?.trim() || "",
148743
+ type: params.type,
148744
+ assignee: params.assignee,
148745
+ status: params.status || "planned",
148746
+ acceptanceCriteria: [...new Set((params.acceptanceCriteria || []).map((item) => item.trim()).filter(Boolean))],
148747
+ featureId: feature.id,
148748
+ sectionId
148749
+ };
148750
+ const nextTasks = existing ? graph.tasks.map((task) => task.id === existing.id ? nextTask : task) : [...graph.tasks, nextTask];
148751
+ await writeProjectPlanFiles(params.root, {
148752
+ ...graph,
148753
+ tasks: nextTasks
148754
+ });
148755
+ return nextTask;
148756
+ }
148757
+ async function updateProjectPlanTaskStatus(params) {
148758
+ const graph = await readProjectPlanGraph(params.root);
148759
+ const task = graph.tasks.find((item) => item.id === params.taskId);
148760
+ if (!task) {
148761
+ throw new Error(`Task "${params.taskId}" not found.`);
148762
+ }
148763
+ const nextTask = {
148764
+ ...task,
148765
+ status: params.status
148766
+ };
148767
+ await writeProjectPlanFiles(params.root, {
148768
+ ...graph,
148769
+ tasks: graph.tasks.map((item) => item.id === task.id ? nextTask : item)
148770
+ });
148771
+ return nextTask;
148772
+ }
148773
+
148728
148774
  // src/knowledge/hook.ts
148729
148775
  function hasWikiLinks(text3) {
148730
148776
  return /\[\[[^\]]+\]\]/u.test(text3);
@@ -148938,6 +148984,17 @@ function serializeMatches(matches) {
148938
148984
  reason: match.reason
148939
148985
  }));
148940
148986
  }
148987
+ async function resolveDocyrusApiAuth(dependencies) {
148988
+ try {
148989
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
148990
+ const profile = await dependencies.authStore.getActiveProfile(apiBaseUrl);
148991
+ if (profile?.accessToken) {
148992
+ return { apiBaseUrl, accessToken: profile.accessToken };
148993
+ }
148994
+ } catch {
148995
+ }
148996
+ return void 0;
148997
+ }
148941
148998
  function createKnowledgeCli(dependencies) {
148942
148999
  const knowledgeCli = Cli_exports.create("knowledge", {
148943
149000
  description: "Docyrus repo knowledge graph commands",
@@ -148964,7 +149021,6 @@ function createKnowledgeCli(dependencies) {
148964
149021
  maybePrintHuman(context, [
148965
149022
  `Knowledge graph ready at ${result.knowledgeDir}`,
148966
149023
  `knowledge.md: ${result.knowledgeFileStatus}`,
148967
- `project-plan: ${result.projectPlanGraphPath}`,
148968
149024
  `AGENTS.md: ${result.agentsStatus}`,
148969
149025
  `CLAUDE.md: ${result.claudeStatus}`,
148970
149026
  `.cursor/rules/docyrus-knowledge.md: ${result.cursorRulesStatus}`,
@@ -148992,10 +149048,8 @@ function createKnowledgeCli(dependencies) {
148992
149048
  root: process.cwd(),
148993
149049
  brief: context.args.brief
148994
149050
  });
148995
- const projectPlan = await syncProjectPlanSectionsFromKnowledge(process.cwd());
148996
149051
  maybePrintHuman(context, [
148997
149052
  `Generated starter knowledge under ${(0, import_node_path20.join)(process.cwd(), "docyrus", "knowledge")}`,
148998
- `project-plan: ${projectPlan.graphPath}`,
148999
149053
  `root: ${result.files.rootKnowledgeStatus}`,
149000
149054
  `architecture: ${result.files.architectureStatus}`,
149001
149055
  `features: ${result.files.featuresStatus}`,
@@ -149020,19 +149074,17 @@ function createKnowledgeCli(dependencies) {
149020
149074
  const codeRefs = await checkKnowledgeCodeRefs(knowledgeContext.knowledgeDir);
149021
149075
  const indexErrors = await checkKnowledgeIndex(knowledgeContext.knowledgeDir);
149022
149076
  const sectionErrors = await checkKnowledgeSections(knowledgeContext.knowledgeDir);
149023
- const projectPlan = await validateProjectPlanGraph(process.cwd());
149024
149077
  const fileStats = { ...markdown.files };
149025
149078
  for (const [extension2, count] of Object.entries(codeRefs.files)) {
149026
149079
  fileStats[extension2] = (fileStats[extension2] || 0) + count;
149027
149080
  }
149028
- const totalErrors = markdown.errors.length + codeRefs.errors.length + indexErrors.length + sectionErrors.length + projectPlan.errors.length;
149081
+ const totalErrors = markdown.errors.length + codeRefs.errors.length + indexErrors.length + sectionErrors.length;
149029
149082
  const human = [
149030
149083
  formatKnowledgeFileStats(fileStats, knowledgeContext.styler),
149031
149084
  ...formatKnowledgeCheckErrors(markdown.errors, knowledgeContext.styler),
149032
149085
  ...formatKnowledgeCheckErrors(codeRefs.errors, knowledgeContext.styler),
149033
149086
  ...formatKnowledgeIndexErrors(indexErrors, knowledgeContext.styler),
149034
149087
  ...formatKnowledgeCheckErrors(sectionErrors, knowledgeContext.styler),
149035
- ...projectPlan.errors.map((error48) => `- ${knowledgeContext.styler.cyan("docyrus/project-plan/project-plan.json")}: ${knowledgeContext.styler.red(error48.message)}`),
149036
149088
  totalErrors === 0 ? knowledgeContext.styler.green("All knowledge checks passed") : knowledgeContext.styler.red(`${totalErrors} error${totalErrors === 1 ? "" : "s"} found`)
149037
149089
  ].join("\n");
149038
149090
  maybePrintHuman(context, human);
@@ -149045,8 +149097,7 @@ function createKnowledgeCli(dependencies) {
149045
149097
  markdown: markdown.errors,
149046
149098
  codeRefs: codeRefs.errors,
149047
149099
  index: indexErrors,
149048
- sections: sectionErrors,
149049
- projectPlan: projectPlan.errors
149100
+ sections: sectionErrors
149050
149101
  },
149051
149102
  files: fileStats,
149052
149103
  ok: totalErrors === 0
@@ -149255,8 +149306,10 @@ function createKnowledgeCli(dependencies) {
149255
149306
  }),
149256
149307
  run: async (context) => {
149257
149308
  const knowledgeContext = await resolveCliKnowledgeContext();
149309
+ const docyrusApi = await resolveDocyrusApiAuth(dependencies);
149258
149310
  const provider = await getKnowledgeSearchProviderInfo({
149259
- settingsRootPath: dependencies.settingsPaths.rootPath
149311
+ settingsRootPath: dependencies.settingsPaths.rootPath,
149312
+ docyrusApi
149260
149313
  });
149261
149314
  if (!provider.provider || !provider.info) {
149262
149315
  throw new UserInputError(provider.error || "No embedding provider is configured.");
@@ -149371,10 +149424,9 @@ function createKnowledgeCli(dependencies) {
149371
149424
  markdown: await checkKnowledgeMarkdown(knowledgeContext.knowledgeDir),
149372
149425
  codeRefs: await checkKnowledgeCodeRefs(knowledgeContext.knowledgeDir),
149373
149426
  index: await checkKnowledgeIndex(knowledgeContext.knowledgeDir),
149374
- sections: await checkKnowledgeSections(knowledgeContext.knowledgeDir),
149375
- projectPlan: await validateProjectPlanGraph(process.cwd())
149427
+ sections: await checkKnowledgeSections(knowledgeContext.knowledgeDir)
149376
149428
  } : null;
149377
- const blockingCheckErrors = checkResult ? checkResult.markdown.errors.length + checkResult.codeRefs.errors.length + checkResult.index.length + checkResult.sections.length + checkResult.projectPlan.errors.length : 0;
149429
+ const blockingCheckErrors = checkResult ? checkResult.markdown.errors.length + checkResult.codeRefs.errors.length + checkResult.index.length + checkResult.sections.length : 0;
149378
149430
  const ok3 = blockingCheckErrors === 0 && audit.blockingErrors.length === 0;
149379
149431
  const payload = {
149380
149432
  ok: ok3,
@@ -149382,8 +149434,7 @@ function createKnowledgeCli(dependencies) {
149382
149434
  markdown: checkResult.markdown.errors,
149383
149435
  codeRefs: checkResult.codeRefs.errors,
149384
149436
  index: checkResult.index,
149385
- sections: checkResult.sections,
149386
- projectPlan: checkResult.projectPlan.errors
149437
+ sections: checkResult.sections
149387
149438
  } : null,
149388
149439
  audit
149389
149440
  };
@@ -149457,10 +149508,8 @@ function createKnowledgeCli(dependencies) {
149457
149508
  brief: context.args.brief,
149458
149509
  targetSectionIds: sectionIds
149459
149510
  });
149460
- const projectPlan = await syncProjectPlanSectionsFromKnowledge(process.cwd());
149461
149511
  maybePrintHuman(context, [
149462
149512
  `Refreshed managed knowledge files.`,
149463
- `project-plan: ${projectPlan.graphPath}`,
149464
149513
  `Targets: ${sectionIds.length > 0 ? sectionIds.join(", ") : "all starter files"}`,
149465
149514
  `root: ${result.files.rootKnowledgeStatus}`,
149466
149515
  `architecture: ${result.files.architectureStatus}`,
@@ -149474,8 +149523,6 @@ function createKnowledgeCli(dependencies) {
149474
149523
  authStore: dependencies.authStore,
149475
149524
  payload: {
149476
149525
  ...result,
149477
- projectPlanGraphPath: projectPlan.graphPath,
149478
- projectPlanMarkdownPath: projectPlan.markdownPath,
149479
149526
  targetSectionIds: sectionIds
149480
149527
  }
149481
149528
  });
@@ -149519,8 +149566,10 @@ function createKnowledgeCli(dependencies) {
149519
149566
  run: async (context) => {
149520
149567
  const projectRoot = findKnowledgeProjectRoot() || process.cwd();
149521
149568
  const knowledgeDir = findKnowledgeDir();
149569
+ const docyrusApi = await resolveDocyrusApiAuth(dependencies);
149522
149570
  const provider = await getKnowledgeSearchProviderInfo({
149523
- settingsRootPath: dependencies.settingsPaths.rootPath
149571
+ settingsRootPath: dependencies.settingsPaths.rootPath,
149572
+ docyrusApi
149524
149573
  });
149525
149574
  const payload = {
149526
149575
  id: (0, import_node_crypto6.randomUUID)(),
@@ -149568,11 +149617,6 @@ function createKnowledgeCli(dependencies) {
149568
149617
  return knowledgeCli;
149569
149618
  }
149570
149619
 
149571
- // src/commands/projectPlanCommands.ts
149572
- var import_node_fs14 = require("node:fs");
149573
- var import_node_path22 = __toESM(require("node:path"));
149574
- init_graph();
149575
-
149576
149620
  // src/project-plan/artifactSync.ts
149577
149621
  var import_node_fs13 = require("node:fs");
149578
149622
  var import_promises16 = __toESM(require("node:fs/promises"));
@@ -149659,7 +149703,7 @@ async function readArchitectPlanJson(artifactDir) {
149659
149703
  return JSON.parse(await import_promises16.default.readFile(jsonPath, "utf8"));
149660
149704
  }
149661
149705
  async function upsertProjectPlanFromPlanArtifact(params) {
149662
- const routes = await resolveDefaultProjectPlanRoutes(params.root);
149706
+ const routes = await ensureDefaultProjectPlanSections(params.root);
149663
149707
  if (!(0, import_node_fs13.existsSync)(params.artifactPath)) {
149664
149708
  return {
149665
149709
  ok: false,
@@ -149765,7 +149809,7 @@ function normalizeArchitectPhaseTitle(phase, fallbackIndex) {
149765
149809
  };
149766
149810
  }
149767
149811
  async function upsertProjectPlanFromArchitectArtifact(params) {
149768
- const routes = await resolveDefaultProjectPlanRoutes(params.root);
149812
+ const routes = await ensureDefaultProjectPlanSections(params.root);
149769
149813
  const warnings = [];
149770
149814
  const updatedFeatureIds = [];
149771
149815
  const updatedTaskIds = [];
@@ -149951,7 +149995,7 @@ function createProjectPlanCli(dependencies) {
149951
149995
  }
149952
149996
  });
149953
149997
  projectPlanCli.command("check", {
149954
- description: "Validate the canonical project plan graph against the knowledge graph",
149998
+ description: "Validate the canonical project plan graph",
149955
149999
  env: EnvSchema,
149956
150000
  outputPolicy: "agent-only",
149957
150001
  run: async (context) => {
@@ -149960,18 +150004,26 @@ function createProjectPlanCli(dependencies) {
149960
150004
  return await wrapPayload(dependencies, result);
149961
150005
  }
149962
150006
  });
149963
- projectPlanCli.command("sync-sections", {
149964
- description: "Seed or re-sync project plan sections from current knowledge section ids",
150007
+ projectPlanCli.command("upsert-section", {
150008
+ description: "Create or update a project plan section",
149965
150009
  env: EnvSchema,
149966
150010
  outputPolicy: "agent-only",
150011
+ options: external_exports.object({
150012
+ id: external_exports.string().optional().describe("Optional existing section id"),
150013
+ title: external_exports.string().min(1).describe("Section title"),
150014
+ slug: external_exports.string().optional().describe("Optional section slug"),
150015
+ summary: external_exports.string().optional().describe("Section summary")
150016
+ }),
149967
150017
  run: async (context) => {
149968
- const result = await syncProjectPlanSectionsFromKnowledge(process.cwd());
149969
- maybePrintHuman2(context, `Synced project plan sections to ${result.graph.sections.length} knowledge section ids.`);
149970
- return await wrapPayload(dependencies, {
149971
- graphPath: result.graphPath,
149972
- markdownPath: result.markdownPath,
149973
- sectionCount: result.graph.sections.length
150018
+ const section2 = await upsertProjectPlanSection({
150019
+ root: process.cwd(),
150020
+ id: context.options.id,
150021
+ title: context.options.title,
150022
+ slug: context.options.slug,
150023
+ summary: context.options.summary
149974
150024
  });
150025
+ maybePrintHuman2(context, `Upserted section ${section2.id}`);
150026
+ return await wrapPayload(dependencies, section2);
149975
150027
  }
149976
150028
  });
149977
150029
  projectPlanCli.command("ensure", {
@@ -149994,7 +150046,7 @@ function createProjectPlanCli(dependencies) {
149994
150046
  outputPolicy: "agent-only",
149995
150047
  options: external_exports.object({
149996
150048
  featureId: external_exports.string().optional().describe("Optional existing feature id"),
149997
- sectionId: external_exports.string().min(1).describe("Knowledge section id"),
150049
+ sectionId: external_exports.string().min(1).describe("Project plan section id"),
149998
150050
  title: external_exports.string().min(1).describe("Feature title"),
149999
150051
  slug: external_exports.string().optional().describe("Optional feature slug"),
150000
150052
  summary: external_exports.string().optional().describe("Feature summary")
@@ -150148,27 +150200,24 @@ function createProjectPlanCli(dependencies) {
150148
150200
  }
150149
150201
  });
150150
150202
  projectPlanCli.command("config", {
150151
- description: "Show resolved project-plan and knowledge graph paths",
150203
+ description: "Show resolved project-plan paths",
150152
150204
  env: EnvSchema,
150153
150205
  outputPolicy: "agent-only",
150154
150206
  run: async (context) => {
150155
150207
  const root = process.cwd();
150156
- const knowledgeDir = import_node_path22.default.join(root, "docyrus", "knowledge");
150157
- const knowledgeSectionCount = (0, import_node_fs14.existsSync)(knowledgeDir) ? flattenSections(await loadAllSections(knowledgeDir)).length : 0;
150208
+ const graph = await readProjectPlanGraph(root);
150158
150209
  const payload = {
150159
150210
  projectRoot: root,
150160
- knowledgeDir: (0, import_node_fs14.existsSync)(knowledgeDir) ? knowledgeDir : null,
150161
150211
  projectPlanDir: resolveProjectPlanDirectory(root),
150162
150212
  graphPath: resolveProjectPlanGraphPath(root),
150163
150213
  markdownPath: resolveProjectPlanMarkdownPath(root),
150164
- knowledgeSectionCount
150214
+ sectionCount: graph.sections.length
150165
150215
  };
150166
150216
  maybePrintHuman2(context, [
150167
- `knowledgeDir: ${payload.knowledgeDir || "(not found)"}`,
150168
150217
  `projectPlanDir: ${payload.projectPlanDir}`,
150169
150218
  `graphPath: ${payload.graphPath}`,
150170
150219
  `markdownPath: ${payload.markdownPath}`,
150171
- `knowledgeSections: ${payload.knowledgeSectionCount}`
150220
+ `sections: ${payload.sectionCount}`
150172
150221
  ].join("\n"));
150173
150222
  return await wrapPayload(dependencies, payload);
150174
150223
  }
@@ -150178,7 +150227,7 @@ function createProjectPlanCli(dependencies) {
150178
150227
 
150179
150228
  // src/services/studioPayload.ts
150180
150229
  var import_promises17 = require("node:fs/promises");
150181
- var import_node_path23 = require("node:path");
150230
+ var import_node_path22 = require("node:path");
150182
150231
  async function readStdinText3() {
150183
150232
  if (process.stdin.isTTY) {
150184
150233
  return "";
@@ -150201,7 +150250,7 @@ async function readStudioWriteInput(params) {
150201
150250
  data,
150202
150251
  fromFile,
150203
150252
  readStdin: readStdin2 = readStdinText3,
150204
- readFileFn = async (path7, encoding) => await (0, import_promises17.readFile)(path7, encoding)
150253
+ readFileFn = async (path6, encoding) => await (0, import_promises17.readFile)(path6, encoding)
150205
150254
  } = params;
150206
150255
  const trimmedData = data?.trim();
150207
150256
  const trimmedFromFile = fromFile?.trim();
@@ -150209,7 +150258,7 @@ async function readStudioWriteInput(params) {
150209
150258
  throw new UserInputError("Provide either --data or --from-file, not both.");
150210
150259
  }
150211
150260
  if (trimmedFromFile) {
150212
- const extension2 = (0, import_node_path23.extname)(trimmedFromFile).toLowerCase();
150261
+ const extension2 = (0, import_node_path22.extname)(trimmedFromFile).toLowerCase();
150213
150262
  if (extension2 && extension2 !== ".json") {
150214
150263
  throw new UserInputError("Studio commands support only JSON files in --from-file.");
150215
150264
  }
@@ -151214,8 +151263,8 @@ function createStudioCli(dependencies) {
151214
151263
 
151215
151264
  // src/commands/tuiCommand.ts
151216
151265
  var import_node_child_process5 = require("node:child_process");
151217
- var import_node_fs15 = require("node:fs");
151218
- var import_node_path24 = require("node:path");
151266
+ var import_node_fs14 = require("node:fs");
151267
+ var import_node_path23 = require("node:path");
151219
151268
  function summarizeFailure2(result) {
151220
151269
  const stderr = result.stderr?.toString().trim();
151221
151270
  if (stderr && stderr.length > 0) {
@@ -151232,23 +151281,23 @@ function summarizeFailure2(result) {
151232
151281
  function resolveCliScriptPath() {
151233
151282
  const argvScript = process.argv[1];
151234
151283
  if (argvScript && argvScript.trim().length > 0) {
151235
- return (0, import_node_path24.isAbsolute)(argvScript) ? argvScript : (0, import_node_path24.resolve)(process.cwd(), argvScript);
151284
+ return (0, import_node_path23.isAbsolute)(argvScript) ? argvScript : (0, import_node_path23.resolve)(process.cwd(), argvScript);
151236
151285
  }
151237
151286
  return __filename;
151238
151287
  }
151239
151288
  function resolveOpenTuiEntryPath(options2 = {}) {
151240
151289
  const cwd = options2.cwd ?? process.cwd();
151241
151290
  const dirname13 = options2.dirname ?? __dirname;
151242
- const fileExists = options2.existsSyncFn ?? import_node_fs15.existsSync;
151291
+ const fileExists = options2.existsSyncFn ?? import_node_fs14.existsSync;
151243
151292
  const candidates = [
151244
151293
  // Source/dev mode in monorepo. Prefer this first so Bun resolves deps via
151245
151294
  // apps/api-cli/node_modules in workspace runs (e.g. `pnpm docyrus tui`).
151246
- (0, import_node_path24.resolve)(cwd, "apps/api-cli/src/tui/opentuiMain.tsx"),
151247
- (0, import_node_path24.resolve)(dirname13, "../tui/opentuiMain.tsx"),
151295
+ (0, import_node_path23.resolve)(cwd, "apps/api-cli/src/tui/opentuiMain.tsx"),
151296
+ (0, import_node_path23.resolve)(dirname13, "../tui/opentuiMain.tsx"),
151248
151297
  // Dist mode (bundled command runtime)
151249
- (0, import_node_path24.resolve)(dirname13, "tui.mjs"),
151250
- (0, import_node_path24.resolve)(dirname13, "../tui.mjs"),
151251
- (0, import_node_path24.resolve)(cwd, "dist/apps/api-cli/tui.mjs")
151298
+ (0, import_node_path23.resolve)(dirname13, "tui.mjs"),
151299
+ (0, import_node_path23.resolve)(dirname13, "../tui.mjs"),
151300
+ (0, import_node_path23.resolve)(cwd, "dist/apps/api-cli/tui.mjs")
151252
151301
  ];
151253
151302
  const resolved = candidates.find((candidate) => fileExists(candidate));
151254
151303
  if (!resolved) {
@@ -151389,7 +151438,7 @@ async function parseResponseBody(response) {
151389
151438
  }
151390
151439
  }
151391
151440
  function normalizeErrorResponse(params) {
151392
- const { status, path: path7, headers, body: body2 } = params;
151441
+ const { status, path: path6, headers, body: body2 } = params;
151393
151442
  const bodyObject = typeof body2 === "object" && body2 !== null ? body2 : null;
151394
151443
  const errorCodeValue = bodyObject?.error;
151395
151444
  const errorDescriptionValue = bodyObject?.error_description ?? bodyObject?.message;
@@ -151399,7 +151448,7 @@ function normalizeErrorResponse(params) {
151399
151448
  status,
151400
151449
  error: errorCode,
151401
151450
  error_description: errorDescription,
151402
- path: path7,
151451
+ path: path6,
151403
151452
  rate_limit_limit: headers.get("ratelimit-limit") || void 0,
151404
151453
  rate_limit_remaining: headers.get("ratelimit-remaining") || void 0,
151405
151454
  rate_limit_reset: headers.get("ratelimit-reset") || void 0,
@@ -151407,13 +151456,13 @@ function normalizeErrorResponse(params) {
151407
151456
  raw: body2
151408
151457
  };
151409
151458
  }
151410
- function normalizePathForUrl(path7) {
151411
- return normalizeApiPath(path7);
151459
+ function normalizePathForUrl(path6) {
151460
+ return normalizeApiPath(path6);
151412
151461
  }
151413
151462
  async function requestDocyrusApi(options2) {
151414
151463
  const {
151415
151464
  baseUrl,
151416
- path: path7,
151465
+ path: path6,
151417
151466
  method = "GET",
151418
151467
  headers,
151419
151468
  query,
@@ -151422,7 +151471,7 @@ async function requestDocyrusApi(options2) {
151422
151471
  fetchFn = fetch
151423
151472
  } = options2;
151424
151473
  const normalizedBaseUrl = normalizeApiBaseUrl(baseUrl);
151425
- const normalizedPath = normalizePathForUrl(path7);
151474
+ const normalizedPath = normalizePathForUrl(path6);
151426
151475
  const url2 = `${normalizedBaseUrl}${normalizedPath}${toQueryString(query)}`;
151427
151476
  const requestHeaders = {
151428
151477
  Accept: "application/json",
@@ -151482,12 +151531,12 @@ var ApiClient = class {
151482
151531
  const {
151483
151532
  authRequired = true,
151484
151533
  method = "GET",
151485
- path: path7,
151534
+ path: path6,
151486
151535
  headers,
151487
151536
  query,
151488
151537
  body: body2
151489
151538
  } = options2;
151490
- if (!path7) {
151539
+ if (!path6) {
151491
151540
  throw new UserInputError("Request path is required.");
151492
151541
  }
151493
151542
  let authToken;
@@ -151497,7 +151546,7 @@ var ApiClient = class {
151497
151546
  return await requestDocyrusApi({
151498
151547
  baseUrl: this.#apiBaseUrl,
151499
151548
  method,
151500
- path: path7,
151549
+ path: path6,
151501
151550
  headers,
151502
151551
  query,
151503
151552
  body: body2,
@@ -152050,7 +152099,7 @@ var AuthSessionService = class {
152050
152099
 
152051
152100
  // src/services/authStore.ts
152052
152101
  var import_promises18 = require("node:fs/promises");
152053
- var import_node_path25 = require("node:path");
152102
+ var import_node_path24 = require("node:path");
152054
152103
  function createEmptyState() {
152055
152104
  return {
152056
152105
  version: 2,
@@ -152126,7 +152175,7 @@ var AuthStore = class {
152126
152175
  });
152127
152176
  }
152128
152177
  const normalized = normalizeState2(validated.data);
152129
- const directory = (0, import_node_path25.dirname)(this.authFilePath);
152178
+ const directory = (0, import_node_path24.dirname)(this.authFilePath);
152130
152179
  await (0, import_promises18.mkdir)(directory, {
152131
152180
  recursive: true,
152132
152181
  mode: 448
@@ -152341,7 +152390,7 @@ var AuthStore = class {
152341
152390
 
152342
152391
  // src/services/environmentConfig.ts
152343
152392
  var import_promises19 = require("node:fs/promises");
152344
- var import_node_path26 = require("node:path");
152393
+ var import_node_path25 = require("node:path");
152345
152394
  var ENVIRONMENT_ID_ALIASES = {
152346
152395
  "local-development": "dev",
152347
152396
  prod: "live"
@@ -152462,7 +152511,7 @@ var EnvironmentConfigService = class {
152462
152511
  });
152463
152512
  }
152464
152513
  const normalized = normalizeState3(validated.data);
152465
- const directory = (0, import_node_path26.dirname)(this.configFilePath);
152514
+ const directory = (0, import_node_path25.dirname)(this.configFilePath);
152466
152515
  await (0, import_promises19.mkdir)(directory, {
152467
152516
  recursive: true,
152468
152517
  mode: 448
@@ -152539,9 +152588,9 @@ var EnvironmentConfigService = class {
152539
152588
 
152540
152589
  // src/services/piAgentLauncher.ts
152541
152590
  var import_node_child_process6 = require("node:child_process");
152542
- var import_node_fs16 = require("node:fs");
152591
+ var import_node_fs15 = require("node:fs");
152543
152592
  var import_promises20 = require("node:fs/promises");
152544
- var import_node_path27 = require("node:path");
152593
+ var import_node_path26 = require("node:path");
152545
152594
 
152546
152595
  // src/services/spinner.ts
152547
152596
  var import_picocolors2 = __toESM(require_picocolors());
@@ -152604,12 +152653,12 @@ function summarizeFailure3(result, commandLabel = "Command") {
152604
152653
  function resolvePackagedPiResourceRoot(options2 = {}) {
152605
152654
  const cwd = options2.cwd ?? process.cwd();
152606
152655
  const dirname13 = options2.dirname ?? __dirname;
152607
- const fileExists = options2.existsSyncFn ?? import_node_fs16.existsSync;
152656
+ const fileExists = options2.existsSyncFn ?? import_node_fs15.existsSync;
152608
152657
  const candidates = [
152609
- (0, import_node_path27.resolve)(cwd, "apps/api-cli/resources/pi-agent"),
152610
- (0, import_node_path27.resolve)(dirname13, "../resources/pi-agent"),
152611
- (0, import_node_path27.resolve)(dirname13, "resources/pi-agent"),
152612
- (0, import_node_path27.resolve)(cwd, "dist/apps/api-cli/resources/pi-agent")
152658
+ (0, import_node_path26.resolve)(cwd, "apps/api-cli/resources/pi-agent"),
152659
+ (0, import_node_path26.resolve)(dirname13, "../resources/pi-agent"),
152660
+ (0, import_node_path26.resolve)(dirname13, "resources/pi-agent"),
152661
+ (0, import_node_path26.resolve)(cwd, "dist/apps/api-cli/resources/pi-agent")
152613
152662
  ];
152614
152663
  const resolved = candidates.find((candidate) => fileExists(candidate));
152615
152664
  if (!resolved) {
@@ -152620,7 +152669,7 @@ function resolvePackagedPiResourceRoot(options2 = {}) {
152620
152669
  function resolveDocyrusPiLoaderEntryPath(options2 = {}) {
152621
152670
  const cwd = options2.cwd ?? process.cwd();
152622
152671
  const dirname13 = options2.dirname ?? __dirname;
152623
- const fileExists = options2.existsSyncFn ?? import_node_fs16.existsSync;
152672
+ const fileExists = options2.existsSyncFn ?? import_node_fs15.existsSync;
152624
152673
  const seen = /* @__PURE__ */ new Set();
152625
152674
  const candidates = options2.candidatePaths ?? [];
152626
152675
  const addCandidate = (candidate) => {
@@ -152630,23 +152679,23 @@ function resolveDocyrusPiLoaderEntryPath(options2 = {}) {
152630
152679
  }
152631
152680
  };
152632
152681
  const collectAncestorCandidates = (startDir) => {
152633
- let currentDir = (0, import_node_path27.resolve)(startDir);
152682
+ let currentDir = (0, import_node_path26.resolve)(startDir);
152634
152683
  while (true) {
152635
- addCandidate((0, import_node_path27.join)(currentDir, "dist", "apps", "api-cli", "agent-loader.js"));
152636
- addCandidate((0, import_node_path27.join)(currentDir, "agent-loader.js"));
152637
- if ((0, import_node_path27.basename)(currentDir) === "dist") {
152638
- addCandidate((0, import_node_path27.join)(currentDir, "apps", "api-cli", "agent-loader.js"));
152684
+ addCandidate((0, import_node_path26.join)(currentDir, "dist", "apps", "api-cli", "agent-loader.js"));
152685
+ addCandidate((0, import_node_path26.join)(currentDir, "agent-loader.js"));
152686
+ if ((0, import_node_path26.basename)(currentDir) === "dist") {
152687
+ addCandidate((0, import_node_path26.join)(currentDir, "apps", "api-cli", "agent-loader.js"));
152639
152688
  }
152640
- const parentDir = (0, import_node_path27.resolve)(currentDir, "..");
152689
+ const parentDir = (0, import_node_path26.resolve)(currentDir, "..");
152641
152690
  if (parentDir === currentDir) {
152642
152691
  break;
152643
152692
  }
152644
152693
  currentDir = parentDir;
152645
152694
  }
152646
152695
  };
152647
- addCandidate((0, import_node_path27.resolve)(cwd, "dist/apps/api-cli/agent-loader.js"));
152648
- addCandidate((0, import_node_path27.resolve)(dirname13, "../agent-loader.js"));
152649
- addCandidate((0, import_node_path27.resolve)(dirname13, "agent-loader.js"));
152696
+ addCandidate((0, import_node_path26.resolve)(cwd, "dist/apps/api-cli/agent-loader.js"));
152697
+ addCandidate((0, import_node_path26.resolve)(dirname13, "../agent-loader.js"));
152698
+ addCandidate((0, import_node_path26.resolve)(dirname13, "agent-loader.js"));
152650
152699
  collectAncestorCandidates(cwd);
152651
152700
  collectAncestorCandidates(dirname13);
152652
152701
  const resolved = candidates.find((candidate) => fileExists(candidate));
@@ -152659,27 +152708,27 @@ function resolveDocyrusCliEntryPath(options2 = {}) {
152659
152708
  const cwd = options2.cwd ?? process.cwd();
152660
152709
  const dirname13 = options2.dirname ?? __dirname;
152661
152710
  const argv = options2.argv ?? process.argv;
152662
- const fileExists = options2.existsSyncFn ?? import_node_fs16.existsSync;
152711
+ const fileExists = options2.existsSyncFn ?? import_node_fs15.existsSync;
152663
152712
  const seen = /* @__PURE__ */ new Set();
152664
152713
  const candidates = options2.candidatePaths ?? [];
152665
152714
  const addCandidate = (candidate) => {
152666
152715
  if (!candidate) {
152667
152716
  return;
152668
152717
  }
152669
- const resolvedCandidate = (0, import_node_path27.resolve)(candidate);
152718
+ const resolvedCandidate = (0, import_node_path26.resolve)(candidate);
152670
152719
  if (!seen.has(resolvedCandidate)) {
152671
152720
  seen.add(resolvedCandidate);
152672
152721
  candidates.push(resolvedCandidate);
152673
152722
  }
152674
152723
  };
152675
152724
  const argvScript = argv[1]?.trim();
152676
- const normalizedArgvScript = argvScript ? argvScript.startsWith("/") ? argvScript : (0, import_node_path27.resolve)(cwd, argvScript) : void 0;
152725
+ const normalizedArgvScript = argvScript ? argvScript.startsWith("/") ? argvScript : (0, import_node_path26.resolve)(cwd, argvScript) : void 0;
152677
152726
  if (normalizedArgvScript && normalizedArgvScript.endsWith(".js")) {
152678
152727
  addCandidate(normalizedArgvScript);
152679
152728
  }
152680
- addCandidate((0, import_node_path27.resolve)(cwd, "dist/apps/api-cli/main.js"));
152681
- addCandidate((0, import_node_path27.resolve)(dirname13, "../main.js"));
152682
- addCandidate((0, import_node_path27.resolve)(dirname13, "main.js"));
152729
+ addCandidate((0, import_node_path26.resolve)(cwd, "dist/apps/api-cli/main.js"));
152730
+ addCandidate((0, import_node_path26.resolve)(dirname13, "../main.js"));
152731
+ addCandidate((0, import_node_path26.resolve)(dirname13, "main.js"));
152683
152732
  if (normalizedArgvScript) {
152684
152733
  addCandidate(normalizedArgvScript);
152685
152734
  }
@@ -152692,7 +152741,7 @@ function resolveDocyrusCliEntryPath(options2 = {}) {
152692
152741
  function resolveInstalledPiPackageRootPath(options2 = {}) {
152693
152742
  const cwd = options2.cwd ?? process.cwd();
152694
152743
  const dirname13 = options2.dirname ?? __dirname;
152695
- const fileExists = options2.existsSyncFn ?? import_node_fs16.existsSync;
152744
+ const fileExists = options2.existsSyncFn ?? import_node_fs15.existsSync;
152696
152745
  const seen = /* @__PURE__ */ new Set();
152697
152746
  const candidates = options2.candidatePaths ?? [];
152698
152747
  const addCandidate = (candidate) => {
@@ -152702,33 +152751,33 @@ function resolveInstalledPiPackageRootPath(options2 = {}) {
152702
152751
  }
152703
152752
  };
152704
152753
  const collectAncestorCandidates = (startDir) => {
152705
- let currentDir = (0, import_node_path27.resolve)(startDir);
152754
+ let currentDir = (0, import_node_path26.resolve)(startDir);
152706
152755
  while (true) {
152707
- addCandidate((0, import_node_path27.join)(currentDir, "node_modules", "@mariozechner", "pi-coding-agent", "package.json"));
152708
- if ((0, import_node_path27.basename)(currentDir) === "node_modules") {
152709
- addCandidate((0, import_node_path27.join)(currentDir, "@mariozechner", "pi-coding-agent", "package.json"));
152756
+ addCandidate((0, import_node_path26.join)(currentDir, "node_modules", "@mariozechner", "pi-coding-agent", "package.json"));
152757
+ if ((0, import_node_path26.basename)(currentDir) === "node_modules") {
152758
+ addCandidate((0, import_node_path26.join)(currentDir, "@mariozechner", "pi-coding-agent", "package.json"));
152710
152759
  }
152711
- const parentDir = (0, import_node_path27.resolve)(currentDir, "..");
152760
+ const parentDir = (0, import_node_path26.resolve)(currentDir, "..");
152712
152761
  if (parentDir === currentDir) {
152713
152762
  break;
152714
152763
  }
152715
152764
  currentDir = parentDir;
152716
152765
  }
152717
152766
  };
152718
- addCandidate((0, import_node_path27.resolve)(cwd, "apps/api-cli/node_modules/@mariozechner/pi-coding-agent/package.json"));
152719
- addCandidate((0, import_node_path27.resolve)(dirname13, "../../../apps/api-cli/node_modules/@mariozechner/pi-coding-agent/package.json"));
152767
+ addCandidate((0, import_node_path26.resolve)(cwd, "apps/api-cli/node_modules/@mariozechner/pi-coding-agent/package.json"));
152768
+ addCandidate((0, import_node_path26.resolve)(dirname13, "../../../apps/api-cli/node_modules/@mariozechner/pi-coding-agent/package.json"));
152720
152769
  collectAncestorCandidates(cwd);
152721
152770
  collectAncestorCandidates(dirname13);
152722
152771
  const resolvedPackageJson = candidates.find((candidate) => fileExists(candidate));
152723
152772
  if (!resolvedPackageJson) {
152724
152773
  throw new UserInputError(`Unable to locate the installed pi package root. Checked: ${candidates.join(", ")}`);
152725
152774
  }
152726
- return (0, import_node_path27.resolve)(resolvedPackageJson, "..");
152775
+ return (0, import_node_path26.resolve)(resolvedPackageJson, "..");
152727
152776
  }
152728
152777
  function createPiAgentRuntimeSkill(params) {
152729
152778
  const commandPrefix = params.scope === "global" ? "docyrus -g" : "docyrus";
152730
- const knowledgeDir = (0, import_node_path27.join)(params.cwd, "docyrus", "knowledge");
152731
- const hasKnowledgeGraph = (0, import_node_fs16.existsSync)(knowledgeDir);
152779
+ const knowledgeDir = (0, import_node_path26.join)(params.cwd, "docyrus", "knowledge");
152780
+ const hasKnowledgeGraph = (0, import_node_fs15.existsSync)(knowledgeDir);
152732
152781
  const authLines = params.activeProfile ? [
152733
152782
  `- email: \`${params.activeProfile.email}\``,
152734
152783
  `- tenant: \`${params.activeProfile.tenantName} (${params.activeProfile.tenantNo})\``,
@@ -152781,8 +152830,8 @@ function createPiAgentRuntimeSkill(params) {
152781
152830
  ].join("\n");
152782
152831
  }
152783
152832
  async function syncPackagedSkills(params) {
152784
- const sourceSkillsRoot = (0, import_node_path27.join)(params.resourceRoot, "skills");
152785
- const targetSkillsRoot = (0, import_node_path27.join)(params.agentRootPath, "skills");
152833
+ const sourceSkillsRoot = (0, import_node_path26.join)(params.resourceRoot, "skills");
152834
+ const targetSkillsRoot = (0, import_node_path26.join)(params.agentRootPath, "skills");
152786
152835
  await (0, import_promises20.mkdir)(targetSkillsRoot, {
152787
152836
  recursive: true,
152788
152837
  mode: 448
@@ -152791,25 +152840,25 @@ async function syncPackagedSkills(params) {
152791
152840
  withFileTypes: true
152792
152841
  });
152793
152842
  await Promise.all(DOCYRUS_MIGRATED_SKILL_NAMES.map(async (skillName) => {
152794
- await (0, import_promises20.rm)((0, import_node_path27.join)(targetSkillsRoot, skillName), {
152843
+ await (0, import_promises20.rm)((0, import_node_path26.join)(targetSkillsRoot, skillName), {
152795
152844
  recursive: true,
152796
152845
  force: true
152797
152846
  });
152798
152847
  }));
152799
152848
  await Promise.all(entries.map(async (entry) => {
152800
- await (0, import_promises20.cp)((0, import_node_path27.join)(sourceSkillsRoot, entry.name), (0, import_node_path27.join)(targetSkillsRoot, entry.name), {
152849
+ await (0, import_promises20.cp)((0, import_node_path26.join)(sourceSkillsRoot, entry.name), (0, import_node_path26.join)(targetSkillsRoot, entry.name), {
152801
152850
  recursive: true,
152802
152851
  force: true
152803
152852
  });
152804
152853
  }));
152805
152854
  }
152806
152855
  async function writeRuntimeSkill(params) {
152807
- const runtimeSkillDir = (0, import_node_path27.join)(params.agentRootPath, "skills", "docyrus-runtime-context");
152856
+ const runtimeSkillDir = (0, import_node_path26.join)(params.agentRootPath, "skills", "docyrus-runtime-context");
152808
152857
  await (0, import_promises20.mkdir)(runtimeSkillDir, {
152809
152858
  recursive: true,
152810
152859
  mode: 448
152811
152860
  });
152812
- await (0, import_promises20.writeFile)((0, import_node_path27.join)(runtimeSkillDir, "SKILL.md"), `${params.content}
152861
+ await (0, import_promises20.writeFile)((0, import_node_path26.join)(runtimeSkillDir, "SKILL.md"), `${params.content}
152813
152862
  `, {
152814
152863
  encoding: "utf8",
152815
152864
  mode: 384
@@ -152822,10 +152871,10 @@ function resolveNpmCommand() {
152822
152871
  return process.platform === "win32" ? "npm.cmd" : "npm";
152823
152872
  }
152824
152873
  function resolveManagedDiffityInstallRoot(agentRootPath) {
152825
- return (0, import_node_path27.join)(agentRootPath, "tools", "diffity");
152874
+ return (0, import_node_path26.join)(agentRootPath, "tools", "diffity");
152826
152875
  }
152827
152876
  function resolveManagedDiffityExecutablePath(agentRootPath) {
152828
- return (0, import_node_path27.join)(
152877
+ return (0, import_node_path26.join)(
152829
152878
  resolveManagedDiffityInstallRoot(agentRootPath),
152830
152879
  "node_modules",
152831
152880
  ".bin",
@@ -152833,10 +152882,10 @@ function resolveManagedDiffityExecutablePath(agentRootPath) {
152833
152882
  );
152834
152883
  }
152835
152884
  function prependPathEntry(entry, existingPath) {
152836
- const values = existingPath ? existingPath.split(import_node_path27.delimiter).filter((value2) => value2.trim().length > 0) : [];
152885
+ const values = existingPath ? existingPath.split(import_node_path26.delimiter).filter((value2) => value2.trim().length > 0) : [];
152837
152886
  const normalizedEntry = entry.trim();
152838
152887
  const remaining = values.filter((value2) => value2 !== normalizedEntry);
152839
- return [normalizedEntry, ...remaining].join(import_node_path27.delimiter);
152888
+ return [normalizedEntry, ...remaining].join(import_node_path26.delimiter);
152840
152889
  }
152841
152890
  function createDocyrusSkillsInstallArgs(scope) {
152842
152891
  const args2 = [
@@ -152874,8 +152923,8 @@ function createPackagedDocyrusPlatformInstallArgs(params) {
152874
152923
  return args2;
152875
152924
  }
152876
152925
  async function installExternalDocyrusSkillsOnce(params) {
152877
- const markerPath = (0, import_node_path27.join)(params.agentRootPath, DOCYRUS_EXTERNAL_SKILL_MARKER_FILE);
152878
- if ((0, import_node_fs16.existsSync)(markerPath)) {
152926
+ const markerPath = (0, import_node_path26.join)(params.agentRootPath, DOCYRUS_EXTERNAL_SKILL_MARKER_FILE);
152927
+ if ((0, import_node_fs15.existsSync)(markerPath)) {
152879
152928
  return;
152880
152929
  }
152881
152930
  const result = params.spawnCommand(resolveNpxCommand(), createDocyrusSkillsInstallArgs(params.scope), {
@@ -152907,8 +152956,8 @@ async function installExternalDocyrusSkillsOnce(params) {
152907
152956
  }
152908
152957
  async function ensureManagedDiffityInstalled(params) {
152909
152958
  const executablePath = resolveManagedDiffityExecutablePath(params.agentRootPath);
152910
- const binDir = (0, import_node_path27.dirname)(executablePath);
152911
- if ((0, import_node_fs16.existsSync)(executablePath)) {
152959
+ const binDir = (0, import_node_path26.dirname)(executablePath);
152960
+ if ((0, import_node_fs15.existsSync)(executablePath)) {
152912
152961
  return {
152913
152962
  available: true,
152914
152963
  executablePath,
@@ -152946,19 +152995,19 @@ async function ensureManagedDiffityInstalled(params) {
152946
152995
  };
152947
152996
  }
152948
152997
  function resolvePackagedDocyrusPlatformSkillPath(resourceRoot) {
152949
- return (0, import_node_path27.join)(resourceRoot, "skills", DOCYRUS_PACKAGED_PLATFORM_SKILL_NAME);
152998
+ return (0, import_node_path26.join)(resourceRoot, "skills", DOCYRUS_PACKAGED_PLATFORM_SKILL_NAME);
152950
152999
  }
152951
153000
  function resolvePackagedOfficeCliRootPath(resourceRoot) {
152952
- return (0, import_node_path27.join)((0, import_node_path27.resolve)(resourceRoot, ".."), "officecli");
153001
+ return (0, import_node_path26.join)((0, import_node_path26.resolve)(resourceRoot, ".."), "officecli");
152953
153002
  }
152954
153003
  function resolvePackagedOfficeCliManifestPath(resourceRoot) {
152955
- return (0, import_node_path27.join)(resolvePackagedOfficeCliRootPath(resourceRoot), DOCYRUS_OFFICECLI_MANIFEST_FILE_NAME);
153004
+ return (0, import_node_path26.join)(resolvePackagedOfficeCliRootPath(resourceRoot), DOCYRUS_OFFICECLI_MANIFEST_FILE_NAME);
152956
153005
  }
152957
153006
  function resolveManagedOfficeCliInstallRoot(agentRootPath) {
152958
- return (0, import_node_path27.join)(agentRootPath, "tools", "officecli");
153007
+ return (0, import_node_path26.join)(agentRootPath, "tools", "officecli");
152959
153008
  }
152960
153009
  function resolveManagedOfficeCliExecutablePath(agentRootPath) {
152961
- return (0, import_node_path27.join)(
153010
+ return (0, import_node_path26.join)(
152962
153011
  resolveManagedOfficeCliInstallRoot(agentRootPath),
152963
153012
  process.platform === "win32" ? "officecli.exe" : "officecli"
152964
153013
  );
@@ -152966,7 +153015,7 @@ function resolveManagedOfficeCliExecutablePath(agentRootPath) {
152966
153015
  function resolveOfficeCliReleaseAssetName(options2 = {}) {
152967
153016
  const platform2 = options2.platform ?? process.platform;
152968
153017
  const arch = options2.arch ?? process.arch;
152969
- const isAlpine = options2.isAlpine ?? (0, import_node_fs16.existsSync)("/etc/alpine-release");
153018
+ const isAlpine = options2.isAlpine ?? (0, import_node_fs15.existsSync)("/etc/alpine-release");
152970
153019
  switch (platform2) {
152971
153020
  case "darwin":
152972
153021
  if (arch === "arm64") {
@@ -153000,7 +153049,7 @@ function resolveOfficeCliReleaseAssetName(options2 = {}) {
153000
153049
  throw new UserInputError(`OfficeCLI is not supported on ${platform2}/${arch}.`);
153001
153050
  }
153002
153051
  function resolvePackagedOfficeCliExecutablePath(resourceRoot, options2) {
153003
- return (0, import_node_path27.join)(
153052
+ return (0, import_node_path26.join)(
153004
153053
  resolvePackagedOfficeCliRootPath(resourceRoot),
153005
153054
  "bundled",
153006
153055
  resolveOfficeCliReleaseAssetName(options2)
@@ -153028,11 +153077,11 @@ async function downloadOfficeCliBinary(params) {
153028
153077
  });
153029
153078
  }
153030
153079
  function resolveManagedOfficeCliConfigMarkerPath(agentRootPath) {
153031
- return (0, import_node_path27.join)(resolveManagedOfficeCliInstallRoot(agentRootPath), ".docyrus-officecli-configured.json");
153080
+ return (0, import_node_path26.join)(resolveManagedOfficeCliInstallRoot(agentRootPath), ".docyrus-officecli-configured.json");
153032
153081
  }
153033
153082
  async function disableManagedOfficeCliAutoUpdate(params) {
153034
153083
  const markerPath = resolveManagedOfficeCliConfigMarkerPath(params.agentRootPath);
153035
- if ((0, import_node_fs16.existsSync)(markerPath)) {
153084
+ if ((0, import_node_fs15.existsSync)(markerPath)) {
153036
153085
  return;
153037
153086
  }
153038
153087
  const result = params.spawnCommand(params.executablePath, ["config", "autoUpdate", "false"], {
@@ -153061,8 +153110,8 @@ async function disableManagedOfficeCliAutoUpdate(params) {
153061
153110
  }
153062
153111
  async function ensureManagedOfficeCliInstalled(params) {
153063
153112
  const executablePath = resolveManagedOfficeCliExecutablePath(params.agentRootPath);
153064
- const binDir = (0, import_node_path27.dirname)(executablePath);
153065
- if ((0, import_node_fs16.existsSync)(executablePath)) {
153113
+ const binDir = (0, import_node_path26.dirname)(executablePath);
153114
+ if ((0, import_node_fs15.existsSync)(executablePath)) {
153066
153115
  await disableManagedOfficeCliAutoUpdate({
153067
153116
  agentRootPath: params.agentRootPath,
153068
153117
  executablePath,
@@ -153082,7 +153131,7 @@ async function ensureManagedOfficeCliInstalled(params) {
153082
153131
  mode: 448
153083
153132
  });
153084
153133
  const bundledExecutablePath = resolvePackagedOfficeCliExecutablePath(params.resourceRoot);
153085
- if ((0, import_node_fs16.existsSync)(bundledExecutablePath)) {
153134
+ if ((0, import_node_fs15.existsSync)(bundledExecutablePath)) {
153086
153135
  await (0, import_promises20.cp)(bundledExecutablePath, tempPath, {
153087
153136
  force: true
153088
153137
  });
@@ -153141,7 +153190,7 @@ async function ensureManagedOfficeCliInstalled(params) {
153141
153190
  }
153142
153191
  function installPackagedDocyrusPlatformSkill(params) {
153143
153192
  const skillSourcePath = resolvePackagedDocyrusPlatformSkillPath(params.resourceRoot);
153144
- if (!(0, import_node_fs16.existsSync)(skillSourcePath)) {
153193
+ if (!(0, import_node_fs15.existsSync)(skillSourcePath)) {
153145
153194
  process.stderr.write("[docyrus] Packaged docyrus-platform skill is missing. Continuing without agent sync.\n");
153146
153195
  return;
153147
153196
  }
@@ -153270,8 +153319,8 @@ function createPiAgentLauncher(options2) {
153270
153319
 
153271
153320
  // src/services/piAgentServerLauncher.ts
153272
153321
  var import_node_child_process7 = require("node:child_process");
153273
- var import_node_fs17 = require("node:fs");
153274
- var import_node_path28 = require("node:path");
153322
+ var import_node_fs16 = require("node:fs");
153323
+ var import_node_path27 = require("node:path");
153275
153324
  function serializePiAgentServerRequest(request) {
153276
153325
  return JSON.stringify(request);
153277
153326
  }
@@ -153285,26 +153334,26 @@ function resolveServerLoaderEntryPath(cwd, dirname13) {
153285
153334
  }
153286
153335
  };
153287
153336
  const collectAncestorCandidates = (startDir) => {
153288
- let currentDir = (0, import_node_path28.resolve)(startDir);
153337
+ let currentDir = (0, import_node_path27.resolve)(startDir);
153289
153338
  while (true) {
153290
- addCandidate((0, import_node_path28.join)(currentDir, "dist", "apps", "api-cli", "server-loader.js"));
153291
- addCandidate((0, import_node_path28.join)(currentDir, "server-loader.js"));
153292
- if ((0, import_node_path28.basename)(currentDir) === "dist") {
153293
- addCandidate((0, import_node_path28.join)(currentDir, "apps", "api-cli", "server-loader.js"));
153339
+ addCandidate((0, import_node_path27.join)(currentDir, "dist", "apps", "api-cli", "server-loader.js"));
153340
+ addCandidate((0, import_node_path27.join)(currentDir, "server-loader.js"));
153341
+ if ((0, import_node_path27.basename)(currentDir) === "dist") {
153342
+ addCandidate((0, import_node_path27.join)(currentDir, "apps", "api-cli", "server-loader.js"));
153294
153343
  }
153295
- const parentDir = (0, import_node_path28.resolve)(currentDir, "..");
153344
+ const parentDir = (0, import_node_path27.resolve)(currentDir, "..");
153296
153345
  if (parentDir === currentDir) {
153297
153346
  break;
153298
153347
  }
153299
153348
  currentDir = parentDir;
153300
153349
  }
153301
153350
  };
153302
- addCandidate((0, import_node_path28.resolve)(cwd, "dist/apps/api-cli/server-loader.js"));
153303
- addCandidate((0, import_node_path28.resolve)(dirname13, "../server-loader.js"));
153304
- addCandidate((0, import_node_path28.resolve)(dirname13, "server-loader.js"));
153351
+ addCandidate((0, import_node_path27.resolve)(cwd, "dist/apps/api-cli/server-loader.js"));
153352
+ addCandidate((0, import_node_path27.resolve)(dirname13, "../server-loader.js"));
153353
+ addCandidate((0, import_node_path27.resolve)(dirname13, "server-loader.js"));
153305
153354
  collectAncestorCandidates(cwd);
153306
153355
  collectAncestorCandidates(dirname13);
153307
- const resolved = candidates.find((candidate) => (0, import_node_fs17.existsSync)(candidate));
153356
+ const resolved = candidates.find((candidate) => (0, import_node_fs16.existsSync)(candidate));
153308
153357
  if (!resolved) {
153309
153358
  throw new UserInputError(`Unable to locate Docyrus pi server loader entry file. Checked: ${candidates.join(", ")}`);
153310
153359
  }
@@ -153422,7 +153471,7 @@ async function runWithIncurSkillsOutOfDateWarningSuppressed(params) {
153422
153471
 
153423
153472
  // src/services/tenantOpenApi.ts
153424
153473
  var import_promises21 = require("node:fs/promises");
153425
- var import_node_path29 = require("node:path");
153474
+ var import_node_path28 = require("node:path");
153426
153475
  function resolveSourceUrl(tenantId, template) {
153427
153476
  return template.replace("{tenantId}", encodeURIComponent(tenantId));
153428
153477
  }
@@ -153447,7 +153496,7 @@ var TenantOpenApiService = class {
153447
153496
  params;
153448
153497
  async #writeOpenApiFile(tenantId, parsedContent) {
153449
153498
  const filePath = this.getTenantOpenApiFilePath(tenantId);
153450
- await (0, import_promises21.mkdir)((0, import_node_path29.dirname)(filePath), {
153499
+ await (0, import_promises21.mkdir)((0, import_node_path28.dirname)(filePath), {
153451
153500
  recursive: true,
153452
153501
  mode: 448
153453
153502
  });
@@ -153493,7 +153542,7 @@ var TenantOpenApiService = class {
153493
153542
  throw new AuthSessionError("Tenant ID is required to resolve OpenAPI spec path.");
153494
153543
  }
153495
153544
  const rootPath = this.params?.rootPath || TENANT_OPENAPI_ROOT_PATH;
153496
- return (0, import_node_path29.join)(rootPath, normalizedTenantId, "openapi.json");
153545
+ return (0, import_node_path28.join)(rootPath, normalizedTenantId, "openapi.json");
153497
153546
  }
153498
153547
  async downloadTenantOpenApi(tenantId, options2 = {}) {
153499
153548
  const normalizedTenantId = tenantId.trim();