heyspex 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/.claude-plugin/marketplace.json +2 -1
  2. package/README.md +11 -0
  3. package/bin/hs-vault-binding.mjs +157 -0
  4. package/bin/hs.mjs +83 -79
  5. package/bin/spexcode.mjs +91 -0
  6. package/dev-factory/engine/worktree.mjs +36 -7
  7. package/dev-factory/lib/epic-detect.mjs +2 -2
  8. package/dev-factory/lib/fleet-readiness.mjs +3 -5
  9. package/dev-factory/lib/fleet-state.mjs +2 -2
  10. package/dev-factory/lib/sufficiency-score.mjs +3 -5
  11. package/dist/cli/hs-check.mjs +76 -46
  12. package/dist/cli/hs-claim.mjs +63 -33
  13. package/dist/cli/hs-connect.mjs +520 -214
  14. package/dist/cli/hs-defer.mjs +161 -19
  15. package/dist/cli/hs-dev.mjs +11 -5
  16. package/dist/cli/hs-env.mjs +187 -161
  17. package/dist/cli/hs-index-rebuild.mjs +123 -78
  18. package/dist/cli/hs-index-reconcile.mjs +203 -107
  19. package/dist/cli/hs-init.mjs +426 -179
  20. package/dist/cli/hs-install.mjs +759 -437
  21. package/dist/cli/hs-join.mjs +590 -383
  22. package/dist/cli/hs-vault-pull.mjs +359 -254
  23. package/dist/cli/hs-vault-push.mjs +151 -113
  24. package/dist/cli/hs-vault.mjs +271 -104
  25. package/dist/cli/hs-workspace.mjs +90 -57
  26. package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +178 -91
  27. package/docs/copilot-plugin-install.md +200 -177
  28. package/docs/driving-heyspex-from-copilot.md +174 -165
  29. package/docs/mcp-client-config.md +93 -25
  30. package/package.json +257 -250
  31. package/plugins/heyspex/.claude-plugin/plugin.json +13 -12
  32. package/plugins/heyspex/.cursor-plugin/plugin.json +16 -15
  33. package/plugins/heyspex/.mcp.json +3 -4
  34. package/plugins/heyspex/README.md +323 -312
  35. package/plugins/heyspex/assets/heyspex-glyph-128.png +0 -0
  36. package/plugins/heyspex/assets/heyspex-glyph-256.png +0 -0
  37. package/plugins/heyspex/assets/heyspex-glyph.svg +12 -0
  38. package/plugins/heyspex/bin/launch-mcp.mjs +21 -7
  39. package/plugins/heyspex/mcp.json +12 -13
  40. package/scripts/check-mcp-freshness.mjs +6 -4
  41. package/scripts/claude-hooks/_intent-classifier-router.mjs +518 -456
  42. package/scripts/claude-hooks/intent-classifier-trigger.mjs +305 -279
  43. package/scripts/claude-hooks/research-method-guard.mjs +2 -2
  44. package/scripts/claude-hooks/wip-checkpoint.mjs +33 -9
  45. package/scripts/claude-statusline/fonts/HeySpexIcons.ttf +0 -0
  46. package/scripts/claude-statusline/statusline-command.mjs +1073 -0
  47. package/scripts/copilot-statusline.mjs +130 -0
  48. package/scripts/dev-server-status.mjs +3 -2
  49. package/scripts/dev-server-stop.mjs +3 -2
  50. package/scripts/hs-capture-cli.mjs +2 -2
  51. package/scripts/hs-settings.mjs +2 -2
  52. package/scripts/hs-view.mjs +3 -2
  53. package/scripts/install-copilot-hooks.mjs +152 -36
  54. package/scripts/lib/copilot-cli.mjs +108 -0
  55. package/scripts/lib/customer-kit.mjs +223 -30
  56. package/scripts/lib/dev-mode.mjs +28 -2
  57. package/scripts/lib/shared-path-helpers.mjs +32 -0
  58. package/scripts/lib/standalone-doctor.mjs +131 -32
  59. package/scripts/wip-ledger-health.mjs +3 -2
  60. package/spexharness/src/gates/vault-mirror-catchup.mjs +113 -24
  61. package/spexharness/src/gates/vault-mirror-catchup.runner.mjs +52 -0
  62. package/spexharness/src/intent-directive.mjs +839 -626
  63. package/spexharness/src/rule-table.mjs +1 -1
  64. package/vendor/heyspex-mcp/cli-verbs.mjs +16 -2
  65. package/vendor/heyspex-mcp/cli.mjs +20 -4
  66. package/vendor/heyspex-mcp/console-fetch.mjs +15 -3
  67. package/vendor/heyspex-mcp/dev-tools.mjs +11 -4
  68. package/vendor/heyspex-mcp/events-tools.mjs +1 -1
  69. package/vendor/heyspex-mcp/factory-run-status.mjs +42 -0
  70. package/vendor/heyspex-mcp/http-transport.mjs +6 -1
  71. package/vendor/heyspex-mcp/mcp-config.mjs +4 -2
  72. package/vendor/heyspex-mcp/server-identity.mjs +13 -0
  73. package/vendor/heyspex-mcp/spec-edit-tools.mjs +26 -1
  74. package/vendor/heyspex-mcp/test-helpers.mjs +5 -2
  75. package/vendor/heyspex-mcp/tool-catalog.mjs +12 -0
  76. package/vendor/heyspex-mcp/tool-dispatch.mjs +63 -23
  77. package/vendor/heyspex-mcp/usable-dir-env.mjs +82 -0
  78. package/vendor/heyspex-mcp/vault-binding.mjs +839 -0
  79. package/vendor/heyspex-mcp/vault-resolve.mjs +353 -245
@@ -112,7 +112,7 @@ var require_main = __commonJS({
112
112
  "node_modules/dotenv/lib/main.js"(exports, module) {
113
113
  "use strict";
114
114
  var fs = __require("fs");
115
- var path7 = __require("path");
115
+ var path8 = __require("path");
116
116
  var os2 = __require("os");
117
117
  var crypto3 = __require("crypto");
118
118
  var packageJson = require_package();
@@ -228,7 +228,7 @@ var require_main = __commonJS({
228
228
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
229
229
  }
230
230
  } else {
231
- possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
231
+ possibleVaultPath = path8.resolve(process.cwd(), ".env.vault");
232
232
  }
233
233
  if (fs.existsSync(possibleVaultPath)) {
234
234
  return possibleVaultPath;
@@ -236,7 +236,7 @@ var require_main = __commonJS({
236
236
  return null;
237
237
  }
238
238
  function _resolveHome(envPath) {
239
- return envPath[0] === "~" ? path7.join(os2.homedir(), envPath.slice(1)) : envPath;
239
+ return envPath[0] === "~" ? path8.join(os2.homedir(), envPath.slice(1)) : envPath;
240
240
  }
241
241
  function _configVault(options) {
242
242
  const debug = Boolean(options && options.debug);
@@ -253,7 +253,7 @@ var require_main = __commonJS({
253
253
  return { parsed };
254
254
  }
255
255
  function configDotenv(options) {
256
- const dotenvPath2 = path7.resolve(process.cwd(), ".env");
256
+ const dotenvPath2 = path8.resolve(process.cwd(), ".env");
257
257
  let encoding = "utf8";
258
258
  const debug = Boolean(options && options.debug);
259
259
  const quiet = options && "quiet" in options ? options.quiet : true;
@@ -277,13 +277,13 @@ var require_main = __commonJS({
277
277
  }
278
278
  let lastError;
279
279
  const parsedAll = {};
280
- for (const path8 of optionPaths) {
280
+ for (const path9 of optionPaths) {
281
281
  try {
282
- const parsed = DotenvModule.parse(fs.readFileSync(path8, { encoding }));
282
+ const parsed = DotenvModule.parse(fs.readFileSync(path9, { encoding }));
283
283
  DotenvModule.populate(parsedAll, parsed, options);
284
284
  } catch (e) {
285
285
  if (debug) {
286
- _debug(`Failed to load ${path8} ${e.message}`);
286
+ _debug(`Failed to load ${path9} ${e.message}`);
287
287
  }
288
288
  lastError = e;
289
289
  }
@@ -298,7 +298,7 @@ var require_main = __commonJS({
298
298
  const shortPaths = [];
299
299
  for (const filePath of optionPaths) {
300
300
  try {
301
- const relative = path7.relative(process.cwd(), filePath);
301
+ const relative = path8.relative(process.cwd(), filePath);
302
302
  shortPaths.push(relative);
303
303
  } catch (e) {
304
304
  if (debug) {
@@ -475,17 +475,17 @@ var require_visit = __commonJS({
475
475
  visit.BREAK = BREAK;
476
476
  visit.SKIP = SKIP;
477
477
  visit.REMOVE = REMOVE;
478
- function visit_(key, node, visitor, path7) {
479
- const ctrl = callVisitor(key, node, visitor, path7);
478
+ function visit_(key, node, visitor, path8) {
479
+ const ctrl = callVisitor(key, node, visitor, path8);
480
480
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
481
- replaceNode(key, path7, ctrl);
482
- return visit_(key, ctrl, visitor, path7);
481
+ replaceNode(key, path8, ctrl);
482
+ return visit_(key, ctrl, visitor, path8);
483
483
  }
484
484
  if (typeof ctrl !== "symbol") {
485
485
  if (identity.isCollection(node)) {
486
- path7 = Object.freeze(path7.concat(node));
486
+ path8 = Object.freeze(path8.concat(node));
487
487
  for (let i = 0; i < node.items.length; ++i) {
488
- const ci = visit_(i, node.items[i], visitor, path7);
488
+ const ci = visit_(i, node.items[i], visitor, path8);
489
489
  if (typeof ci === "number")
490
490
  i = ci - 1;
491
491
  else if (ci === BREAK)
@@ -496,13 +496,13 @@ var require_visit = __commonJS({
496
496
  }
497
497
  }
498
498
  } else if (identity.isPair(node)) {
499
- path7 = Object.freeze(path7.concat(node));
500
- const ck = visit_("key", node.key, visitor, path7);
499
+ path8 = Object.freeze(path8.concat(node));
500
+ const ck = visit_("key", node.key, visitor, path8);
501
501
  if (ck === BREAK)
502
502
  return BREAK;
503
503
  else if (ck === REMOVE)
504
504
  node.key = null;
505
- const cv = visit_("value", node.value, visitor, path7);
505
+ const cv = visit_("value", node.value, visitor, path8);
506
506
  if (cv === BREAK)
507
507
  return BREAK;
508
508
  else if (cv === REMOVE)
@@ -523,17 +523,17 @@ var require_visit = __commonJS({
523
523
  visitAsync.BREAK = BREAK;
524
524
  visitAsync.SKIP = SKIP;
525
525
  visitAsync.REMOVE = REMOVE;
526
- async function visitAsync_(key, node, visitor, path7) {
527
- const ctrl = await callVisitor(key, node, visitor, path7);
526
+ async function visitAsync_(key, node, visitor, path8) {
527
+ const ctrl = await callVisitor(key, node, visitor, path8);
528
528
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
529
- replaceNode(key, path7, ctrl);
530
- return visitAsync_(key, ctrl, visitor, path7);
529
+ replaceNode(key, path8, ctrl);
530
+ return visitAsync_(key, ctrl, visitor, path8);
531
531
  }
532
532
  if (typeof ctrl !== "symbol") {
533
533
  if (identity.isCollection(node)) {
534
- path7 = Object.freeze(path7.concat(node));
534
+ path8 = Object.freeze(path8.concat(node));
535
535
  for (let i = 0; i < node.items.length; ++i) {
536
- const ci = await visitAsync_(i, node.items[i], visitor, path7);
536
+ const ci = await visitAsync_(i, node.items[i], visitor, path8);
537
537
  if (typeof ci === "number")
538
538
  i = ci - 1;
539
539
  else if (ci === BREAK)
@@ -544,13 +544,13 @@ var require_visit = __commonJS({
544
544
  }
545
545
  }
546
546
  } else if (identity.isPair(node)) {
547
- path7 = Object.freeze(path7.concat(node));
548
- const ck = await visitAsync_("key", node.key, visitor, path7);
547
+ path8 = Object.freeze(path8.concat(node));
548
+ const ck = await visitAsync_("key", node.key, visitor, path8);
549
549
  if (ck === BREAK)
550
550
  return BREAK;
551
551
  else if (ck === REMOVE)
552
552
  node.key = null;
553
- const cv = await visitAsync_("value", node.value, visitor, path7);
553
+ const cv = await visitAsync_("value", node.value, visitor, path8);
554
554
  if (cv === BREAK)
555
555
  return BREAK;
556
556
  else if (cv === REMOVE)
@@ -577,23 +577,23 @@ var require_visit = __commonJS({
577
577
  }
578
578
  return visitor;
579
579
  }
580
- function callVisitor(key, node, visitor, path7) {
580
+ function callVisitor(key, node, visitor, path8) {
581
581
  if (typeof visitor === "function")
582
- return visitor(key, node, path7);
582
+ return visitor(key, node, path8);
583
583
  if (identity.isMap(node))
584
- return visitor.Map?.(key, node, path7);
584
+ return visitor.Map?.(key, node, path8);
585
585
  if (identity.isSeq(node))
586
- return visitor.Seq?.(key, node, path7);
586
+ return visitor.Seq?.(key, node, path8);
587
587
  if (identity.isPair(node))
588
- return visitor.Pair?.(key, node, path7);
588
+ return visitor.Pair?.(key, node, path8);
589
589
  if (identity.isScalar(node))
590
- return visitor.Scalar?.(key, node, path7);
590
+ return visitor.Scalar?.(key, node, path8);
591
591
  if (identity.isAlias(node))
592
- return visitor.Alias?.(key, node, path7);
592
+ return visitor.Alias?.(key, node, path8);
593
593
  return void 0;
594
594
  }
595
- function replaceNode(key, path7, node) {
596
- const parent = path7[path7.length - 1];
595
+ function replaceNode(key, path8, node) {
596
+ const parent = path8[path8.length - 1];
597
597
  if (identity.isCollection(parent)) {
598
598
  parent.items[key] = node;
599
599
  } else if (identity.isPair(parent)) {
@@ -1203,10 +1203,10 @@ var require_Collection = __commonJS({
1203
1203
  var createNode = require_createNode();
1204
1204
  var identity = require_identity();
1205
1205
  var Node = require_Node();
1206
- function collectionFromPath(schema, path7, value) {
1206
+ function collectionFromPath(schema, path8, value) {
1207
1207
  let v = value;
1208
- for (let i = path7.length - 1; i >= 0; --i) {
1209
- const k = path7[i];
1208
+ for (let i = path8.length - 1; i >= 0; --i) {
1209
+ const k = path8[i];
1210
1210
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
1211
1211
  const a = [];
1212
1212
  a[k] = v;
@@ -1225,7 +1225,7 @@ var require_Collection = __commonJS({
1225
1225
  sourceObjects: /* @__PURE__ */ new Map()
1226
1226
  });
1227
1227
  }
1228
- var isEmptyPath = (path7) => path7 == null || typeof path7 === "object" && !!path7[Symbol.iterator]().next().done;
1228
+ var isEmptyPath = (path8) => path8 == null || typeof path8 === "object" && !!path8[Symbol.iterator]().next().done;
1229
1229
  var Collection = class extends Node.NodeBase {
1230
1230
  constructor(type, schema) {
1231
1231
  super(type);
@@ -1255,11 +1255,11 @@ var require_Collection = __commonJS({
1255
1255
  * be a Pair instance or a `{ key, value }` object, which may not have a key
1256
1256
  * that already exists in the map.
1257
1257
  */
1258
- addIn(path7, value) {
1259
- if (isEmptyPath(path7))
1258
+ addIn(path8, value) {
1259
+ if (isEmptyPath(path8))
1260
1260
  this.add(value);
1261
1261
  else {
1262
- const [key, ...rest] = path7;
1262
+ const [key, ...rest] = path8;
1263
1263
  const node = this.get(key, true);
1264
1264
  if (identity.isCollection(node))
1265
1265
  node.addIn(rest, value);
@@ -1273,8 +1273,8 @@ var require_Collection = __commonJS({
1273
1273
  * Removes a value from the collection.
1274
1274
  * @returns `true` if the item was found and removed.
1275
1275
  */
1276
- deleteIn(path7) {
1277
- const [key, ...rest] = path7;
1276
+ deleteIn(path8) {
1277
+ const [key, ...rest] = path8;
1278
1278
  if (rest.length === 0)
1279
1279
  return this.delete(key);
1280
1280
  const node = this.get(key, true);
@@ -1288,8 +1288,8 @@ var require_Collection = __commonJS({
1288
1288
  * scalar values from their surrounding node; to disable set `keepScalar` to
1289
1289
  * `true` (collections are always returned intact).
1290
1290
  */
1291
- getIn(path7, keepScalar) {
1292
- const [key, ...rest] = path7;
1291
+ getIn(path8, keepScalar) {
1292
+ const [key, ...rest] = path8;
1293
1293
  const node = this.get(key, true);
1294
1294
  if (rest.length === 0)
1295
1295
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -1307,8 +1307,8 @@ var require_Collection = __commonJS({
1307
1307
  /**
1308
1308
  * Checks if the collection includes a value with the key `key`.
1309
1309
  */
1310
- hasIn(path7) {
1311
- const [key, ...rest] = path7;
1310
+ hasIn(path8) {
1311
+ const [key, ...rest] = path8;
1312
1312
  if (rest.length === 0)
1313
1313
  return this.has(key);
1314
1314
  const node = this.get(key, true);
@@ -1318,8 +1318,8 @@ var require_Collection = __commonJS({
1318
1318
  * Sets a value in this collection. For `!!set`, `value` needs to be a
1319
1319
  * boolean to add/remove the item from the set.
1320
1320
  */
1321
- setIn(path7, value) {
1322
- const [key, ...rest] = path7;
1321
+ setIn(path8, value) {
1322
+ const [key, ...rest] = path8;
1323
1323
  if (rest.length === 0) {
1324
1324
  this.set(key, value);
1325
1325
  } else {
@@ -3834,9 +3834,9 @@ var require_Document = __commonJS({
3834
3834
  this.contents.add(value);
3835
3835
  }
3836
3836
  /** Adds a value to the document. */
3837
- addIn(path7, value) {
3837
+ addIn(path8, value) {
3838
3838
  if (assertCollection(this.contents))
3839
- this.contents.addIn(path7, value);
3839
+ this.contents.addIn(path8, value);
3840
3840
  }
3841
3841
  /**
3842
3842
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3911,14 +3911,14 @@ var require_Document = __commonJS({
3911
3911
  * Removes a value from the document.
3912
3912
  * @returns `true` if the item was found and removed.
3913
3913
  */
3914
- deleteIn(path7) {
3915
- if (Collection.isEmptyPath(path7)) {
3914
+ deleteIn(path8) {
3915
+ if (Collection.isEmptyPath(path8)) {
3916
3916
  if (this.contents == null)
3917
3917
  return false;
3918
3918
  this.contents = null;
3919
3919
  return true;
3920
3920
  }
3921
- return assertCollection(this.contents) ? this.contents.deleteIn(path7) : false;
3921
+ return assertCollection(this.contents) ? this.contents.deleteIn(path8) : false;
3922
3922
  }
3923
3923
  /**
3924
3924
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3933,10 +3933,10 @@ var require_Document = __commonJS({
3933
3933
  * scalar values from their surrounding node; to disable set `keepScalar` to
3934
3934
  * `true` (collections are always returned intact).
3935
3935
  */
3936
- getIn(path7, keepScalar) {
3937
- if (Collection.isEmptyPath(path7))
3936
+ getIn(path8, keepScalar) {
3937
+ if (Collection.isEmptyPath(path8))
3938
3938
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3939
- return identity.isCollection(this.contents) ? this.contents.getIn(path7, keepScalar) : void 0;
3939
+ return identity.isCollection(this.contents) ? this.contents.getIn(path8, keepScalar) : void 0;
3940
3940
  }
3941
3941
  /**
3942
3942
  * Checks if the document includes a value with the key `key`.
@@ -3947,10 +3947,10 @@ var require_Document = __commonJS({
3947
3947
  /**
3948
3948
  * Checks if the document includes a value at `path`.
3949
3949
  */
3950
- hasIn(path7) {
3951
- if (Collection.isEmptyPath(path7))
3950
+ hasIn(path8) {
3951
+ if (Collection.isEmptyPath(path8))
3952
3952
  return this.contents !== void 0;
3953
- return identity.isCollection(this.contents) ? this.contents.hasIn(path7) : false;
3953
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path8) : false;
3954
3954
  }
3955
3955
  /**
3956
3956
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3967,13 +3967,13 @@ var require_Document = __commonJS({
3967
3967
  * Sets a value in this document. For `!!set`, `value` needs to be a
3968
3968
  * boolean to add/remove the item from the set.
3969
3969
  */
3970
- setIn(path7, value) {
3971
- if (Collection.isEmptyPath(path7)) {
3970
+ setIn(path8, value) {
3971
+ if (Collection.isEmptyPath(path8)) {
3972
3972
  this.contents = value;
3973
3973
  } else if (this.contents == null) {
3974
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path7), value);
3974
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path8), value);
3975
3975
  } else if (assertCollection(this.contents)) {
3976
- this.contents.setIn(path7, value);
3976
+ this.contents.setIn(path8, value);
3977
3977
  }
3978
3978
  }
3979
3979
  /**
@@ -5933,9 +5933,9 @@ var require_cst_visit = __commonJS({
5933
5933
  visit.BREAK = BREAK;
5934
5934
  visit.SKIP = SKIP;
5935
5935
  visit.REMOVE = REMOVE;
5936
- visit.itemAtPath = (cst, path7) => {
5936
+ visit.itemAtPath = (cst, path8) => {
5937
5937
  let item = cst;
5938
- for (const [field, index] of path7) {
5938
+ for (const [field, index] of path8) {
5939
5939
  const tok = item?.[field];
5940
5940
  if (tok && "items" in tok) {
5941
5941
  item = tok.items[index];
@@ -5944,23 +5944,23 @@ var require_cst_visit = __commonJS({
5944
5944
  }
5945
5945
  return item;
5946
5946
  };
5947
- visit.parentCollection = (cst, path7) => {
5948
- const parent = visit.itemAtPath(cst, path7.slice(0, -1));
5949
- const field = path7[path7.length - 1][0];
5947
+ visit.parentCollection = (cst, path8) => {
5948
+ const parent = visit.itemAtPath(cst, path8.slice(0, -1));
5949
+ const field = path8[path8.length - 1][0];
5950
5950
  const coll = parent?.[field];
5951
5951
  if (coll && "items" in coll)
5952
5952
  return coll;
5953
5953
  throw new Error("Parent collection not found");
5954
5954
  };
5955
- function _visit(path7, item, visitor) {
5956
- let ctrl = visitor(item, path7);
5955
+ function _visit(path8, item, visitor) {
5956
+ let ctrl = visitor(item, path8);
5957
5957
  if (typeof ctrl === "symbol")
5958
5958
  return ctrl;
5959
5959
  for (const field of ["key", "value"]) {
5960
5960
  const token = item[field];
5961
5961
  if (token && "items" in token) {
5962
5962
  for (let i = 0; i < token.items.length; ++i) {
5963
- const ci = _visit(Object.freeze(path7.concat([[field, i]])), token.items[i], visitor);
5963
+ const ci = _visit(Object.freeze(path8.concat([[field, i]])), token.items[i], visitor);
5964
5964
  if (typeof ci === "number")
5965
5965
  i = ci - 1;
5966
5966
  else if (ci === BREAK)
@@ -5971,10 +5971,10 @@ var require_cst_visit = __commonJS({
5971
5971
  }
5972
5972
  }
5973
5973
  if (typeof ctrl === "function" && field === "key")
5974
- ctrl = ctrl(item, path7);
5974
+ ctrl = ctrl(item, path8);
5975
5975
  }
5976
5976
  }
5977
- return typeof ctrl === "function" ? ctrl(item, path7) : ctrl;
5977
+ return typeof ctrl === "function" ? ctrl(item, path8) : ctrl;
5978
5978
  }
5979
5979
  exports.visit = visit;
5980
5980
  }
@@ -9829,11 +9829,11 @@ var require_baseGet = __commonJS({
9829
9829
  "use strict";
9830
9830
  var castPath = require_castPath();
9831
9831
  var toKey = require_toKey();
9832
- function baseGet(object, path7) {
9833
- path7 = castPath(path7, object);
9834
- var index = 0, length = path7.length;
9832
+ function baseGet(object, path8) {
9833
+ path8 = castPath(path8, object);
9834
+ var index = 0, length = path8.length;
9835
9835
  while (object != null && index < length) {
9836
- object = object[toKey(path7[index++])];
9836
+ object = object[toKey(path8[index++])];
9837
9837
  }
9838
9838
  return index && index == length ? object : void 0;
9839
9839
  }
@@ -9846,8 +9846,8 @@ var require_get = __commonJS({
9846
9846
  "node_modules/lodash/get.js"(exports, module) {
9847
9847
  "use strict";
9848
9848
  var baseGet = require_baseGet();
9849
- function get2(object, path7, defaultValue) {
9850
- var result = object == null ? void 0 : baseGet(object, path7);
9849
+ function get2(object, path8, defaultValue) {
9850
+ var result = object == null ? void 0 : baseGet(object, path8);
9851
9851
  return result === void 0 ? defaultValue : result;
9852
9852
  }
9853
9853
  module.exports = get2;
@@ -21810,14 +21810,16 @@ var init_dev_mode = __esm({
21810
21810
 
21811
21811
  // spex-console/bin/hs-env.ts
21812
21812
  import { spawn } from "node:child_process";
21813
- import { existsSync as existsSync10 } from "node:fs";
21813
+ import { existsSync as existsSync11 } from "node:fs";
21814
21814
  import { networkInterfaces } from "node:os";
21815
- import path6 from "node:path";
21815
+ import path7 from "node:path";
21816
21816
  import process3 from "node:process";
21817
- import { fileURLToPath as fileURLToPath2 } from "node:url";
21817
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
21818
21818
 
21819
21819
  // scripts/lib/shared-path-helpers.mjs
21820
+ import { realpathSync } from "node:fs";
21820
21821
  import { isAbsolute, resolve, sep } from "node:path";
21822
+ import { fileURLToPath } from "node:url";
21821
21823
  function resolveCodeRoot({
21822
21824
  explicit,
21823
21825
  packageRoot,
@@ -26299,17 +26301,17 @@ import { spawnSync as spawnSync2 } from "node:child_process";
26299
26301
  import { randomBytes as randomBytes5 } from "node:crypto";
26300
26302
  import {
26301
26303
  chmodSync,
26302
- existsSync as existsSync9,
26303
- mkdirSync as mkdirSync8,
26304
+ existsSync as existsSync10,
26305
+ mkdirSync as mkdirSync9,
26304
26306
  readdirSync as readdirSync2,
26305
- readFileSync as readFileSync12,
26306
- renameSync as renameSync7,
26307
- statSync as statSync3,
26308
- unlinkSync as unlinkSync3,
26309
- writeFileSync as writeFileSync8
26307
+ readFileSync as readFileSync13,
26308
+ renameSync as renameSync8,
26309
+ statSync as statSync6,
26310
+ unlinkSync as unlinkSync4,
26311
+ writeFileSync as writeFileSync9
26310
26312
  } from "node:fs";
26311
- import { homedir as homedir11 } from "node:os";
26312
- import path5 from "node:path";
26313
+ import { homedir as homedir12 } from "node:os";
26314
+ import path6 from "node:path";
26313
26315
 
26314
26316
  // node_modules/sops-age/dist/index.js
26315
26317
  var import_dotenv = __toESM(require_main(), 1);
@@ -26793,8 +26795,8 @@ function getErrorMap() {
26793
26795
 
26794
26796
  // node_modules/zod/v3/helpers/parseUtil.js
26795
26797
  var makeIssue = (params) => {
26796
- const { data, path: path7, errorMaps, issueData } = params;
26797
- const fullPath = [...path7, ...issueData.path || []];
26798
+ const { data, path: path8, errorMaps, issueData } = params;
26799
+ const fullPath = [...path8, ...issueData.path || []];
26798
26800
  const fullIssue = {
26799
26801
  ...issueData,
26800
26802
  path: fullPath
@@ -26910,11 +26912,11 @@ var errorUtil;
26910
26912
 
26911
26913
  // node_modules/zod/v3/types.js
26912
26914
  var ParseInputLazyPath = class {
26913
- constructor(parent, value, path7, key) {
26915
+ constructor(parent, value, path8, key) {
26914
26916
  this._cachedPath = [];
26915
26917
  this.parent = parent;
26916
26918
  this.data = value;
26917
- this._path = path7;
26919
+ this._path = path8;
26918
26920
  this._key = key;
26919
26921
  }
26920
26922
  get path() {
@@ -34983,18 +34985,18 @@ import { homedir as homedir2, platform } from "node:os";
34983
34985
  import { exec } from "node:child_process";
34984
34986
  import { promisify } from "node:util";
34985
34987
  var import_sshpk = __toESM(require_lib2(), 1);
34986
- async function loadFromFile(path7) {
34988
+ async function loadFromFile(path8) {
34987
34989
  if (globalThis.Deno) {
34988
- return Deno.readTextFile(path7);
34990
+ return Deno.readTextFile(path8);
34989
34991
  }
34990
34992
  if (globalThis.Bun) {
34991
- return Bun.file(path7).text();
34993
+ return Bun.file(path8).text();
34992
34994
  }
34993
34995
  if (typeof process !== "undefined" && process.versions?.node) {
34994
34996
  const fs = await import("fs/promises");
34995
- return fs.readFile(path7, "utf-8");
34997
+ return fs.readFile(path8, "utf-8");
34996
34998
  }
34997
- throw new Error(`Unable to determine method to load file "${path7}"`);
34999
+ throw new Error(`Unable to determine method to load file "${path8}"`);
34998
35000
  }
34999
35001
  function isSopsInput(value) {
35000
35002
  if (!value) {
@@ -35102,13 +35104,13 @@ async function parseSops(input, sopsFileType) {
35102
35104
  });
35103
35105
  }
35104
35106
  }
35105
- async function loadSopsFile(path7, sopsFileType) {
35107
+ async function loadSopsFile(path8, sopsFileType) {
35106
35108
  try {
35107
- const content = await loadFromFile(path7);
35109
+ const content = await loadFromFile(path8);
35108
35110
  return await parseSops(content, sopsFileType);
35109
35111
  } catch (err) {
35110
35112
  throw new Error(
35111
- `Failed to load SOPS file '${path7}': ${err.message}`,
35113
+ `Failed to load SOPS file '${path8}': ${err.message}`,
35112
35114
  {
35113
35115
  cause: err
35114
35116
  }
@@ -35525,15 +35527,15 @@ async function getSopsEncryptionKey(sops, secretKeys) {
35525
35527
  ${errors.join("\n")}`
35526
35528
  );
35527
35529
  }
35528
- function path2gopath(path7) {
35529
- return `${path7.filter((x) => !/^\d+$/.test(x)).join(":")}:`;
35530
+ function path2gopath(path8) {
35531
+ return `${path8.filter((x) => !/^\d+$/.test(x)).join(":")}:`;
35530
35532
  }
35531
- function decryptSOPSValue(ciphertext, decryptionKey, path7) {
35533
+ function decryptSOPSValue(ciphertext, decryptionKey, path8) {
35532
35534
  if (!ciphertext) {
35533
35535
  return "";
35534
35536
  }
35535
35537
  const encryptedValue = parse(ciphertext);
35536
- const aad = path2gopath(path7);
35538
+ const aad = path2gopath(path8);
35537
35539
  let decrypted;
35538
35540
  try {
35539
35541
  decrypted = decryptAesGcm(
@@ -35543,22 +35545,22 @@ function decryptSOPSValue(ciphertext, decryptionKey, path7) {
35543
35545
  );
35544
35546
  } catch (err) {
35545
35547
  throw new Error(
35546
- `AES-GCM decryption failed at path ${JSON.stringify(path7)} for value "${ciphertext}": ${err instanceof Error ? err.message : String(err)}`
35548
+ `AES-GCM decryption failed at path ${JSON.stringify(path8)} for value "${ciphertext}": ${err instanceof Error ? err.message : String(err)}`
35547
35549
  );
35548
35550
  }
35549
35551
  const decryptedValue = new TextDecoder().decode(decrypted);
35550
35552
  return convertDecryptedValue(decryptedValue, encryptedValue.datatype);
35551
35553
  }
35552
- function decryptObject(obj, decryptionKey, path7 = []) {
35554
+ function decryptObject(obj, decryptionKey, path8 = []) {
35553
35555
  if (typeof obj !== "object" || obj === null) {
35554
35556
  return obj;
35555
35557
  }
35556
35558
  for (const key of Object.keys(obj)) {
35557
35559
  const value = obj[key];
35558
35560
  if (typeof value === "string" && value.startsWith("ENC[AES256_GCM,data:")) {
35559
- obj[key] = decryptSOPSValue(value, decryptionKey, [...path7, key]);
35561
+ obj[key] = decryptSOPSValue(value, decryptionKey, [...path8, key]);
35560
35562
  } else if (typeof value === "object") {
35561
- obj[key] = decryptObject(value, decryptionKey, [...path7, key]);
35563
+ obj[key] = decryptObject(value, decryptionKey, [...path8, key]);
35562
35564
  }
35563
35565
  }
35564
35566
  return obj;
@@ -35637,16 +35639,16 @@ import { homedir as homedir6 } from "node:os";
35637
35639
  import { join as join7 } from "node:path";
35638
35640
 
35639
35641
  // spex-console/src/lib/cli/control-shared.ts
35640
- import path4 from "node:path";
35642
+ import path5 from "node:path";
35641
35643
 
35642
35644
  // scripts/lib/hs-command.mjs
35643
35645
  import { existsSync as existsSync5 } from "node:fs";
35644
35646
  import { delimiter, dirname as dirname2, join as join8 } from "node:path";
35645
- import { fileURLToPath } from "node:url";
35647
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
35646
35648
  var HS_BIN_NAME = "hs";
35647
35649
  var HS_DISPATCHER_PATH = (() => {
35648
35650
  try {
35649
- const here = dirname2(fileURLToPath(import.meta.url));
35651
+ const here = dirname2(fileURLToPath2(import.meta.url));
35650
35652
  return join8(dirname2(dirname2(here)), "bin", "hs.mjs");
35651
35653
  } catch {
35652
35654
  return null;
@@ -35660,8 +35662,8 @@ var HS_DISPATCHER_PREFIX = HS_DISPATCHER_PATH ? `node ${shellQuote(HS_DISPATCHER
35660
35662
  // vendor/heyspex-mcp/console-fetch.mjs
35661
35663
  init_heyspex_home();
35662
35664
  init_credentials();
35663
- import { readFileSync as readFileSync10 } from "node:fs";
35664
- import { homedir as homedir9 } from "node:os";
35665
+ import { readFileSync as readFileSync11 } from "node:fs";
35666
+ import { homedir as homedir10 } from "node:os";
35665
35667
  import { join as join12 } from "node:path";
35666
35668
 
35667
35669
  // vendor/heyspex-mcp/session-owner.mjs
@@ -35696,9 +35698,30 @@ import { basename, join as join10, isAbsolute as isAbsolute2 } from "node:path";
35696
35698
 
35697
35699
  // vendor/heyspex-mcp/vault-resolve.mjs
35698
35700
  init_heyspex_home();
35699
- import { existsSync as existsSync7, readFileSync as readFileSync9 } from "node:fs";
35700
- import { homedir as homedir8, tmpdir } from "node:os";
35701
- import { dirname as dirname3, join as join11, resolve as resolve3 } from "node:path";
35701
+ import { existsSync as existsSync8, readFileSync as readFileSync10, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
35702
+ import { homedir as homedir9, tmpdir } from "node:os";
35703
+
35704
+ // vendor/heyspex-mcp/usable-dir-env.mjs
35705
+ import { statSync as statSync3 } from "node:fs";
35706
+ import { isAbsolute as isAbsolute3 } from "node:path";
35707
+
35708
+ // vendor/heyspex-mcp/vault-resolve.mjs
35709
+ import { basename as basename2, dirname as dirname3, join as join11, resolve as resolve3 } from "node:path";
35710
+
35711
+ // vendor/heyspex-mcp/vault-binding.mjs
35712
+ import {
35713
+ copyFileSync,
35714
+ existsSync as existsSync7,
35715
+ mkdirSync as mkdirSync7,
35716
+ readFileSync as readFileSync9,
35717
+ realpathSync as realpathSync2,
35718
+ renameSync as renameSync6,
35719
+ statSync as statSync4,
35720
+ unlinkSync as unlinkSync3,
35721
+ writeFileSync as writeFileSync7
35722
+ } from "node:fs";
35723
+ import { homedir as homedir8 } from "node:os";
35724
+ import path4 from "node:path";
35702
35725
 
35703
35726
  // vendor/heyspex-mcp/console-fetch.mjs
35704
35727
  var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMATCH", "VAULT_NOT_REGISTERED"]);
@@ -35707,11 +35730,11 @@ var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMAT
35707
35730
  init_credentials();
35708
35731
 
35709
35732
  // spex-console/src/lib/vault-registry/registry-file.ts
35710
- import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync6, writeFileSync as writeFileSync7 } from "node:fs";
35733
+ import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync12, renameSync as renameSync7, writeFileSync as writeFileSync8 } from "node:fs";
35711
35734
  import { dirname as dirname4, join as join13, resolve as resolve4 } from "node:path";
35712
35735
 
35713
35736
  // spex-console/src/lib/heyspex-home.ts
35714
- import { homedir as homedir10 } from "node:os";
35737
+ import { homedir as homedir11 } from "node:os";
35715
35738
 
35716
35739
  // spex-console/src/lib/cli/init.ts
35717
35740
  function parseVaultId(content) {
@@ -35746,12 +35769,15 @@ var HELP2 = [
35746
35769
  "(spex-console/src/lib/cli/template-manifest.ts) \u2014 universal docs",
35747
35770
  "copied verbatim, template-shape docs written as author-prompt skeletons \u2014",
35748
35771
  "plus a generated CLAUDE.md, the kept-principles index, and the template_version",
35749
- "pin; with --git, one initial `git init` + commit. Rerunnable: a <dir> that already",
35750
- "holds heyspex.yaml and an empty/placeholder-only specs/ is accepted, existing",
35751
- "files are never overwritten (an existing CLAUDE.md gets a CLAUDE.md.template",
35752
- "beside it), and the result lists each manifest row as created or kept. Refuses a",
35753
- "non-empty <dir> without heyspex.yaml, or a specs/ holding managed specs.",
35754
- "See init.customer-vault.ts.",
35772
+ "pin; with --git, one initial `git init` + commit. On an EXISTING vault (<dir>",
35773
+ "holds heyspex.yaml with a vault_id) it is a REFRESH \u2014 the repair `hs doctor`'s",
35774
+ "vault-template row names: only missing shipped files are added, template_version",
35775
+ "is written/updated in heyspex.yaml (every other byte and the vault_id kept),",
35776
+ "nothing existing is ever overwritten (an existing CLAUDE.md gets a",
35777
+ "CLAUDE.md.template beside it), the result lists each manifest row as created or",
35778
+ "kept, and a second run writes nothing. <dir> may be any path (a satellite repo",
35779
+ "names its vault, e.g. `hs init --customer-vault ../my-specs`). Refuses only a",
35780
+ "non-empty <dir> that has no heyspex.yaml. See init.customer-vault.ts.",
35755
35781
  "",
35756
35782
  "Flags:",
35757
35783
  " --console-url <url> console_url value (default: the mode-aware console --",
@@ -36057,23 +36083,23 @@ function isExpiredDate(expires, today = todayIso()) {
36057
36083
  return expires !== null && today > expires;
36058
36084
  }
36059
36085
  function envDir(vaultRoot) {
36060
- return path5.join(vaultRoot, ".heyspex", "env");
36086
+ return path6.join(vaultRoot, ".heyspex", "env");
36061
36087
  }
36062
36088
  function profilePath(vaultRoot, name) {
36063
- return path5.join(envDir(vaultRoot), `${name}.env`);
36089
+ return path6.join(envDir(vaultRoot), `${name}.env`);
36064
36090
  }
36065
36091
  function keysPath(vaultRoot) {
36066
- return path5.join(vaultRoot, ".heyspex", "env.keys");
36092
+ return path6.join(vaultRoot, ".heyspex", "env.keys");
36067
36093
  }
36068
36094
  function homeKeysPath() {
36069
- return path5.join(process.env.HEYSPEX_ENV_KEYS_HOME || homedir11(), ".heyspex", "env.keys");
36095
+ return path6.join(process.env.HEYSPEX_ENV_KEYS_HOME || homedir12(), ".heyspex", "env.keys");
36070
36096
  }
36071
36097
  function dotenvPath(vaultRoot) {
36072
- return path5.join(vaultRoot, ".env");
36098
+ return path6.join(vaultRoot, ".env");
36073
36099
  }
36074
36100
  function readOrNull(file) {
36075
36101
  try {
36076
- return readFileSync12(file, "utf-8");
36102
+ return readFileSync13(file, "utf-8");
36077
36103
  } catch {
36078
36104
  return null;
36079
36105
  }
@@ -36087,7 +36113,7 @@ function renameWithRetry(tmp, file) {
36087
36113
  const retryable = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES"]);
36088
36114
  for (let attempt = 0; ; attempt++) {
36089
36115
  try {
36090
- renameSync7(tmp, file);
36116
+ renameSync8(tmp, file);
36091
36117
  return;
36092
36118
  } catch (err) {
36093
36119
  const code = err.code ?? "";
@@ -36098,21 +36124,21 @@ function renameWithRetry(tmp, file) {
36098
36124
  }
36099
36125
  function unlinkQuiet(file) {
36100
36126
  try {
36101
- unlinkSync3(file);
36127
+ unlinkSync4(file);
36102
36128
  } catch {
36103
36129
  }
36104
36130
  }
36105
36131
  function atomicWrite(file, content, mode = 420) {
36106
36132
  const secret = mode === SECRET_MODE;
36107
- const dir = path5.dirname(file);
36108
- mkdirSync8(dir, { recursive: true, ...secret ? { mode: SECRET_DIR_MODE } : {} });
36109
- const tmp = path5.join(
36133
+ const dir = path6.dirname(file);
36134
+ mkdirSync9(dir, { recursive: true, ...secret ? { mode: SECRET_DIR_MODE } : {} });
36135
+ const tmp = path6.join(
36110
36136
  dir,
36111
- `.${path5.basename(file)}.${process.pid}.${randomBytes5(4).toString("hex")}.tmp`
36137
+ `.${path6.basename(file)}.${process.pid}.${randomBytes5(4).toString("hex")}.tmp`
36112
36138
  );
36113
36139
  let renamed = false;
36114
36140
  try {
36115
- writeFileSync8(tmp, content, { encoding: "utf-8", mode });
36141
+ writeFileSync9(tmp, content, { encoding: "utf-8", mode });
36116
36142
  if (secret) chmodOwnerOnly(tmp);
36117
36143
  renameWithRetry(tmp, file);
36118
36144
  renamed = true;
@@ -36126,18 +36152,18 @@ var LOCK_RETRY_MS3 = 50;
36126
36152
  var LOCK_STALE_MS3 = 5e3;
36127
36153
  function withFileLock(file, fn) {
36128
36154
  const lock = `${file}.lock`;
36129
- mkdirSync8(path5.dirname(file), { recursive: true, mode: SECRET_DIR_MODE });
36155
+ mkdirSync9(path6.dirname(file), { recursive: true, mode: SECRET_DIR_MODE });
36130
36156
  let held = false;
36131
36157
  for (let attempt = 0; attempt < LOCK_RETRIES && !held; attempt++) {
36132
36158
  try {
36133
- writeFileSync8(lock, `${process.pid}
36159
+ writeFileSync9(lock, `${process.pid}
36134
36160
  `, { flag: "wx" });
36135
36161
  held = true;
36136
36162
  } catch (err) {
36137
36163
  if (err.code !== "EEXIST") throw err;
36138
36164
  let ageMs = Infinity;
36139
36165
  try {
36140
- ageMs = Date.now() - statSync3(lock).mtimeMs;
36166
+ ageMs = Date.now() - statSync6(lock).mtimeMs;
36141
36167
  } catch {
36142
36168
  ageMs = Infinity;
36143
36169
  }
@@ -36179,7 +36205,7 @@ function writeHomeKeyLine(profileName, privateKey, vaultId) {
36179
36205
  }
36180
36206
  function readVaultId(vaultRoot) {
36181
36207
  try {
36182
- const raw = readOrNull(path5.join(vaultRoot, "heyspex.yaml"));
36208
+ const raw = readOrNull(path6.join(vaultRoot, "heyspex.yaml"));
36183
36209
  return raw === null ? null : parseVaultId(raw);
36184
36210
  } catch {
36185
36211
  return null;
@@ -36322,7 +36348,7 @@ function legacyDecryptAllSync(vaultRoot, name) {
36322
36348
  }
36323
36349
  function initProfile(vaultRoot, name = DEFAULT_PROFILE2, opts = {}) {
36324
36350
  const pFile = profilePath(vaultRoot, name);
36325
- if (existsSync9(pFile) && !opts.force) {
36351
+ if (existsSync10(pFile) && !opts.force) {
36326
36352
  throw new EnvVaultConfigError(
36327
36353
  `Env profile "${name}" already exists at ${pFile}. Pass --force to re-key it (this discards existing values and mints a new keypair).`
36328
36354
  );
@@ -36364,7 +36390,7 @@ function saveProfile(vaultRoot, name, profile) {
36364
36390
  function listProfiles(vaultRoot) {
36365
36391
  const dir = envDir(vaultRoot);
36366
36392
  try {
36367
- if (!statSync3(dir).isDirectory()) return [];
36393
+ if (!statSync6(dir).isDirectory()) return [];
36368
36394
  } catch {
36369
36395
  return [];
36370
36396
  }
@@ -36708,7 +36734,7 @@ function removeGrant(vaultRoot, profileName, name, opts = {}) {
36708
36734
  }
36709
36735
  async function exportProfile(vaultRoot, name = DEFAULT_PROFILE2, opts = {}) {
36710
36736
  const target = dotenvPath(vaultRoot);
36711
- if (existsSync9(target) && !opts.force) {
36737
+ if (existsSync10(target) && !opts.force) {
36712
36738
  throw new EnvVaultConfigError(
36713
36739
  `${target} already exists. Pass --force to overwrite it (it is disposable \u2014 the encrypted profile is the system of record).`
36714
36740
  );
@@ -36720,10 +36746,10 @@ async function exportProfile(vaultRoot, name = DEFAULT_PROFILE2, opts = {}) {
36720
36746
  return { path: target };
36721
36747
  }
36722
36748
  function resolveVaultPath(vaultRoot, filePath) {
36723
- const root = path5.resolve(vaultRoot);
36724
- const resolved = path5.resolve(root, filePath);
36725
- const rel = path5.relative(root, resolved);
36726
- if (path5.isAbsolute(filePath) || path5.isAbsolute(rel) || rel === ".." || rel.startsWith(`..${path5.sep}`)) {
36749
+ const root = path6.resolve(vaultRoot);
36750
+ const resolved = path6.resolve(root, filePath);
36751
+ const rel = path6.relative(root, resolved);
36752
+ if (path6.isAbsolute(filePath) || path6.isAbsolute(rel) || rel === ".." || rel.startsWith(`..${path6.sep}`)) {
36727
36753
  throw new EnvVaultConfigError(
36728
36754
  `Refusing to touch "${filePath}" \u2014 it resolves outside the vault root (${root}). Vault file paths must stay inside the repo (no "..", no absolute paths).`
36729
36755
  );
@@ -36737,12 +36763,12 @@ function writeTextFile(vaultRoot, filePath, content) {
36737
36763
  atomicWrite(resolveVaultPath(vaultRoot, filePath), content, SECRET_MODE);
36738
36764
  }
36739
36765
  function pathExists(vaultRoot, filePath) {
36740
- return existsSync9(resolveVaultPath(vaultRoot, filePath));
36766
+ return existsSync10(resolveVaultPath(vaultRoot, filePath));
36741
36767
  }
36742
36768
  function fileMtime(vaultRoot, filePath) {
36743
36769
  const resolved = resolveVaultPath(vaultRoot, filePath);
36744
36770
  try {
36745
- return statSync3(resolved).mtimeMs;
36771
+ return statSync6(resolved).mtimeMs;
36746
36772
  } catch {
36747
36773
  return null;
36748
36774
  }
@@ -36771,7 +36797,7 @@ function listRepoSourceFiles(vaultRoot) {
36771
36797
  for (const entry of entries) {
36772
36798
  const childRel = rel === "" ? entry.name : `${rel}/${entry.name}`;
36773
36799
  if (entry.isDirectory()) {
36774
- if (!WALK_SKIP_DIRS.has(entry.name)) walk(path5.join(dir, entry.name), childRel);
36800
+ if (!WALK_SKIP_DIRS.has(entry.name)) walk(path6.join(dir, entry.name), childRel);
36775
36801
  } else if (entry.isFile()) {
36776
36802
  out.push(childRel);
36777
36803
  }
@@ -36797,7 +36823,7 @@ function isKeysFileGitignored(vaultRoot) {
36797
36823
  if (res.status === 1) return false;
36798
36824
  } catch {
36799
36825
  }
36800
- const gitignore = readOrNull(path5.join(vaultRoot, ".gitignore"));
36826
+ const gitignore = readOrNull(path6.join(vaultRoot, ".gitignore"));
36801
36827
  if (gitignore === null) return false;
36802
36828
  const ignorePatterns = /* @__PURE__ */ new Set([
36803
36829
  ".heyspex/env.keys",
@@ -36857,13 +36883,13 @@ function runEntry(name, main2, options = {}) {
36857
36883
 
36858
36884
  // spex-console/bin/hs-env.ts
36859
36885
  function hsSelfCommand() {
36860
- const here = path6.dirname(fileURLToPath2(import.meta.url));
36886
+ const here = path7.dirname(fileURLToPath3(import.meta.url));
36861
36887
  const pkgRoot = resolveCodeRoot({});
36862
36888
  const candidates = [
36863
- ...pkgRoot ? [path6.join(pkgRoot, "bin", "hs.mjs")] : [],
36864
- path6.resolve(here, "..", "..", "bin", "hs.mjs")
36889
+ ...pkgRoot ? [path7.join(pkgRoot, "bin", "hs.mjs")] : [],
36890
+ path7.resolve(here, "..", "..", "bin", "hs.mjs")
36865
36891
  ];
36866
- const launcher = candidates.find((c) => existsSync10(c));
36892
+ const launcher = candidates.find((c) => existsSync11(c));
36867
36893
  return launcher ? [process3.execPath, launcher] : null;
36868
36894
  }
36869
36895
  var VIRTUAL_ADAPTER = /nordlynx|tailscale|zerotier|hamachi|wireguard|openvpn|proton|tap-|tun\d|vethernet|\bwsl\b|hyper-v|docker|vmware|virtualbox|vbox|utun|bridge/i;