xtrm-tools 2.4.1 → 2.4.3

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 (126) hide show
  1. package/README.md +15 -6
  2. package/cli/dist/index.cjs +738 -239
  3. package/cli/dist/index.cjs.map +1 -1
  4. package/cli/package.json +1 -1
  5. package/config/hooks.json +10 -0
  6. package/config/pi/extensions/core/adapter.ts +2 -14
  7. package/config/pi/extensions/core/guard-rules.ts +70 -0
  8. package/config/pi/extensions/core/session-state.ts +59 -0
  9. package/config/pi/extensions/main-guard.ts +10 -14
  10. package/config/pi/extensions/plan-mode/README.md +65 -0
  11. package/config/pi/extensions/plan-mode/index.ts +340 -0
  12. package/config/pi/extensions/plan-mode/utils.ts +168 -0
  13. package/config/pi/extensions/service-skills.ts +51 -7
  14. package/config/pi/extensions/session-flow.ts +117 -0
  15. package/hooks/beads-claim-sync.mjs +140 -14
  16. package/hooks/beads-compact-restore.mjs +41 -9
  17. package/hooks/beads-compact-save.mjs +36 -5
  18. package/hooks/beads-gate-messages.mjs +27 -1
  19. package/hooks/beads-memory-gate.mjs +24 -16
  20. package/hooks/beads-stop-gate.mjs +58 -8
  21. package/hooks/guard-rules.mjs +117 -0
  22. package/hooks/hooks.json +28 -18
  23. package/hooks/main-guard.mjs +22 -22
  24. package/hooks/quality-check.cjs +1286 -0
  25. package/hooks/quality-check.py +345 -0
  26. package/hooks/session-state.mjs +138 -0
  27. package/package.json +2 -1
  28. package/project-skills/quality-gates/.claude/settings.json +1 -24
  29. package/skills/creating-service-skills/SKILL.md +433 -0
  30. package/skills/creating-service-skills/references/script_quality_standards.md +425 -0
  31. package/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
  32. package/skills/creating-service-skills/scripts/bootstrap.py +326 -0
  33. package/skills/creating-service-skills/scripts/deep_dive.py +304 -0
  34. package/skills/creating-service-skills/scripts/scaffolder.py +482 -0
  35. package/skills/scoping-service-skills/SKILL.md +231 -0
  36. package/skills/scoping-service-skills/scripts/scope.py +74 -0
  37. package/skills/sync-docs/SKILL.md +235 -0
  38. package/skills/sync-docs/evals/evals.json +89 -0
  39. package/skills/sync-docs/references/doc-structure.md +104 -0
  40. package/skills/sync-docs/references/schema.md +103 -0
  41. package/skills/sync-docs/scripts/context_gatherer.py +246 -0
  42. package/skills/sync-docs/scripts/doc_structure_analyzer.py +495 -0
  43. package/skills/sync-docs/scripts/validate_doc.py +365 -0
  44. package/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
  45. package/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
  46. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
  47. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
  48. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
  49. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  50. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
  51. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
  52. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  53. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
  54. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
  55. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
  56. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
  57. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  58. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
  59. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
  60. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
  61. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
  62. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
  63. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
  64. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  65. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
  66. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
  67. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
  68. package/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
  69. package/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
  70. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
  71. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
  72. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
  73. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  74. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
  75. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
  76. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
  77. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
  78. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
  79. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
  80. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  81. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
  82. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
  83. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  84. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
  85. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
  86. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  87. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  88. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
  89. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
  90. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  91. package/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
  92. package/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
  93. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
  94. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
  95. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
  96. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
  97. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
  98. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
  99. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  100. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
  101. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
  102. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
  103. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
  104. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
  105. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
  106. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  107. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
  108. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
  109. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
  110. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
  111. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
  112. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
  113. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
  114. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  115. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
  116. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
  117. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
  118. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  119. package/skills/updating-service-skills/SKILL.md +136 -0
  120. package/skills/updating-service-skills/scripts/drift_detector.py +222 -0
  121. package/skills/using-quality-gates/SKILL.md +254 -0
  122. package/skills/using-service-skills/SKILL.md +108 -0
  123. package/skills/using-service-skills/scripts/cataloger.py +74 -0
  124. package/skills/using-service-skills/scripts/skill_activator.py +152 -0
  125. package/skills/using-service-skills/scripts/test_skill_activator.py +58 -0
  126. package/skills/using-xtrm/SKILL.md +34 -38
@@ -1202,7 +1202,7 @@ var require_command = __commonJS({
1202
1202
  "use strict";
1203
1203
  var EventEmitter2 = require("events").EventEmitter;
1204
1204
  var childProcess = require("child_process");
1205
- var path18 = require("path");
1205
+ var path19 = require("path");
1206
1206
  var fs19 = require("fs");
1207
1207
  var process19 = require("process");
1208
1208
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -2215,9 +2215,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2215
2215
  let launchWithNode = false;
2216
2216
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2217
2217
  function findFile(baseDir, baseName) {
2218
- const localBin = path18.resolve(baseDir, baseName);
2218
+ const localBin = path19.resolve(baseDir, baseName);
2219
2219
  if (fs19.existsSync(localBin)) return localBin;
2220
- if (sourceExt.includes(path18.extname(baseName))) return void 0;
2220
+ if (sourceExt.includes(path19.extname(baseName))) return void 0;
2221
2221
  const foundExt = sourceExt.find(
2222
2222
  (ext) => fs19.existsSync(`${localBin}${ext}`)
2223
2223
  );
@@ -2235,17 +2235,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2235
2235
  } catch {
2236
2236
  resolvedScriptPath = this._scriptPath;
2237
2237
  }
2238
- executableDir = path18.resolve(
2239
- path18.dirname(resolvedScriptPath),
2238
+ executableDir = path19.resolve(
2239
+ path19.dirname(resolvedScriptPath),
2240
2240
  executableDir
2241
2241
  );
2242
2242
  }
2243
2243
  if (executableDir) {
2244
2244
  let localFile = findFile(executableDir, executableFile);
2245
2245
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2246
- const legacyName = path18.basename(
2246
+ const legacyName = path19.basename(
2247
2247
  this._scriptPath,
2248
- path18.extname(this._scriptPath)
2248
+ path19.extname(this._scriptPath)
2249
2249
  );
2250
2250
  if (legacyName !== this._name) {
2251
2251
  localFile = findFile(
@@ -2256,7 +2256,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2256
2256
  }
2257
2257
  executableFile = localFile || executableFile;
2258
2258
  }
2259
- launchWithNode = sourceExt.includes(path18.extname(executableFile));
2259
+ launchWithNode = sourceExt.includes(path19.extname(executableFile));
2260
2260
  let proc;
2261
2261
  if (process19.platform !== "win32") {
2262
2262
  if (launchWithNode) {
@@ -3171,7 +3171,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3171
3171
  * @return {Command}
3172
3172
  */
3173
3173
  nameFromFilename(filename) {
3174
- this._name = path18.basename(filename, path18.extname(filename));
3174
+ this._name = path19.basename(filename, path19.extname(filename));
3175
3175
  return this;
3176
3176
  }
3177
3177
  /**
@@ -3185,9 +3185,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3185
3185
  * @param {string} [path]
3186
3186
  * @return {(string|null|Command)}
3187
3187
  */
3188
- executableDir(path19) {
3189
- if (path19 === void 0) return this._executableDir;
3190
- this._executableDir = path19;
3188
+ executableDir(path20) {
3189
+ if (path20 === void 0) return this._executableDir;
3190
+ this._executableDir = path20;
3191
3191
  return this;
3192
3192
  }
3193
3193
  /**
@@ -3503,7 +3503,7 @@ var require_kleur = __commonJS({
3503
3503
  bgCyan: init2(46, 49),
3504
3504
  bgWhite: init2(47, 49)
3505
3505
  };
3506
- function run2(arr, str) {
3506
+ function run3(arr, str) {
3507
3507
  let i = 0, tmp, beg = "", end = "";
3508
3508
  for (; i < arr.length; i++) {
3509
3509
  tmp = arr[i];
@@ -3554,9 +3554,9 @@ var require_kleur = __commonJS({
3554
3554
  return function(txt) {
3555
3555
  if (this !== void 0 && this.has !== void 0) {
3556
3556
  this.has.includes(open) || (this.has.push(open), this.keys.push(blk));
3557
- return txt === void 0 ? this : $2.enabled ? run2(this.keys, txt + "") : txt + "";
3557
+ return txt === void 0 ? this : $2.enabled ? run3(this.keys, txt + "") : txt + "";
3558
3558
  }
3559
- return txt === void 0 ? chain2([open], [blk]) : $2.enabled ? run2([blk], txt + "") : txt + "";
3559
+ return txt === void 0 ? chain2([open], [blk]) : $2.enabled ? run3([blk], txt + "") : txt + "";
3560
3560
  };
3561
3561
  }
3562
3562
  module2.exports = $2;
@@ -11582,14 +11582,14 @@ var require_polyfills = __commonJS({
11582
11582
  fs19.fstatSync = statFixSync(fs19.fstatSync);
11583
11583
  fs19.lstatSync = statFixSync(fs19.lstatSync);
11584
11584
  if (fs19.chmod && !fs19.lchmod) {
11585
- fs19.lchmod = function(path18, mode, cb) {
11585
+ fs19.lchmod = function(path19, mode, cb) {
11586
11586
  if (cb) process.nextTick(cb);
11587
11587
  };
11588
11588
  fs19.lchmodSync = function() {
11589
11589
  };
11590
11590
  }
11591
11591
  if (fs19.chown && !fs19.lchown) {
11592
- fs19.lchown = function(path18, uid, gid, cb) {
11592
+ fs19.lchown = function(path19, uid, gid, cb) {
11593
11593
  if (cb) process.nextTick(cb);
11594
11594
  };
11595
11595
  fs19.lchownSync = function() {
@@ -11656,9 +11656,9 @@ var require_polyfills = __commonJS({
11656
11656
  };
11657
11657
  })(fs19.readSync);
11658
11658
  function patchLchmod(fs20) {
11659
- fs20.lchmod = function(path18, mode, callback) {
11659
+ fs20.lchmod = function(path19, mode, callback) {
11660
11660
  fs20.open(
11661
- path18,
11661
+ path19,
11662
11662
  constants.O_WRONLY | constants.O_SYMLINK,
11663
11663
  mode,
11664
11664
  function(err, fd) {
@@ -11674,8 +11674,8 @@ var require_polyfills = __commonJS({
11674
11674
  }
11675
11675
  );
11676
11676
  };
11677
- fs20.lchmodSync = function(path18, mode) {
11678
- var fd = fs20.openSync(path18, constants.O_WRONLY | constants.O_SYMLINK, mode);
11677
+ fs20.lchmodSync = function(path19, mode) {
11678
+ var fd = fs20.openSync(path19, constants.O_WRONLY | constants.O_SYMLINK, mode);
11679
11679
  var threw = true;
11680
11680
  var ret;
11681
11681
  try {
@@ -11696,8 +11696,8 @@ var require_polyfills = __commonJS({
11696
11696
  }
11697
11697
  function patchLutimes(fs20) {
11698
11698
  if (constants.hasOwnProperty("O_SYMLINK") && fs20.futimes) {
11699
- fs20.lutimes = function(path18, at, mt, cb) {
11700
- fs20.open(path18, constants.O_SYMLINK, function(er, fd) {
11699
+ fs20.lutimes = function(path19, at, mt, cb) {
11700
+ fs20.open(path19, constants.O_SYMLINK, function(er, fd) {
11701
11701
  if (er) {
11702
11702
  if (cb) cb(er);
11703
11703
  return;
@@ -11709,8 +11709,8 @@ var require_polyfills = __commonJS({
11709
11709
  });
11710
11710
  });
11711
11711
  };
11712
- fs20.lutimesSync = function(path18, at, mt) {
11713
- var fd = fs20.openSync(path18, constants.O_SYMLINK);
11712
+ fs20.lutimesSync = function(path19, at, mt) {
11713
+ var fd = fs20.openSync(path19, constants.O_SYMLINK);
11714
11714
  var ret;
11715
11715
  var threw = true;
11716
11716
  try {
@@ -11829,11 +11829,11 @@ var require_legacy_streams = __commonJS({
11829
11829
  ReadStream,
11830
11830
  WriteStream
11831
11831
  };
11832
- function ReadStream(path18, options) {
11833
- if (!(this instanceof ReadStream)) return new ReadStream(path18, options);
11832
+ function ReadStream(path19, options) {
11833
+ if (!(this instanceof ReadStream)) return new ReadStream(path19, options);
11834
11834
  Stream.call(this);
11835
11835
  var self = this;
11836
- this.path = path18;
11836
+ this.path = path19;
11837
11837
  this.fd = null;
11838
11838
  this.readable = true;
11839
11839
  this.paused = false;
@@ -11878,10 +11878,10 @@ var require_legacy_streams = __commonJS({
11878
11878
  self._read();
11879
11879
  });
11880
11880
  }
11881
- function WriteStream(path18, options) {
11882
- if (!(this instanceof WriteStream)) return new WriteStream(path18, options);
11881
+ function WriteStream(path19, options) {
11882
+ if (!(this instanceof WriteStream)) return new WriteStream(path19, options);
11883
11883
  Stream.call(this);
11884
- this.path = path18;
11884
+ this.path = path19;
11885
11885
  this.fd = null;
11886
11886
  this.writable = true;
11887
11887
  this.flags = "w";
@@ -12025,14 +12025,14 @@ var require_graceful_fs = __commonJS({
12025
12025
  fs20.createWriteStream = createWriteStream2;
12026
12026
  var fs$readFile = fs20.readFile;
12027
12027
  fs20.readFile = readFile;
12028
- function readFile(path18, options, cb) {
12028
+ function readFile(path19, options, cb) {
12029
12029
  if (typeof options === "function")
12030
12030
  cb = options, options = null;
12031
- return go$readFile(path18, options, cb);
12032
- function go$readFile(path19, options2, cb2, startTime) {
12033
- return fs$readFile(path19, options2, function(err) {
12031
+ return go$readFile(path19, options, cb);
12032
+ function go$readFile(path20, options2, cb2, startTime) {
12033
+ return fs$readFile(path20, options2, function(err) {
12034
12034
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
12035
- enqueue([go$readFile, [path19, options2, cb2], err, startTime || Date.now(), Date.now()]);
12035
+ enqueue([go$readFile, [path20, options2, cb2], err, startTime || Date.now(), Date.now()]);
12036
12036
  else {
12037
12037
  if (typeof cb2 === "function")
12038
12038
  cb2.apply(this, arguments);
@@ -12042,14 +12042,14 @@ var require_graceful_fs = __commonJS({
12042
12042
  }
12043
12043
  var fs$writeFile = fs20.writeFile;
12044
12044
  fs20.writeFile = writeFile;
12045
- function writeFile(path18, data, options, cb) {
12045
+ function writeFile(path19, data, options, cb) {
12046
12046
  if (typeof options === "function")
12047
12047
  cb = options, options = null;
12048
- return go$writeFile(path18, data, options, cb);
12049
- function go$writeFile(path19, data2, options2, cb2, startTime) {
12050
- return fs$writeFile(path19, data2, options2, function(err) {
12048
+ return go$writeFile(path19, data, options, cb);
12049
+ function go$writeFile(path20, data2, options2, cb2, startTime) {
12050
+ return fs$writeFile(path20, data2, options2, function(err) {
12051
12051
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
12052
- enqueue([go$writeFile, [path19, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
12052
+ enqueue([go$writeFile, [path20, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
12053
12053
  else {
12054
12054
  if (typeof cb2 === "function")
12055
12055
  cb2.apply(this, arguments);
@@ -12060,14 +12060,14 @@ var require_graceful_fs = __commonJS({
12060
12060
  var fs$appendFile = fs20.appendFile;
12061
12061
  if (fs$appendFile)
12062
12062
  fs20.appendFile = appendFile;
12063
- function appendFile(path18, data, options, cb) {
12063
+ function appendFile(path19, data, options, cb) {
12064
12064
  if (typeof options === "function")
12065
12065
  cb = options, options = null;
12066
- return go$appendFile(path18, data, options, cb);
12067
- function go$appendFile(path19, data2, options2, cb2, startTime) {
12068
- return fs$appendFile(path19, data2, options2, function(err) {
12066
+ return go$appendFile(path19, data, options, cb);
12067
+ function go$appendFile(path20, data2, options2, cb2, startTime) {
12068
+ return fs$appendFile(path20, data2, options2, function(err) {
12069
12069
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
12070
- enqueue([go$appendFile, [path19, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
12070
+ enqueue([go$appendFile, [path20, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
12071
12071
  else {
12072
12072
  if (typeof cb2 === "function")
12073
12073
  cb2.apply(this, arguments);
@@ -12098,31 +12098,31 @@ var require_graceful_fs = __commonJS({
12098
12098
  var fs$readdir = fs20.readdir;
12099
12099
  fs20.readdir = readdir;
12100
12100
  var noReaddirOptionVersions = /^v[0-5]\./;
12101
- function readdir(path18, options, cb) {
12101
+ function readdir(path19, options, cb) {
12102
12102
  if (typeof options === "function")
12103
12103
  cb = options, options = null;
12104
- var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path19, options2, cb2, startTime) {
12105
- return fs$readdir(path19, fs$readdirCallback(
12106
- path19,
12104
+ var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path20, options2, cb2, startTime) {
12105
+ return fs$readdir(path20, fs$readdirCallback(
12106
+ path20,
12107
12107
  options2,
12108
12108
  cb2,
12109
12109
  startTime
12110
12110
  ));
12111
- } : function go$readdir2(path19, options2, cb2, startTime) {
12112
- return fs$readdir(path19, options2, fs$readdirCallback(
12113
- path19,
12111
+ } : function go$readdir2(path20, options2, cb2, startTime) {
12112
+ return fs$readdir(path20, options2, fs$readdirCallback(
12113
+ path20,
12114
12114
  options2,
12115
12115
  cb2,
12116
12116
  startTime
12117
12117
  ));
12118
12118
  };
12119
- return go$readdir(path18, options, cb);
12120
- function fs$readdirCallback(path19, options2, cb2, startTime) {
12119
+ return go$readdir(path19, options, cb);
12120
+ function fs$readdirCallback(path20, options2, cb2, startTime) {
12121
12121
  return function(err, files) {
12122
12122
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
12123
12123
  enqueue([
12124
12124
  go$readdir,
12125
- [path19, options2, cb2],
12125
+ [path20, options2, cb2],
12126
12126
  err,
12127
12127
  startTime || Date.now(),
12128
12128
  Date.now()
@@ -12193,7 +12193,7 @@ var require_graceful_fs = __commonJS({
12193
12193
  enumerable: true,
12194
12194
  configurable: true
12195
12195
  });
12196
- function ReadStream(path18, options) {
12196
+ function ReadStream(path19, options) {
12197
12197
  if (this instanceof ReadStream)
12198
12198
  return fs$ReadStream.apply(this, arguments), this;
12199
12199
  else
@@ -12213,7 +12213,7 @@ var require_graceful_fs = __commonJS({
12213
12213
  }
12214
12214
  });
12215
12215
  }
12216
- function WriteStream(path18, options) {
12216
+ function WriteStream(path19, options) {
12217
12217
  if (this instanceof WriteStream)
12218
12218
  return fs$WriteStream.apply(this, arguments), this;
12219
12219
  else
@@ -12231,22 +12231,22 @@ var require_graceful_fs = __commonJS({
12231
12231
  }
12232
12232
  });
12233
12233
  }
12234
- function createReadStream(path18, options) {
12235
- return new fs20.ReadStream(path18, options);
12234
+ function createReadStream(path19, options) {
12235
+ return new fs20.ReadStream(path19, options);
12236
12236
  }
12237
- function createWriteStream2(path18, options) {
12238
- return new fs20.WriteStream(path18, options);
12237
+ function createWriteStream2(path19, options) {
12238
+ return new fs20.WriteStream(path19, options);
12239
12239
  }
12240
12240
  var fs$open = fs20.open;
12241
12241
  fs20.open = open;
12242
- function open(path18, flags, mode, cb) {
12242
+ function open(path19, flags, mode, cb) {
12243
12243
  if (typeof mode === "function")
12244
12244
  cb = mode, mode = null;
12245
- return go$open(path18, flags, mode, cb);
12246
- function go$open(path19, flags2, mode2, cb2, startTime) {
12247
- return fs$open(path19, flags2, mode2, function(err, fd) {
12245
+ return go$open(path19, flags, mode, cb);
12246
+ function go$open(path20, flags2, mode2, cb2, startTime) {
12247
+ return fs$open(path20, flags2, mode2, function(err, fd) {
12248
12248
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
12249
- enqueue([go$open, [path19, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
12249
+ enqueue([go$open, [path20, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
12250
12250
  else {
12251
12251
  if (typeof cb2 === "function")
12252
12252
  cb2.apply(this, arguments);
@@ -12429,10 +12429,10 @@ var require_fs = __commonJS({
12429
12429
  var require_utils = __commonJS({
12430
12430
  "node_modules/fs-extra/lib/mkdirs/utils.js"(exports2, module2) {
12431
12431
  "use strict";
12432
- var path18 = require("path");
12432
+ var path19 = require("path");
12433
12433
  module2.exports.checkPath = function checkPath(pth) {
12434
12434
  if (process.platform === "win32") {
12435
- const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path18.parse(pth).root, ""));
12435
+ const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path19.parse(pth).root, ""));
12436
12436
  if (pathHasInvalidWinCharacters) {
12437
12437
  const error49 = new Error(`Path contains invalid characters: ${pth}`);
12438
12438
  error49.code = "EINVAL";
@@ -12496,8 +12496,8 @@ var require_path_exists = __commonJS({
12496
12496
  "use strict";
12497
12497
  var u = require_universalify().fromPromise;
12498
12498
  var fs19 = require_fs();
12499
- function pathExists(path18) {
12500
- return fs19.access(path18).then(() => true).catch(() => false);
12499
+ function pathExists(path19) {
12500
+ return fs19.access(path19).then(() => true).catch(() => false);
12501
12501
  }
12502
12502
  module2.exports = {
12503
12503
  pathExists: u(pathExists),
@@ -12512,8 +12512,8 @@ var require_utimes = __commonJS({
12512
12512
  "use strict";
12513
12513
  var fs19 = require_fs();
12514
12514
  var u = require_universalify().fromPromise;
12515
- async function utimesMillis(path18, atime, mtime) {
12516
- const fd = await fs19.open(path18, "r+");
12515
+ async function utimesMillis(path19, atime, mtime) {
12516
+ const fd = await fs19.open(path19, "r+");
12517
12517
  let closeErr = null;
12518
12518
  try {
12519
12519
  await fs19.futimes(fd, atime, mtime);
@@ -12528,8 +12528,8 @@ var require_utimes = __commonJS({
12528
12528
  throw closeErr;
12529
12529
  }
12530
12530
  }
12531
- function utimesMillisSync(path18, atime, mtime) {
12532
- const fd = fs19.openSync(path18, "r+");
12531
+ function utimesMillisSync(path19, atime, mtime) {
12532
+ const fd = fs19.openSync(path19, "r+");
12533
12533
  fs19.futimesSync(fd, atime, mtime);
12534
12534
  return fs19.closeSync(fd);
12535
12535
  }
@@ -12545,7 +12545,7 @@ var require_stat = __commonJS({
12545
12545
  "node_modules/fs-extra/lib/util/stat.js"(exports2, module2) {
12546
12546
  "use strict";
12547
12547
  var fs19 = require_fs();
12548
- var path18 = require("path");
12548
+ var path19 = require("path");
12549
12549
  var u = require_universalify().fromPromise;
12550
12550
  function getStats(src, dest, opts) {
12551
12551
  const statFunc = opts.dereference ? (file2) => fs19.stat(file2, { bigint: true }) : (file2) => fs19.lstat(file2, { bigint: true });
@@ -12573,8 +12573,8 @@ var require_stat = __commonJS({
12573
12573
  const { srcStat, destStat } = await getStats(src, dest, opts);
12574
12574
  if (destStat) {
12575
12575
  if (areIdentical(srcStat, destStat)) {
12576
- const srcBaseName = path18.basename(src);
12577
- const destBaseName = path18.basename(dest);
12576
+ const srcBaseName = path19.basename(src);
12577
+ const destBaseName = path19.basename(dest);
12578
12578
  if (funcName === "move" && srcBaseName !== destBaseName && srcBaseName.toLowerCase() === destBaseName.toLowerCase()) {
12579
12579
  return { srcStat, destStat, isChangingCase: true };
12580
12580
  }
@@ -12596,8 +12596,8 @@ var require_stat = __commonJS({
12596
12596
  const { srcStat, destStat } = getStatsSync(src, dest, opts);
12597
12597
  if (destStat) {
12598
12598
  if (areIdentical(srcStat, destStat)) {
12599
- const srcBaseName = path18.basename(src);
12600
- const destBaseName = path18.basename(dest);
12599
+ const srcBaseName = path19.basename(src);
12600
+ const destBaseName = path19.basename(dest);
12601
12601
  if (funcName === "move" && srcBaseName !== destBaseName && srcBaseName.toLowerCase() === destBaseName.toLowerCase()) {
12602
12602
  return { srcStat, destStat, isChangingCase: true };
12603
12603
  }
@@ -12616,9 +12616,9 @@ var require_stat = __commonJS({
12616
12616
  return { srcStat, destStat };
12617
12617
  }
12618
12618
  async function checkParentPaths(src, srcStat, dest, funcName) {
12619
- const srcParent = path18.resolve(path18.dirname(src));
12620
- const destParent = path18.resolve(path18.dirname(dest));
12621
- if (destParent === srcParent || destParent === path18.parse(destParent).root) return;
12619
+ const srcParent = path19.resolve(path19.dirname(src));
12620
+ const destParent = path19.resolve(path19.dirname(dest));
12621
+ if (destParent === srcParent || destParent === path19.parse(destParent).root) return;
12622
12622
  let destStat;
12623
12623
  try {
12624
12624
  destStat = await fs19.stat(destParent, { bigint: true });
@@ -12632,9 +12632,9 @@ var require_stat = __commonJS({
12632
12632
  return checkParentPaths(src, srcStat, destParent, funcName);
12633
12633
  }
12634
12634
  function checkParentPathsSync(src, srcStat, dest, funcName) {
12635
- const srcParent = path18.resolve(path18.dirname(src));
12636
- const destParent = path18.resolve(path18.dirname(dest));
12637
- if (destParent === srcParent || destParent === path18.parse(destParent).root) return;
12635
+ const srcParent = path19.resolve(path19.dirname(src));
12636
+ const destParent = path19.resolve(path19.dirname(dest));
12637
+ if (destParent === srcParent || destParent === path19.parse(destParent).root) return;
12638
12638
  let destStat;
12639
12639
  try {
12640
12640
  destStat = fs19.statSync(destParent, { bigint: true });
@@ -12651,8 +12651,8 @@ var require_stat = __commonJS({
12651
12651
  return destStat.ino !== void 0 && destStat.dev !== void 0 && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev;
12652
12652
  }
12653
12653
  function isSrcSubdir(src, dest) {
12654
- const srcArr = path18.resolve(src).split(path18.sep).filter((i) => i);
12655
- const destArr = path18.resolve(dest).split(path18.sep).filter((i) => i);
12654
+ const srcArr = path19.resolve(src).split(path19.sep).filter((i) => i);
12655
+ const destArr = path19.resolve(dest).split(path19.sep).filter((i) => i);
12656
12656
  return srcArr.every((cur, i) => destArr[i] === cur);
12657
12657
  }
12658
12658
  function errMsg(src, dest, funcName) {
@@ -12705,7 +12705,7 @@ var require_copy = __commonJS({
12705
12705
  "node_modules/fs-extra/lib/copy/copy.js"(exports2, module2) {
12706
12706
  "use strict";
12707
12707
  var fs19 = require_fs();
12708
- var path18 = require("path");
12708
+ var path19 = require("path");
12709
12709
  var { mkdirs } = require_mkdirs();
12710
12710
  var { pathExists } = require_path_exists();
12711
12711
  var { utimesMillis } = require_utimes();
@@ -12728,7 +12728,7 @@ var require_copy = __commonJS({
12728
12728
  await stat.checkParentPaths(src, srcStat, dest, "copy");
12729
12729
  const include = await runFilter(src, dest, opts);
12730
12730
  if (!include) return;
12731
- const destParent = path18.dirname(dest);
12731
+ const destParent = path19.dirname(dest);
12732
12732
  const dirExists = await pathExists(destParent);
12733
12733
  if (!dirExists) {
12734
12734
  await mkdirs(destParent);
@@ -12781,8 +12781,8 @@ var require_copy = __commonJS({
12781
12781
  await fs19.mkdir(dest);
12782
12782
  }
12783
12783
  await asyncIteratorConcurrentProcess(await fs19.opendir(src), async (item) => {
12784
- const srcItem = path18.join(src, item.name);
12785
- const destItem = path18.join(dest, item.name);
12784
+ const srcItem = path19.join(src, item.name);
12785
+ const destItem = path19.join(dest, item.name);
12786
12786
  const include = await runFilter(srcItem, destItem, opts);
12787
12787
  if (include) {
12788
12788
  const { destStat: destStat2 } = await stat.checkPaths(srcItem, destItem, "copy", opts);
@@ -12796,7 +12796,7 @@ var require_copy = __commonJS({
12796
12796
  async function onLink(destStat, src, dest, opts) {
12797
12797
  let resolvedSrc = await fs19.readlink(src);
12798
12798
  if (opts.dereference) {
12799
- resolvedSrc = path18.resolve(process.cwd(), resolvedSrc);
12799
+ resolvedSrc = path19.resolve(process.cwd(), resolvedSrc);
12800
12800
  }
12801
12801
  if (!destStat) {
12802
12802
  return fs19.symlink(resolvedSrc, dest);
@@ -12809,7 +12809,7 @@ var require_copy = __commonJS({
12809
12809
  throw e;
12810
12810
  }
12811
12811
  if (opts.dereference) {
12812
- resolvedDest = path18.resolve(process.cwd(), resolvedDest);
12812
+ resolvedDest = path19.resolve(process.cwd(), resolvedDest);
12813
12813
  }
12814
12814
  if (resolvedSrc !== resolvedDest) {
12815
12815
  if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
@@ -12831,7 +12831,7 @@ var require_copy_sync = __commonJS({
12831
12831
  "node_modules/fs-extra/lib/copy/copy-sync.js"(exports2, module2) {
12832
12832
  "use strict";
12833
12833
  var fs19 = require_graceful_fs();
12834
- var path18 = require("path");
12834
+ var path19 = require("path");
12835
12835
  var mkdirsSync = require_mkdirs().mkdirsSync;
12836
12836
  var utimesMillisSync = require_utimes().utimesMillisSync;
12837
12837
  var stat = require_stat();
@@ -12852,7 +12852,7 @@ var require_copy_sync = __commonJS({
12852
12852
  const { srcStat, destStat } = stat.checkPathsSync(src, dest, "copy", opts);
12853
12853
  stat.checkParentPathsSync(src, srcStat, dest, "copy");
12854
12854
  if (opts.filter && !opts.filter(src, dest)) return;
12855
- const destParent = path18.dirname(dest);
12855
+ const destParent = path19.dirname(dest);
12856
12856
  if (!fs19.existsSync(destParent)) mkdirsSync(destParent);
12857
12857
  return getStats(destStat, src, dest, opts);
12858
12858
  }
@@ -12921,8 +12921,8 @@ var require_copy_sync = __commonJS({
12921
12921
  }
12922
12922
  }
12923
12923
  function copyDirItem(item, src, dest, opts) {
12924
- const srcItem = path18.join(src, item);
12925
- const destItem = path18.join(dest, item);
12924
+ const srcItem = path19.join(src, item);
12925
+ const destItem = path19.join(dest, item);
12926
12926
  if (opts.filter && !opts.filter(srcItem, destItem)) return;
12927
12927
  const { destStat } = stat.checkPathsSync(srcItem, destItem, "copy", opts);
12928
12928
  return getStats(destStat, srcItem, destItem, opts);
@@ -12930,7 +12930,7 @@ var require_copy_sync = __commonJS({
12930
12930
  function onLink(destStat, src, dest, opts) {
12931
12931
  let resolvedSrc = fs19.readlinkSync(src);
12932
12932
  if (opts.dereference) {
12933
- resolvedSrc = path18.resolve(process.cwd(), resolvedSrc);
12933
+ resolvedSrc = path19.resolve(process.cwd(), resolvedSrc);
12934
12934
  }
12935
12935
  if (!destStat) {
12936
12936
  return fs19.symlinkSync(resolvedSrc, dest);
@@ -12943,7 +12943,7 @@ var require_copy_sync = __commonJS({
12943
12943
  throw err;
12944
12944
  }
12945
12945
  if (opts.dereference) {
12946
- resolvedDest = path18.resolve(process.cwd(), resolvedDest);
12946
+ resolvedDest = path19.resolve(process.cwd(), resolvedDest);
12947
12947
  }
12948
12948
  if (resolvedSrc !== resolvedDest) {
12949
12949
  if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
@@ -12982,11 +12982,11 @@ var require_remove = __commonJS({
12982
12982
  "use strict";
12983
12983
  var fs19 = require_graceful_fs();
12984
12984
  var u = require_universalify().fromCallback;
12985
- function remove(path18, callback) {
12986
- fs19.rm(path18, { recursive: true, force: true }, callback);
12985
+ function remove(path19, callback) {
12986
+ fs19.rm(path19, { recursive: true, force: true }, callback);
12987
12987
  }
12988
- function removeSync(path18) {
12989
- fs19.rmSync(path18, { recursive: true, force: true });
12988
+ function removeSync(path19) {
12989
+ fs19.rmSync(path19, { recursive: true, force: true });
12990
12990
  }
12991
12991
  module2.exports = {
12992
12992
  remove: u(remove),
@@ -13001,7 +13001,7 @@ var require_empty = __commonJS({
13001
13001
  "use strict";
13002
13002
  var u = require_universalify().fromPromise;
13003
13003
  var fs19 = require_fs();
13004
- var path18 = require("path");
13004
+ var path19 = require("path");
13005
13005
  var mkdir = require_mkdirs();
13006
13006
  var remove = require_remove();
13007
13007
  var emptyDir = u(async function emptyDir2(dir) {
@@ -13011,7 +13011,7 @@ var require_empty = __commonJS({
13011
13011
  } catch {
13012
13012
  return mkdir.mkdirs(dir);
13013
13013
  }
13014
- return Promise.all(items.map((item) => remove.remove(path18.join(dir, item))));
13014
+ return Promise.all(items.map((item) => remove.remove(path19.join(dir, item))));
13015
13015
  });
13016
13016
  function emptyDirSync(dir) {
13017
13017
  let items;
@@ -13021,7 +13021,7 @@ var require_empty = __commonJS({
13021
13021
  return mkdir.mkdirsSync(dir);
13022
13022
  }
13023
13023
  items.forEach((item) => {
13024
- item = path18.join(dir, item);
13024
+ item = path19.join(dir, item);
13025
13025
  remove.removeSync(item);
13026
13026
  });
13027
13027
  }
@@ -13039,7 +13039,7 @@ var require_file = __commonJS({
13039
13039
  "node_modules/fs-extra/lib/ensure/file.js"(exports2, module2) {
13040
13040
  "use strict";
13041
13041
  var u = require_universalify().fromPromise;
13042
- var path18 = require("path");
13042
+ var path19 = require("path");
13043
13043
  var fs19 = require_fs();
13044
13044
  var mkdir = require_mkdirs();
13045
13045
  async function createFile(file2) {
@@ -13049,7 +13049,7 @@ var require_file = __commonJS({
13049
13049
  } catch {
13050
13050
  }
13051
13051
  if (stats && stats.isFile()) return;
13052
- const dir = path18.dirname(file2);
13052
+ const dir = path19.dirname(file2);
13053
13053
  let dirStats = null;
13054
13054
  try {
13055
13055
  dirStats = await fs19.stat(dir);
@@ -13075,7 +13075,7 @@ var require_file = __commonJS({
13075
13075
  } catch {
13076
13076
  }
13077
13077
  if (stats && stats.isFile()) return;
13078
- const dir = path18.dirname(file2);
13078
+ const dir = path19.dirname(file2);
13079
13079
  try {
13080
13080
  if (!fs19.statSync(dir).isDirectory()) {
13081
13081
  fs19.readdirSync(dir);
@@ -13098,7 +13098,7 @@ var require_link = __commonJS({
13098
13098
  "node_modules/fs-extra/lib/ensure/link.js"(exports2, module2) {
13099
13099
  "use strict";
13100
13100
  var u = require_universalify().fromPromise;
13101
- var path18 = require("path");
13101
+ var path19 = require("path");
13102
13102
  var fs19 = require_fs();
13103
13103
  var mkdir = require_mkdirs();
13104
13104
  var { pathExists } = require_path_exists();
@@ -13117,7 +13117,7 @@ var require_link = __commonJS({
13117
13117
  throw err;
13118
13118
  }
13119
13119
  if (dstStat && areIdentical(srcStat, dstStat)) return;
13120
- const dir = path18.dirname(dstpath);
13120
+ const dir = path19.dirname(dstpath);
13121
13121
  const dirExists = await pathExists(dir);
13122
13122
  if (!dirExists) {
13123
13123
  await mkdir.mkdirs(dir);
@@ -13137,7 +13137,7 @@ var require_link = __commonJS({
13137
13137
  err.message = err.message.replace("lstat", "ensureLink");
13138
13138
  throw err;
13139
13139
  }
13140
- const dir = path18.dirname(dstpath);
13140
+ const dir = path19.dirname(dstpath);
13141
13141
  const dirExists = fs19.existsSync(dir);
13142
13142
  if (dirExists) return fs19.linkSync(srcpath, dstpath);
13143
13143
  mkdir.mkdirsSync(dir);
@@ -13154,12 +13154,12 @@ var require_link = __commonJS({
13154
13154
  var require_symlink_paths = __commonJS({
13155
13155
  "node_modules/fs-extra/lib/ensure/symlink-paths.js"(exports2, module2) {
13156
13156
  "use strict";
13157
- var path18 = require("path");
13157
+ var path19 = require("path");
13158
13158
  var fs19 = require_fs();
13159
13159
  var { pathExists } = require_path_exists();
13160
13160
  var u = require_universalify().fromPromise;
13161
13161
  async function symlinkPaths(srcpath, dstpath) {
13162
- if (path18.isAbsolute(srcpath)) {
13162
+ if (path19.isAbsolute(srcpath)) {
13163
13163
  try {
13164
13164
  await fs19.lstat(srcpath);
13165
13165
  } catch (err) {
@@ -13171,8 +13171,8 @@ var require_symlink_paths = __commonJS({
13171
13171
  toDst: srcpath
13172
13172
  };
13173
13173
  }
13174
- const dstdir = path18.dirname(dstpath);
13175
- const relativeToDst = path18.join(dstdir, srcpath);
13174
+ const dstdir = path19.dirname(dstpath);
13175
+ const relativeToDst = path19.join(dstdir, srcpath);
13176
13176
  const exists = await pathExists(relativeToDst);
13177
13177
  if (exists) {
13178
13178
  return {
@@ -13188,11 +13188,11 @@ var require_symlink_paths = __commonJS({
13188
13188
  }
13189
13189
  return {
13190
13190
  toCwd: srcpath,
13191
- toDst: path18.relative(dstdir, srcpath)
13191
+ toDst: path19.relative(dstdir, srcpath)
13192
13192
  };
13193
13193
  }
13194
13194
  function symlinkPathsSync(srcpath, dstpath) {
13195
- if (path18.isAbsolute(srcpath)) {
13195
+ if (path19.isAbsolute(srcpath)) {
13196
13196
  const exists2 = fs19.existsSync(srcpath);
13197
13197
  if (!exists2) throw new Error("absolute srcpath does not exist");
13198
13198
  return {
@@ -13200,8 +13200,8 @@ var require_symlink_paths = __commonJS({
13200
13200
  toDst: srcpath
13201
13201
  };
13202
13202
  }
13203
- const dstdir = path18.dirname(dstpath);
13204
- const relativeToDst = path18.join(dstdir, srcpath);
13203
+ const dstdir = path19.dirname(dstpath);
13204
+ const relativeToDst = path19.join(dstdir, srcpath);
13205
13205
  const exists = fs19.existsSync(relativeToDst);
13206
13206
  if (exists) {
13207
13207
  return {
@@ -13213,7 +13213,7 @@ var require_symlink_paths = __commonJS({
13213
13213
  if (!srcExists) throw new Error("relative srcpath does not exist");
13214
13214
  return {
13215
13215
  toCwd: srcpath,
13216
- toDst: path18.relative(dstdir, srcpath)
13216
+ toDst: path19.relative(dstdir, srcpath)
13217
13217
  };
13218
13218
  }
13219
13219
  module2.exports = {
@@ -13261,7 +13261,7 @@ var require_symlink = __commonJS({
13261
13261
  "node_modules/fs-extra/lib/ensure/symlink.js"(exports2, module2) {
13262
13262
  "use strict";
13263
13263
  var u = require_universalify().fromPromise;
13264
- var path18 = require("path");
13264
+ var path19 = require("path");
13265
13265
  var fs19 = require_fs();
13266
13266
  var { mkdirs, mkdirsSync } = require_mkdirs();
13267
13267
  var { symlinkPaths, symlinkPathsSync } = require_symlink_paths();
@@ -13284,7 +13284,7 @@ var require_symlink = __commonJS({
13284
13284
  const relative = await symlinkPaths(srcpath, dstpath);
13285
13285
  srcpath = relative.toDst;
13286
13286
  const toType = await symlinkType(relative.toCwd, type);
13287
- const dir = path18.dirname(dstpath);
13287
+ const dir = path19.dirname(dstpath);
13288
13288
  if (!await pathExists(dir)) {
13289
13289
  await mkdirs(dir);
13290
13290
  }
@@ -13304,7 +13304,7 @@ var require_symlink = __commonJS({
13304
13304
  const relative = symlinkPathsSync(srcpath, dstpath);
13305
13305
  srcpath = relative.toDst;
13306
13306
  type = symlinkTypeSync(relative.toCwd, type);
13307
- const dir = path18.dirname(dstpath);
13307
+ const dir = path19.dirname(dstpath);
13308
13308
  const exists = fs19.existsSync(dir);
13309
13309
  if (exists) return fs19.symlinkSync(srcpath, dstpath, type);
13310
13310
  mkdirsSync(dir);
@@ -13395,7 +13395,7 @@ var require_jsonfile = __commonJS({
13395
13395
  return obj;
13396
13396
  }
13397
13397
  var readFile = universalify.fromPromise(_readFile);
13398
- function readFileSync2(file2, options = {}) {
13398
+ function readFileSync3(file2, options = {}) {
13399
13399
  if (typeof options === "string") {
13400
13400
  options = { encoding: options };
13401
13401
  }
@@ -13420,16 +13420,16 @@ var require_jsonfile = __commonJS({
13420
13420
  await universalify.fromCallback(fs19.writeFile)(file2, str, options);
13421
13421
  }
13422
13422
  var writeFile = universalify.fromPromise(_writeFile);
13423
- function writeFileSync2(file2, obj, options = {}) {
13423
+ function writeFileSync3(file2, obj, options = {}) {
13424
13424
  const fs19 = options.fs || _fs;
13425
13425
  const str = stringify2(obj, options);
13426
13426
  return fs19.writeFileSync(file2, str, options);
13427
13427
  }
13428
13428
  module2.exports = {
13429
13429
  readFile,
13430
- readFileSync: readFileSync2,
13430
+ readFileSync: readFileSync3,
13431
13431
  writeFile,
13432
- writeFileSync: writeFileSync2
13432
+ writeFileSync: writeFileSync3
13433
13433
  };
13434
13434
  }
13435
13435
  });
@@ -13455,18 +13455,18 @@ var require_output_file = __commonJS({
13455
13455
  "use strict";
13456
13456
  var u = require_universalify().fromPromise;
13457
13457
  var fs19 = require_fs();
13458
- var path18 = require("path");
13458
+ var path19 = require("path");
13459
13459
  var mkdir = require_mkdirs();
13460
13460
  var pathExists = require_path_exists().pathExists;
13461
13461
  async function outputFile(file2, data, encoding = "utf-8") {
13462
- const dir = path18.dirname(file2);
13462
+ const dir = path19.dirname(file2);
13463
13463
  if (!await pathExists(dir)) {
13464
13464
  await mkdir.mkdirs(dir);
13465
13465
  }
13466
13466
  return fs19.writeFile(file2, data, encoding);
13467
13467
  }
13468
13468
  function outputFileSync(file2, ...args) {
13469
- const dir = path18.dirname(file2);
13469
+ const dir = path19.dirname(file2);
13470
13470
  if (!fs19.existsSync(dir)) {
13471
13471
  mkdir.mkdirsSync(dir);
13472
13472
  }
@@ -13530,7 +13530,7 @@ var require_move = __commonJS({
13530
13530
  "node_modules/fs-extra/lib/move/move.js"(exports2, module2) {
13531
13531
  "use strict";
13532
13532
  var fs19 = require_fs();
13533
- var path18 = require("path");
13533
+ var path19 = require("path");
13534
13534
  var { copy } = require_copy2();
13535
13535
  var { remove } = require_remove();
13536
13536
  var { mkdirp } = require_mkdirs();
@@ -13540,8 +13540,8 @@ var require_move = __commonJS({
13540
13540
  const overwrite = opts.overwrite || opts.clobber || false;
13541
13541
  const { srcStat, isChangingCase = false } = await stat.checkPaths(src, dest, "move", opts);
13542
13542
  await stat.checkParentPaths(src, srcStat, dest, "move");
13543
- const destParent = path18.dirname(dest);
13544
- const parsedParentPath = path18.parse(destParent);
13543
+ const destParent = path19.dirname(dest);
13544
+ const parsedParentPath = path19.parse(destParent);
13545
13545
  if (parsedParentPath.root !== destParent) {
13546
13546
  await mkdirp(destParent);
13547
13547
  }
@@ -13582,7 +13582,7 @@ var require_move_sync = __commonJS({
13582
13582
  "node_modules/fs-extra/lib/move/move-sync.js"(exports2, module2) {
13583
13583
  "use strict";
13584
13584
  var fs19 = require_graceful_fs();
13585
- var path18 = require("path");
13585
+ var path19 = require("path");
13586
13586
  var copySync = require_copy2().copySync;
13587
13587
  var removeSync = require_remove().removeSync;
13588
13588
  var mkdirpSync = require_mkdirs().mkdirpSync;
@@ -13592,12 +13592,12 @@ var require_move_sync = __commonJS({
13592
13592
  const overwrite = opts.overwrite || opts.clobber || false;
13593
13593
  const { srcStat, isChangingCase = false } = stat.checkPathsSync(src, dest, "move", opts);
13594
13594
  stat.checkParentPathsSync(src, srcStat, dest, "move");
13595
- if (!isParentRoot(dest)) mkdirpSync(path18.dirname(dest));
13595
+ if (!isParentRoot(dest)) mkdirpSync(path19.dirname(dest));
13596
13596
  return doRename(src, dest, overwrite, isChangingCase);
13597
13597
  }
13598
13598
  function isParentRoot(dest) {
13599
- const parent = path18.dirname(dest);
13600
- const parsedPath = path18.parse(parent);
13599
+ const parent = path19.dirname(dest);
13600
+ const parsedPath = path19.parse(parent);
13601
13601
  return parsedPath.root === parent;
13602
13602
  }
13603
13603
  function doRename(src, dest, overwrite, isChangingCase) {
@@ -16856,8 +16856,8 @@ var require_utils3 = __commonJS({
16856
16856
  }
16857
16857
  return ind;
16858
16858
  }
16859
- function removeDotSegments(path18) {
16860
- let input = path18;
16859
+ function removeDotSegments(path19) {
16860
+ let input = path19;
16861
16861
  const output = [];
16862
16862
  let nextSlash = -1;
16863
16863
  let len = 0;
@@ -17056,8 +17056,8 @@ var require_schemes = __commonJS({
17056
17056
  wsComponent.secure = void 0;
17057
17057
  }
17058
17058
  if (wsComponent.resourceName) {
17059
- const [path18, query] = wsComponent.resourceName.split("?");
17060
- wsComponent.path = path18 && path18 !== "/" ? path18 : void 0;
17059
+ const [path19, query] = wsComponent.resourceName.split("?");
17060
+ wsComponent.path = path19 && path19 !== "/" ? path19 : void 0;
17061
17061
  wsComponent.query = query;
17062
17062
  wsComponent.resourceName = void 0;
17063
17063
  }
@@ -30991,7 +30991,7 @@ var require_main = __commonJS({
30991
30991
  "node_modules/dotenv/lib/main.js"(exports2, module2) {
30992
30992
  "use strict";
30993
30993
  var fs19 = require("fs");
30994
- var path18 = require("path");
30994
+ var path19 = require("path");
30995
30995
  var os7 = require("os");
30996
30996
  var crypto2 = require("crypto");
30997
30997
  var packageJson = require_package();
@@ -31107,7 +31107,7 @@ var require_main = __commonJS({
31107
31107
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
31108
31108
  }
31109
31109
  } else {
31110
- possibleVaultPath = path18.resolve(process.cwd(), ".env.vault");
31110
+ possibleVaultPath = path19.resolve(process.cwd(), ".env.vault");
31111
31111
  }
31112
31112
  if (fs19.existsSync(possibleVaultPath)) {
31113
31113
  return possibleVaultPath;
@@ -31115,7 +31115,7 @@ var require_main = __commonJS({
31115
31115
  return null;
31116
31116
  }
31117
31117
  function _resolveHome(envPath) {
31118
- return envPath[0] === "~" ? path18.join(os7.homedir(), envPath.slice(1)) : envPath;
31118
+ return envPath[0] === "~" ? path19.join(os7.homedir(), envPath.slice(1)) : envPath;
31119
31119
  }
31120
31120
  function _configVault(options) {
31121
31121
  const debug = Boolean(options && options.debug);
@@ -31132,7 +31132,7 @@ var require_main = __commonJS({
31132
31132
  return { parsed };
31133
31133
  }
31134
31134
  function configDotenv(options) {
31135
- const dotenvPath = path18.resolve(process.cwd(), ".env");
31135
+ const dotenvPath = path19.resolve(process.cwd(), ".env");
31136
31136
  let encoding = "utf8";
31137
31137
  const debug = Boolean(options && options.debug);
31138
31138
  const quiet = options && "quiet" in options ? options.quiet : true;
@@ -31156,13 +31156,13 @@ var require_main = __commonJS({
31156
31156
  }
31157
31157
  let lastError;
31158
31158
  const parsedAll = {};
31159
- for (const path19 of optionPaths) {
31159
+ for (const path20 of optionPaths) {
31160
31160
  try {
31161
- const parsed = DotenvModule.parse(fs19.readFileSync(path19, { encoding }));
31161
+ const parsed = DotenvModule.parse(fs19.readFileSync(path20, { encoding }));
31162
31162
  DotenvModule.populate(parsedAll, parsed, options);
31163
31163
  } catch (e) {
31164
31164
  if (debug) {
31165
- _debug(`Failed to load ${path19} ${e.message}`);
31165
+ _debug(`Failed to load ${path20} ${e.message}`);
31166
31166
  }
31167
31167
  lastError = e;
31168
31168
  }
@@ -31177,7 +31177,7 @@ var require_main = __commonJS({
31177
31177
  const shortPaths = [];
31178
31178
  for (const filePath of optionPaths) {
31179
31179
  try {
31180
- const relative = path18.relative(process.cwd(), filePath);
31180
+ const relative = path19.relative(process.cwd(), filePath);
31181
31181
  shortPaths.push(relative);
31182
31182
  } catch (e) {
31183
31183
  if (debug) {
@@ -33870,8 +33870,8 @@ var init_boxen = __esm({
33870
33870
  });
33871
33871
 
33872
33872
  // src/index.ts
33873
- var import_node_fs4 = require("fs");
33874
- var import_node_path5 = require("path");
33873
+ var import_node_fs6 = require("fs");
33874
+ var import_node_path6 = require("path");
33875
33875
 
33876
33876
  // node_modules/commander/esm.mjs
33877
33877
  var import_index = __toESM(require_commander(), 1);
@@ -35815,12 +35815,12 @@ var disallowedKeys = /* @__PURE__ */ new Set([
35815
35815
  "constructor"
35816
35816
  ]);
35817
35817
  var digits = new Set("0123456789");
35818
- function getPathSegments(path18) {
35818
+ function getPathSegments(path19) {
35819
35819
  const parts = [];
35820
35820
  let currentSegment = "";
35821
35821
  let currentPart = "start";
35822
35822
  let isIgnoring = false;
35823
- for (const character of path18) {
35823
+ for (const character of path19) {
35824
35824
  switch (character) {
35825
35825
  case "\\": {
35826
35826
  if (currentPart === "index") {
@@ -35942,11 +35942,11 @@ function assertNotStringIndex(object2, key) {
35942
35942
  throw new Error("Cannot use string index");
35943
35943
  }
35944
35944
  }
35945
- function getProperty(object2, path18, value) {
35946
- if (!isObject(object2) || typeof path18 !== "string") {
35945
+ function getProperty(object2, path19, value) {
35946
+ if (!isObject(object2) || typeof path19 !== "string") {
35947
35947
  return value === void 0 ? object2 : value;
35948
35948
  }
35949
- const pathArray = getPathSegments(path18);
35949
+ const pathArray = getPathSegments(path19);
35950
35950
  if (pathArray.length === 0) {
35951
35951
  return value;
35952
35952
  }
@@ -35966,12 +35966,12 @@ function getProperty(object2, path18, value) {
35966
35966
  }
35967
35967
  return object2 === void 0 ? value : object2;
35968
35968
  }
35969
- function setProperty(object2, path18, value) {
35970
- if (!isObject(object2) || typeof path18 !== "string") {
35969
+ function setProperty(object2, path19, value) {
35970
+ if (!isObject(object2) || typeof path19 !== "string") {
35971
35971
  return object2;
35972
35972
  }
35973
35973
  const root = object2;
35974
- const pathArray = getPathSegments(path18);
35974
+ const pathArray = getPathSegments(path19);
35975
35975
  for (let index = 0; index < pathArray.length; index++) {
35976
35976
  const key = pathArray[index];
35977
35977
  assertNotStringIndex(object2, key);
@@ -35984,11 +35984,11 @@ function setProperty(object2, path18, value) {
35984
35984
  }
35985
35985
  return root;
35986
35986
  }
35987
- function deleteProperty(object2, path18) {
35988
- if (!isObject(object2) || typeof path18 !== "string") {
35987
+ function deleteProperty(object2, path19) {
35988
+ if (!isObject(object2) || typeof path19 !== "string") {
35989
35989
  return false;
35990
35990
  }
35991
- const pathArray = getPathSegments(path18);
35991
+ const pathArray = getPathSegments(path19);
35992
35992
  for (let index = 0; index < pathArray.length; index++) {
35993
35993
  const key = pathArray[index];
35994
35994
  assertNotStringIndex(object2, key);
@@ -36002,11 +36002,11 @@ function deleteProperty(object2, path18) {
36002
36002
  }
36003
36003
  }
36004
36004
  }
36005
- function hasProperty(object2, path18) {
36006
- if (!isObject(object2) || typeof path18 !== "string") {
36005
+ function hasProperty(object2, path19) {
36006
+ if (!isObject(object2) || typeof path19 !== "string") {
36007
36007
  return false;
36008
36008
  }
36009
- const pathArray = getPathSegments(path18);
36009
+ const pathArray = getPathSegments(path19);
36010
36010
  if (pathArray.length === 0) {
36011
36011
  return false;
36012
36012
  }
@@ -36123,9 +36123,9 @@ var retryifyAsync = (fn, options) => {
36123
36123
  throw error49;
36124
36124
  if (Date.now() >= timestamp)
36125
36125
  throw error49;
36126
- const delay3 = Math.round(interval * Math.random());
36127
- if (delay3 > 0) {
36128
- const delayPromise = new Promise((resolve2) => setTimeout(resolve2, delay3));
36126
+ const delay4 = Math.round(interval * Math.random());
36127
+ if (delay4 > 0) {
36128
+ const delayPromise = new Promise((resolve2) => setTimeout(resolve2, delay4));
36129
36129
  return delayPromise.then(() => attempt.apply(void 0, args));
36130
36130
  } else {
36131
36131
  return attempt.apply(void 0, args);
@@ -37217,8 +37217,8 @@ function detectAdapter(systemRoot) {
37217
37217
  // src/core/diff.ts
37218
37218
  var IGNORED_ITEMS = /* @__PURE__ */ new Set(["__pycache__", ".DS_Store", "Thumbs.db", ".gitkeep", "node_modules"]);
37219
37219
  var PruneModeReadError = class extends Error {
37220
- constructor(path18) {
37221
- super(`Cannot read ${path18} in prune mode \u2014 aborting to prevent accidental deletion`);
37220
+ constructor(path19) {
37221
+ super(`Cannot read ${path19} in prune mode \u2014 aborting to prevent accidental deletion`);
37222
37222
  this.name = "PruneModeReadError";
37223
37223
  }
37224
37224
  };
@@ -41029,6 +41029,99 @@ var INSTRUCTIONS_DIR = import_path11.default.join(PKG_ROOT2, "config", "instruct
41029
41029
  var XTRM_BLOCK_START = "<!-- xtrm:start -->";
41030
41030
  var XTRM_BLOCK_END = "<!-- xtrm:end -->";
41031
41031
  var syncedProjectMcpRoots = /* @__PURE__ */ new Set();
41032
+ function toServiceId(name) {
41033
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "service";
41034
+ }
41035
+ function parseComposeServices(content) {
41036
+ const lines = content.split("\n");
41037
+ const services = /* @__PURE__ */ new Set();
41038
+ let inServices = false;
41039
+ for (const line of lines) {
41040
+ const raw = line.replace(/\t/g, " ");
41041
+ if (!inServices) {
41042
+ if (/^services:\s*$/.test(raw)) {
41043
+ inServices = true;
41044
+ }
41045
+ continue;
41046
+ }
41047
+ if (/^[^\s#].*:\s*$/.test(raw) && !/^services:\s*$/.test(raw)) {
41048
+ break;
41049
+ }
41050
+ const serviceMatch = raw.match(/^\s{2}([A-Za-z0-9._-]+):\s*(?:#.*)?$/);
41051
+ if (serviceMatch) {
41052
+ services.add(serviceMatch[1]);
41053
+ }
41054
+ }
41055
+ return [...services];
41056
+ }
41057
+ async function detectProjectFeatures(projectRoot) {
41058
+ const hasTypeScript = await import_fs_extra11.default.pathExists(import_path11.default.join(projectRoot, "tsconfig.json"));
41059
+ const hasPython = await import_fs_extra11.default.pathExists(import_path11.default.join(projectRoot, "pyproject.toml")) || await import_fs_extra11.default.pathExists(import_path11.default.join(projectRoot, "setup.py")) || await import_fs_extra11.default.pathExists(import_path11.default.join(projectRoot, "requirements.txt"));
41060
+ const composeCandidates = [
41061
+ "docker-compose.yml",
41062
+ "docker-compose.yaml",
41063
+ "compose.yml",
41064
+ "compose.yaml"
41065
+ ];
41066
+ const dockerServices = /* @__PURE__ */ new Set();
41067
+ for (const composeFile of composeCandidates) {
41068
+ const composePath = import_path11.default.join(projectRoot, composeFile);
41069
+ if (!await import_fs_extra11.default.pathExists(composePath)) continue;
41070
+ try {
41071
+ const content = await import_fs_extra11.default.readFile(composePath, "utf8");
41072
+ for (const service of parseComposeServices(content)) {
41073
+ dockerServices.add(service);
41074
+ }
41075
+ } catch {
41076
+ }
41077
+ }
41078
+ const hasDockerfile = await import_fs_extra11.default.pathExists(import_path11.default.join(projectRoot, "Dockerfile"));
41079
+ if (hasDockerfile && dockerServices.size === 0) {
41080
+ dockerServices.add(import_path11.default.basename(projectRoot));
41081
+ }
41082
+ return {
41083
+ hasTypeScript,
41084
+ hasPython,
41085
+ dockerServices: [...dockerServices],
41086
+ generatedRegistry: false
41087
+ };
41088
+ }
41089
+ async function ensureServiceRegistry(projectRoot, services) {
41090
+ const registryPath = import_path11.default.join(projectRoot, "service-registry.json");
41091
+ if (services.length === 0) {
41092
+ return { generated: false, registryPath };
41093
+ }
41094
+ const existedBefore = await import_fs_extra11.default.pathExists(registryPath);
41095
+ const now = (/* @__PURE__ */ new Date()).toISOString();
41096
+ let registry2 = { version: "1.0.0", services: {} };
41097
+ if (existedBefore) {
41098
+ try {
41099
+ registry2 = await import_fs_extra11.default.readJson(registryPath);
41100
+ if (!registry2.services || typeof registry2.services !== "object") {
41101
+ registry2.services = {};
41102
+ }
41103
+ } catch {
41104
+ registry2 = { version: "1.0.0", services: {} };
41105
+ }
41106
+ }
41107
+ let changed = false;
41108
+ for (const serviceName of services) {
41109
+ const serviceId = toServiceId(serviceName);
41110
+ if (registry2.services[serviceId]) continue;
41111
+ registry2.services[serviceId] = {
41112
+ name: serviceName,
41113
+ description: `Detected from Docker configuration (${serviceName}).`,
41114
+ territory: [],
41115
+ skill_path: `.claude/skills/${serviceId}/SKILL.md`,
41116
+ last_sync: now
41117
+ };
41118
+ changed = true;
41119
+ }
41120
+ if (changed || !existedBefore) {
41121
+ await import_fs_extra11.default.writeJson(registryPath, registry2, { spaces: 2 });
41122
+ }
41123
+ return { generated: changed || !existedBefore, registryPath };
41124
+ }
41032
41125
  function resolveEnvVars(value) {
41033
41126
  if (typeof value !== "string") return value;
41034
41127
  return value.replace(/\$\{([A-Z0-9_]+)\}/g, (_m, name) => process.env[name] || "");
@@ -41466,24 +41559,26 @@ Installing ${skills.length} project skills:
41466
41559
  }
41467
41560
  function buildProjectInitGuide() {
41468
41561
  const lines = [
41469
- kleur_default.bold("\nProject Init \u2014 Production baseline\n"),
41470
- kleur_default.dim("This command prints a complete setup checklist and then bootstraps beads + GitNexus for this repo.\n"),
41471
- `${kleur_default.cyan("1) Install core project enforcement (quality-gates):")}`,
41472
- kleur_default.dim(" xtrm install project quality-gates"),
41473
- kleur_default.dim(" - Installs TypeScript + Python PostToolUse quality hooks"),
41474
- kleur_default.dim(" - Includes Serena matcher coverage for edit-equivalent tools"),
41475
- kleur_default.dim(" - Enforces linting/type-checking based on your repo config"),
41562
+ kleur_default.bold("\nProject Init \u2014 Global-first baseline\n"),
41563
+ kleur_default.dim("xtrm init bootstraps project data (beads, GitNexus, service registry) while hooks/skills stay global.\n"),
41564
+ `${kleur_default.cyan("1) Run initialization once per repository:")}`,
41565
+ kleur_default.dim(" xtrm init (alias: xtrm project init)"),
41566
+ kleur_default.dim(" - Initializes beads workspace (bd init)"),
41567
+ kleur_default.dim(" - Refreshes GitNexus index if missing/stale"),
41568
+ kleur_default.dim(" - Syncs project-scoped MCP entries"),
41569
+ kleur_default.dim(" - Detects TS/Python/Docker project signals"),
41570
+ kleur_default.dim(" - Scaffolds service-registry.json when Docker services are detected"),
41476
41571
  "",
41477
- `${kleur_default.cyan("2) Optional installs depending on workflow:")}`,
41478
- kleur_default.dim(" xtrm install project tdd-guard"),
41479
- kleur_default.dim(" - Strong test-first enforcement (PreToolUse + prompt/session checks)"),
41480
- kleur_default.dim(" xtrm install project service-skills-set"),
41481
- kleur_default.dim(" - Service-aware skill routing + drift checks + git hook reminders"),
41572
+ `${kleur_default.cyan("2) What is already global (no per-project install needed):")}`,
41573
+ kleur_default.dim(" - quality gates hooks (formerly installed via quality-gates)"),
41574
+ kleur_default.dim(" - service-skills routing and drift checks (formerly service-skills-set)"),
41575
+ kleur_default.dim(" - main-guard + beads workflow gates"),
41576
+ kleur_default.dim(" - optional TDD strategy guidance (legacy name: tdd-guard)"),
41482
41577
  "",
41483
- `${kleur_default.cyan("3) Configure repo checks (hooks only enforce what your repo defines):")}`,
41484
- kleur_default.dim(" - Tests: should fail on regressions (required for TDD workflows)"),
41578
+ `${kleur_default.cyan("3) Configure repo quality tools (hooks enforce what exists):")}`,
41485
41579
  kleur_default.dim(" - TS: eslint + prettier + tsc"),
41486
41580
  kleur_default.dim(" - PY: ruff + mypy/pyright"),
41581
+ kleur_default.dim(" - tests: failing tests should block regressions"),
41487
41582
  "",
41488
41583
  `${kleur_default.cyan("4) Beads workflow (required for gated edit/commit flow):")}`,
41489
41584
  kleur_default.dim(" - Claim work: bd ready --json -> bd update <id> --claim --json"),
@@ -41496,27 +41591,20 @@ function buildProjectInitGuide() {
41496
41591
  kleur_default.dim(" - git push -u origin feature/<name>"),
41497
41592
  kleur_default.dim(" - gh pr create --fill && gh pr merge --squash"),
41498
41593
  kleur_default.dim(" - git checkout main && git pull --ff-only"),
41499
- "",
41500
- `${kleur_default.cyan("6) Hooks and startup automation:")}`,
41501
- kleur_default.dim(" - PreToolUse: safety gates (main/beads/TDD/type-safety/etc.)"),
41502
- kleur_default.dim(" - PostToolUse: quality checks + reminders"),
41503
- kleur_default.dim(" - Stop: beads stop-gate prevents unresolved session claims"),
41504
- kleur_default.dim(" - SessionStart: workflow context reminders"),
41505
- "",
41506
- kleur_default.bold("Quick start commands:"),
41507
- kleur_default.dim(" xtrm install project list"),
41508
- kleur_default.dim(" xtrm install project quality-gates"),
41509
- kleur_default.dim(" xtrm install project tdd-guard"),
41510
- kleur_default.dim(" xtrm install project service-skills-set"),
41511
41594
  ""
41512
41595
  ];
41513
41596
  return lines.join("\n");
41514
41597
  }
41515
- async function printProjectInitGuide() {
41598
+ async function runProjectInit() {
41516
41599
  console.log(buildProjectInitGuide());
41517
41600
  await bootstrapProjectInit();
41518
41601
  }
41602
+ function printProjectInstallDeprecationWarning() {
41603
+ console.log(kleur_default.yellow("\u26A0 Deprecated: `xtrm install project` is legacy and will be removed in a future release."));
41604
+ console.log(kleur_default.dim(" Use `xtrm init` (alias: `xtrm project init`) for project bootstrap.\n"));
41605
+ }
41519
41606
  async function installProjectByName(toolName) {
41607
+ printProjectInstallDeprecationWarning();
41520
41608
  if (toolName === "all" || toolName === "*") {
41521
41609
  await installAllProjectSkills();
41522
41610
  return;
@@ -41533,10 +41621,33 @@ async function bootstrapProjectInit() {
41533
41621
  `));
41534
41622
  return;
41535
41623
  }
41624
+ const detected = await detectProjectFeatures(projectRoot);
41536
41625
  await runBdInitForProject(projectRoot);
41537
41626
  await injectProjectInstructionHeaders(projectRoot);
41538
41627
  await runGitNexusInitForProject(projectRoot);
41539
41628
  await syncProjectMcpServers(projectRoot);
41629
+ if (detected.dockerServices.length > 0) {
41630
+ const { generated, registryPath } = await ensureServiceRegistry(projectRoot, detected.dockerServices);
41631
+ detected.generatedRegistry = generated;
41632
+ detected.registryPath = registryPath;
41633
+ if (generated) {
41634
+ console.log(`${kleur_default.green(" \u2713")} service registry scaffolded at ${import_path11.default.relative(projectRoot, registryPath)}`);
41635
+ } else {
41636
+ console.log(kleur_default.dim(" \u2713 service-registry.json already includes detected services"));
41637
+ }
41638
+ }
41639
+ const projectTypes = [];
41640
+ if (detected.hasTypeScript) projectTypes.push("TypeScript");
41641
+ if (detected.hasPython) projectTypes.push("Python");
41642
+ if (detected.dockerServices.length > 0) projectTypes.push("Docker");
41643
+ console.log(kleur_default.bold("\nProject initialized."));
41644
+ console.log(kleur_default.white(` Quality gates active globally.`));
41645
+ console.log(kleur_default.white(` Project types: ${projectTypes.length > 0 ? projectTypes.join(", ") : "none detected"}.`));
41646
+ console.log(kleur_default.white(` Services detected: ${detected.dockerServices.length > 0 ? detected.dockerServices.join(", ") : "none"}.`));
41647
+ if (detected.registryPath) {
41648
+ console.log(kleur_default.dim(` Service registry: ${detected.registryPath}`));
41649
+ }
41650
+ console.log("");
41540
41651
  }
41541
41652
  async function runBdInitForProject(projectRoot) {
41542
41653
  console.log(kleur_default.bold("Running beads initialization (bd init)..."));
@@ -41603,6 +41714,7 @@ ${status.stderr || ""}`.toLowerCase();
41603
41714
  console.log(kleur_default.yellow(` \u26A0 gitnexus analyze exited with code ${analyze.status}`));
41604
41715
  }
41605
41716
  async function listProjectSkills() {
41717
+ printProjectInstallDeprecationWarning();
41606
41718
  const entries = await getAvailableProjectSkills();
41607
41719
  if (entries.length === 0) {
41608
41720
  console.log(kleur_default.dim(" No project skills available.\n"));
@@ -41633,12 +41745,12 @@ async function listProjectSkills() {
41633
41745
  table.push([kleur_default.white(skill.name), kleur_default.dim(skill.description)]);
41634
41746
  }
41635
41747
  console.log(table.toString());
41636
- console.log(kleur_default.bold("\n\nUsage:\n"));
41637
- console.log(kleur_default.dim(" xtrm install project <skill-name> Install a project skill"));
41638
- console.log(kleur_default.dim(" xtrm install project all Install all project skills"));
41639
- console.log(kleur_default.dim(" xtrm install project list List available skills\n"));
41640
- console.log(kleur_default.bold("Example:\n"));
41641
- console.log(kleur_default.dim(" xtrm install project tdd-guard\n"));
41748
+ console.log(kleur_default.bold("\n\nUsage (legacy):\n"));
41749
+ console.log(kleur_default.dim(" xtrm install project <skill-name> Install a legacy project skill"));
41750
+ console.log(kleur_default.dim(" xtrm install project all Install all legacy project skills"));
41751
+ console.log(kleur_default.dim(" xtrm install project list List available legacy skills\n"));
41752
+ console.log(kleur_default.bold("Preferred:\n"));
41753
+ console.log(kleur_default.dim(" xtrm init Bootstrap project data for global hooks/skills\n"));
41642
41754
  }
41643
41755
  function getProjectRoot() {
41644
41756
  const result = (0, import_child_process3.spawnSync)("git", ["rev-parse", "--show-toplevel"], {
@@ -41651,7 +41763,7 @@ function getProjectRoot() {
41651
41763
  return import_path11.default.resolve(result.stdout.trim());
41652
41764
  }
41653
41765
  function createInstallProjectCommand() {
41654
- const installProjectCmd = new Command("project").description("Install a project-specific skill package");
41766
+ const installProjectCmd = new Command("project").description("[DEPRECATED] Legacy project skill installer (use `xtrm init`)");
41655
41767
  installProjectCmd.argument("<tool-name>", "Name of the project skill to install").action(async (toolName) => {
41656
41768
  try {
41657
41769
  await installProjectByName(toolName);
@@ -41666,21 +41778,21 @@ function createInstallProjectCommand() {
41666
41778
  await listProjectSkills();
41667
41779
  });
41668
41780
  const initCmd = new Command("init").description("Show full onboarding guidance and bootstrap beads + GitNexus").action(async () => {
41669
- await printProjectInitGuide();
41781
+ await runProjectInit();
41670
41782
  });
41671
41783
  installProjectCmd.addCommand(listCmd);
41672
41784
  installProjectCmd.addCommand(initCmd);
41673
41785
  return installProjectCmd;
41674
41786
  }
41675
41787
  function createProjectCommand() {
41676
- const projectCmd = new Command("project").description("Project skill onboarding and installation helpers");
41788
+ const projectCmd = new Command("project").description("Project onboarding helpers (`project install` is deprecated; use `xtrm init`)");
41677
41789
  projectCmd.command("init").description("Show full onboarding guidance and bootstrap beads + GitNexus").action(async () => {
41678
- await printProjectInitGuide();
41790
+ await runProjectInit();
41679
41791
  });
41680
41792
  projectCmd.command("list").description("List available project skills").action(async () => {
41681
41793
  await listProjectSkills();
41682
41794
  });
41683
- projectCmd.command("install").argument("<tool-name>", "Name of the project skill to install").description("Alias for xtrm install project <tool-name>").action(async (toolName) => {
41795
+ projectCmd.command("install").argument("<tool-name>", "Name of the legacy project skill to install").description("[DEPRECATED] Alias for xtrm install project <tool-name>; prefer `xtrm init`").action(async (toolName) => {
41684
41796
  try {
41685
41797
  await installProjectByName(toolName);
41686
41798
  } catch (err) {
@@ -41699,7 +41811,7 @@ var import_fs_extra12 = __toESM(require_lib2(), 1);
41699
41811
  var import_path12 = __toESM(require("path"), 1);
41700
41812
  var import_node_child_process = require("child_process");
41701
41813
  var import_node_os4 = require("os");
41702
- var PI_AGENT_DIR = import_path12.default.join((0, import_node_os4.homedir)(), ".pi", "agent");
41814
+ var PI_AGENT_DIR = process.env.PI_AGENT_DIR || import_path12.default.join((0, import_node_os4.homedir)(), ".pi", "agent");
41703
41815
  function fillTemplate(template, values) {
41704
41816
  return template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? "");
41705
41817
  }
@@ -41723,12 +41835,82 @@ function readExistingPiValues(piAgentDir) {
41723
41835
  function isPiInstalled() {
41724
41836
  return (0, import_node_child_process.spawnSync)("pi", ["--version"], { encoding: "utf8" }).status === 0;
41725
41837
  }
41838
+ async function listTsFilesRecursive(baseDir) {
41839
+ if (!await import_fs_extra12.default.pathExists(baseDir)) return [];
41840
+ const entries = await import_fs_extra12.default.readdir(baseDir, { withFileTypes: true });
41841
+ const files = [];
41842
+ for (const entry of entries) {
41843
+ const abs = import_path12.default.join(baseDir, entry.name);
41844
+ if (entry.isDirectory()) {
41845
+ files.push(...await listTsFilesRecursive(abs));
41846
+ continue;
41847
+ }
41848
+ if (entry.isFile() && entry.name.endsWith(".ts")) {
41849
+ files.push(abs);
41850
+ }
41851
+ }
41852
+ return files;
41853
+ }
41854
+ async function fileSha256(filePath) {
41855
+ const crypto2 = await import("crypto");
41856
+ const content = await import_fs_extra12.default.readFile(filePath);
41857
+ return crypto2.createHash("sha256").update(content).digest("hex");
41858
+ }
41859
+ async function diffPiExtensions(sourceDir, targetDir) {
41860
+ const sourceAbs = import_path12.default.resolve(sourceDir);
41861
+ const targetAbs = import_path12.default.resolve(targetDir);
41862
+ const sourceFiles = (await listTsFilesRecursive(sourceAbs)).map((f) => import_path12.default.relative(sourceAbs, f)).sort();
41863
+ const missing = [];
41864
+ const stale = [];
41865
+ const upToDate = [];
41866
+ for (const rel of sourceFiles) {
41867
+ const src = import_path12.default.join(sourceAbs, rel);
41868
+ const dst = import_path12.default.join(targetAbs, rel);
41869
+ if (!await import_fs_extra12.default.pathExists(dst)) {
41870
+ missing.push(rel);
41871
+ continue;
41872
+ }
41873
+ const [srcHash, dstHash] = await Promise.all([fileSha256(src), fileSha256(dst)]);
41874
+ if (srcHash !== dstHash) stale.push(rel);
41875
+ else upToDate.push(rel);
41876
+ }
41877
+ return { missing, stale, upToDate };
41878
+ }
41879
+ function printPiCheckSummary(diff) {
41880
+ const totalDiff = diff.missing.length + diff.stale.length;
41881
+ console.log(t.bold("\n Pi extension drift check\n"));
41882
+ console.log(t.muted(` Up-to-date: ${diff.upToDate.length}`));
41883
+ console.log(kleur_default.yellow(` Missing: ${diff.missing.length}`));
41884
+ console.log(kleur_default.yellow(` Stale: ${diff.stale.length}`));
41885
+ if (diff.missing.length > 0) {
41886
+ console.log(kleur_default.yellow("\n Missing files:"));
41887
+ diff.missing.forEach((f) => console.log(kleur_default.yellow(` - ${f}`)));
41888
+ }
41889
+ if (diff.stale.length > 0) {
41890
+ console.log(kleur_default.yellow("\n Stale files:"));
41891
+ diff.stale.forEach((f) => console.log(kleur_default.yellow(` - ${f}`)));
41892
+ }
41893
+ if (totalDiff === 0) {
41894
+ console.log(t.success("\n \u2713 Pi extensions are in sync\n"));
41895
+ }
41896
+ }
41726
41897
  function createInstallPiCommand() {
41727
41898
  const cmd = new Command("pi");
41728
- cmd.description("Install Pi coding agent with providers, extensions, and npm packages").option("-y, --yes", "Skip confirmation prompts", false).action(async (opts) => {
41729
- const { yes } = opts;
41899
+ cmd.description("Install Pi coding agent with providers, extensions, and npm packages").option("-y, --yes", "Skip confirmation prompts", false).option("--check", "Check Pi extension deployment drift without writing changes", false).action(async (opts) => {
41900
+ const { yes, check: check2 } = opts;
41730
41901
  const repoRoot = await findRepoRoot();
41731
41902
  const piConfigDir = import_path12.default.join(repoRoot, "config", "pi");
41903
+ if (check2) {
41904
+ const sourceDir = import_path12.default.join(piConfigDir, "extensions");
41905
+ const targetDir = import_path12.default.join(PI_AGENT_DIR, "extensions");
41906
+ const diff = await diffPiExtensions(sourceDir, targetDir);
41907
+ printPiCheckSummary(diff);
41908
+ if (diff.missing.length > 0 || diff.stale.length > 0) {
41909
+ console.error(kleur_default.red(" \u2717 Pi extension drift detected. Run `xtrm install pi` to sync.\n"));
41910
+ process.exit(1);
41911
+ }
41912
+ return;
41913
+ }
41732
41914
  console.log(t.bold("\n Pi Coding Agent Setup\n"));
41733
41915
  if (!isPiInstalled()) {
41734
41916
  console.log(kleur_default.yellow(" pi not found \u2014 installing oh-pi globally...\n"));
@@ -43051,10 +43233,10 @@ function mergeDefs(...defs) {
43051
43233
  function cloneDef(schema) {
43052
43234
  return mergeDefs(schema._zod.def);
43053
43235
  }
43054
- function getElementAtPath(obj, path18) {
43055
- if (!path18)
43236
+ function getElementAtPath(obj, path19) {
43237
+ if (!path19)
43056
43238
  return obj;
43057
- return path18.reduce((acc, key) => acc?.[key], obj);
43239
+ return path19.reduce((acc, key) => acc?.[key], obj);
43058
43240
  }
43059
43241
  function promiseAllObject(promisesObj) {
43060
43242
  const keys = Object.keys(promisesObj);
@@ -43437,11 +43619,11 @@ function aborted(x, startIndex = 0) {
43437
43619
  }
43438
43620
  return false;
43439
43621
  }
43440
- function prefixIssues(path18, issues) {
43622
+ function prefixIssues(path19, issues) {
43441
43623
  return issues.map((iss) => {
43442
43624
  var _a2;
43443
43625
  (_a2 = iss).path ?? (_a2.path = []);
43444
- iss.path.unshift(path18);
43626
+ iss.path.unshift(path19);
43445
43627
  return iss;
43446
43628
  });
43447
43629
  }
@@ -43624,7 +43806,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
43624
43806
  }
43625
43807
  function treeifyError(error49, mapper = (issue2) => issue2.message) {
43626
43808
  const result = { errors: [] };
43627
- const processError = (error50, path18 = []) => {
43809
+ const processError = (error50, path19 = []) => {
43628
43810
  var _a2, _b;
43629
43811
  for (const issue2 of error50.issues) {
43630
43812
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -43634,7 +43816,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
43634
43816
  } else if (issue2.code === "invalid_element") {
43635
43817
  processError({ issues: issue2.issues }, issue2.path);
43636
43818
  } else {
43637
- const fullpath = [...path18, ...issue2.path];
43819
+ const fullpath = [...path19, ...issue2.path];
43638
43820
  if (fullpath.length === 0) {
43639
43821
  result.errors.push(mapper(issue2));
43640
43822
  continue;
@@ -43666,8 +43848,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
43666
43848
  }
43667
43849
  function toDotPath(_path) {
43668
43850
  const segs = [];
43669
- const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
43670
- for (const seg of path18) {
43851
+ const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
43852
+ for (const seg of path19) {
43671
43853
  if (typeof seg === "number")
43672
43854
  segs.push(`[${seg}]`);
43673
43855
  else if (typeof seg === "symbol")
@@ -55644,13 +55826,13 @@ function resolveRef(ref, ctx) {
55644
55826
  if (!ref.startsWith("#")) {
55645
55827
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
55646
55828
  }
55647
- const path18 = ref.slice(1).split("/").filter(Boolean);
55648
- if (path18.length === 0) {
55829
+ const path19 = ref.slice(1).split("/").filter(Boolean);
55830
+ if (path19.length === 0) {
55649
55831
  return ctx.rootSchema;
55650
55832
  }
55651
55833
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
55652
- if (path18[0] === defsKey) {
55653
- const key = path18[1];
55834
+ if (path19[0] === defsKey) {
55835
+ const key = path19[1];
55654
55836
  if (!key || !ctx.defs[key]) {
55655
55837
  throw new Error(`Reference not found: ${ref}`);
55656
55838
  }
@@ -56230,18 +56412,21 @@ function createResetCommand() {
56230
56412
  var import_path16 = __toESM(require("path"), 1);
56231
56413
  var import_fs_extra15 = __toESM(require_lib2(), 1);
56232
56414
  var HOOK_CATALOG = [
56233
- { file: "main-guard.mjs", event: "PreToolUse", desc: "Blocks direct edits on protected branches" },
56415
+ { file: "main-guard.mjs", event: "PreToolUse", desc: "Blocks direct edits / unsafe Bash on protected branches" },
56234
56416
  { file: "main-guard-post-push.mjs", event: "PostToolUse", desc: "After feature-branch push, reminds PR/merge/sync steps" },
56235
- { file: "skill-suggestion.py", event: "UserPromptSubmit", desc: "Suggests relevant skills based on user prompt" },
56236
56417
  { file: "serena-workflow-reminder.py", event: "SessionStart", desc: "Injects Serena semantic editing workflow reminder" },
56237
- { file: "type-safety-enforcement.py", event: "PreToolUse", desc: "Prevents risky Bash and enforces safe edit patterns" },
56238
- { file: "gitnexus/gitnexus-hook.cjs", event: "PreToolUse", desc: "Adds GitNexus context for Grep/Glob/Bash searches" },
56239
- { file: "skill-discovery.py", event: "UserPromptSubmit", desc: "Discovers available skills for user requests" },
56418
+ { file: "gitnexus/gitnexus-hook.cjs", event: "PostToolUse", desc: "Adds GitNexus context for search and Serena tooling" },
56240
56419
  { file: "agent_context.py", event: "Support module", desc: "Shared hook I/O helper used by Python hook scripts" },
56241
56420
  { file: "beads-edit-gate.mjs", event: "PreToolUse", desc: "Blocks file edits if no beads issue is claimed", beads: true },
56242
56421
  { file: "beads-commit-gate.mjs", event: "PreToolUse", desc: "Blocks commits when no beads issue is in progress", beads: true },
56243
- { file: "beads-stop-gate.mjs", event: "Stop", desc: "Blocks session stop with an unclosed beads claim", beads: true },
56244
- { file: "beads-close-memory-prompt.mjs", event: "PostToolUse", desc: "Prompts memory save when closing a beads issue", beads: true }
56422
+ { file: "beads-memory-gate.mjs", event: "Stop", desc: "Prompts memory save when claim was closed", beads: true },
56423
+ { file: "beads-compact-save.mjs", event: "PreCompact", desc: "Saves in_progress issue + session-state bundle", beads: true },
56424
+ { file: "beads-compact-restore.mjs", event: "SessionStart", desc: "Restores compacted issue + session-state bundle", beads: true },
56425
+ { file: "beads-claim-sync.mjs", event: "PostToolUse", desc: "Auto-claim sync + worktree/session-state bootstrap", sessionFlow: true },
56426
+ { file: "beads-stop-gate.mjs", event: "Stop", desc: "Blocks stop for waiting-merge/conflicting/pending-cleanup", sessionFlow: true },
56427
+ { file: "branch-state.mjs", event: "UserPromptSubmit", desc: "Injects current git branch into prompt context" },
56428
+ { file: "quality-check.cjs", event: "PostToolUse", desc: "Runs JS/TS quality checks on mutating edits" },
56429
+ { file: "quality-check.py", event: "PostToolUse", desc: "Runs Python quality checks on mutating edits" }
56245
56430
  ];
56246
56431
  async function readSkillsFromDir(dir) {
56247
56432
  if (!await import_fs_extra15.default.pathExists(dir)) return [];
@@ -56325,8 +56510,9 @@ ${hr}`;
56325
56510
  "",
56326
56511
  ` ${kleur_default.dim("Flags (all profiles): --dry-run --yes / -y --no-mcp --force --prune --backport")}`
56327
56512
  ].join("\n");
56328
- const general = HOOK_CATALOG.filter((h) => !h.beads);
56513
+ const general = HOOK_CATALOG.filter((h) => !h.beads && !h.sessionFlow);
56329
56514
  const beads = HOOK_CATALOG.filter((h) => h.beads);
56515
+ const sessionFlow = HOOK_CATALOG.filter((h) => h.sessionFlow);
56330
56516
  const hookRows = (hooks) => hooks.map(
56331
56517
  (h) => ` ${kleur_default.white(col(h.file, 34))}${kleur_default.yellow(col(h.event, 20))}${kleur_default.dim(h.desc)}`
56332
56518
  ).join("\n");
@@ -56338,7 +56524,10 @@ ${hr}`;
56338
56524
  hookRows(general),
56339
56525
  "",
56340
56526
  ` ${kleur_default.dim("beads gate hooks (xtrm install all -- require beads+dolt):")}`,
56341
- hookRows(beads)
56527
+ hookRows(beads),
56528
+ "",
56529
+ ` ${kleur_default.dim("session-flow hooks (xtrm finish lifecycle):")}`,
56530
+ hookRows(sessionFlow)
56342
56531
  ].join("\n");
56343
56532
  const skillRows = skills.map((s) => {
56344
56533
  const desc = s.desc.length > 46 ? s.desc.slice(0, 45) + "\u2026" : s.desc;
@@ -56364,6 +56553,7 @@ ${hr}`;
56364
56553
  section("OTHER COMMANDS"),
56365
56554
  "",
56366
56555
  ` ${kleur_default.bold("xtrm status")} ${kleur_default.dim("Show pending changes without applying them")}`,
56556
+ ` ${kleur_default.bold("xtrm finish")} ${kleur_default.dim("Run blocking session closure lifecycle (PR + cleanup)")}`,
56367
56557
  ` ${kleur_default.bold("xtrm reset")} ${kleur_default.dim("Clear saved preferences and start fresh")}`,
56368
56558
  ` ${kleur_default.bold("xtrm help")} ${kleur_default.dim("Show this overview")}`
56369
56559
  ].join("\n");
@@ -56397,9 +56587,12 @@ var CANONICAL_HOOKS = /* @__PURE__ */ new Set([
56397
56587
  "beads-stop-gate.mjs",
56398
56588
  "beads-memory-gate.mjs",
56399
56589
  "beads-claim-sync.mjs",
56590
+ "session-state.mjs",
56400
56591
  "beads-compact-save.mjs",
56401
56592
  "beads-compact-restore.mjs",
56402
56593
  "branch-state.mjs",
56594
+ "quality-check.cjs",
56595
+ "quality-check.py",
56403
56596
  "gitnexus",
56404
56597
  // directory
56405
56598
  "statusline-starship.sh",
@@ -56427,7 +56620,12 @@ var CANONICAL_SKILLS = /* @__PURE__ */ new Set([
56427
56620
  "skill-creator",
56428
56621
  "using-serena-lsp",
56429
56622
  "using-TDD",
56430
- "using-xtrm"
56623
+ "using-xtrm",
56624
+ "using-quality-gates",
56625
+ "using-service-skills",
56626
+ "updating-service-skills",
56627
+ "creating-service-skills",
56628
+ "scoping-service-skills"
56431
56629
  ]);
56432
56630
  var IGNORED_ITEMS2 = /* @__PURE__ */ new Set([
56433
56631
  "__pycache__",
@@ -56665,6 +56863,303 @@ function createCleanCommand() {
56665
56863
  });
56666
56864
  }
56667
56865
 
56866
+ // src/core/xtrm-finish.ts
56867
+ var import_node_child_process3 = require("child_process");
56868
+ var import_node_fs5 = require("fs");
56869
+
56870
+ // src/core/session-state.ts
56871
+ var import_node_child_process2 = require("child_process");
56872
+ var import_node_fs4 = require("fs");
56873
+ var import_node_path5 = __toESM(require("path"), 1);
56874
+ var SESSION_STATE_FILE = ".xtrm-session-state.json";
56875
+ var SESSION_PHASES = [
56876
+ "claimed",
56877
+ "phase1-done",
56878
+ "waiting-merge",
56879
+ "conflicting",
56880
+ "pending-cleanup",
56881
+ "merged",
56882
+ "cleanup-done"
56883
+ ];
56884
+ var ALLOWED_TRANSITIONS = {
56885
+ claimed: ["phase1-done", "waiting-merge", "conflicting", "pending-cleanup", "cleanup-done"],
56886
+ "phase1-done": ["waiting-merge", "conflicting", "pending-cleanup", "cleanup-done"],
56887
+ "waiting-merge": ["conflicting", "pending-cleanup", "merged", "cleanup-done"],
56888
+ conflicting: ["waiting-merge", "pending-cleanup", "merged", "cleanup-done"],
56889
+ "pending-cleanup": ["waiting-merge", "conflicting", "merged", "cleanup-done"],
56890
+ merged: ["cleanup-done"],
56891
+ "cleanup-done": []
56892
+ };
56893
+ var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
56894
+ function isPhase(value) {
56895
+ return typeof value === "string" && SESSION_PHASES.includes(value);
56896
+ }
56897
+ function normalizeState(value) {
56898
+ if (!value || typeof value !== "object") {
56899
+ throw new Error("Invalid session state payload");
56900
+ }
56901
+ const state = value;
56902
+ if (!state.issueId || !state.branch || !state.worktreePath || !state.phase) {
56903
+ throw new Error("Session state requires issueId, branch, worktreePath, and phase");
56904
+ }
56905
+ if (!isPhase(state.phase)) throw new Error(`Invalid session phase: ${String(state.phase)}`);
56906
+ return {
56907
+ issueId: String(state.issueId),
56908
+ branch: String(state.branch),
56909
+ worktreePath: String(state.worktreePath),
56910
+ prNumber: state.prNumber ?? null,
56911
+ prUrl: state.prUrl ?? null,
56912
+ phase: state.phase,
56913
+ conflictFiles: Array.isArray(state.conflictFiles) ? state.conflictFiles.map(String) : [],
56914
+ startedAt: state.startedAt || nowIso(),
56915
+ lastChecked: nowIso()
56916
+ };
56917
+ }
56918
+ function findSessionStateFile(startCwd = process.cwd()) {
56919
+ let current = import_node_path5.default.resolve(startCwd);
56920
+ for (; ; ) {
56921
+ const candidate = import_node_path5.default.join(current, SESSION_STATE_FILE);
56922
+ if ((0, import_node_fs4.existsSync)(candidate)) return candidate;
56923
+ const parent = import_node_path5.default.dirname(current);
56924
+ if (parent === current) return null;
56925
+ current = parent;
56926
+ }
56927
+ }
56928
+ function readSessionState(startCwd = process.cwd()) {
56929
+ const filePath = findSessionStateFile(startCwd);
56930
+ if (!filePath) return null;
56931
+ try {
56932
+ const parsed = JSON.parse((0, import_node_fs4.readFileSync)(filePath, "utf8"));
56933
+ return normalizeState(parsed);
56934
+ } catch {
56935
+ return null;
56936
+ }
56937
+ }
56938
+ function updateSessionPhase(nextPhase, startCwd = process.cwd(), patch = {}) {
56939
+ const filePath = findSessionStateFile(startCwd);
56940
+ if (!filePath) throw new Error("Session state file not found");
56941
+ const current = readSessionState(startCwd);
56942
+ if (!current) throw new Error("Session state file invalid");
56943
+ if (!isPhase(nextPhase)) {
56944
+ throw new Error(`Invalid session phase: ${String(nextPhase)}`);
56945
+ }
56946
+ if (current.phase !== nextPhase && !ALLOWED_TRANSITIONS[current.phase].includes(nextPhase)) {
56947
+ throw new Error(`Invalid phase transition: ${current.phase} -> ${nextPhase}`);
56948
+ }
56949
+ const nextState = normalizeState({
56950
+ ...current,
56951
+ ...patch,
56952
+ phase: nextPhase
56953
+ });
56954
+ (0, import_node_fs4.writeFileSync)(filePath, JSON.stringify(nextState, null, 2) + "\n", "utf8");
56955
+ return nextState;
56956
+ }
56957
+
56958
+ // src/core/xtrm-finish.ts
56959
+ var DEFAULT_POLL_INTERVAL_MS = 5e3;
56960
+ var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
56961
+ function run2(cmd, args, cwd) {
56962
+ const r = (0, import_node_child_process3.spawnSync)(cmd, args, {
56963
+ cwd,
56964
+ encoding: "utf8",
56965
+ stdio: ["pipe", "pipe", "pipe"]
56966
+ });
56967
+ return {
56968
+ code: r.status ?? 1,
56969
+ stdout: (r.stdout ?? "").trim(),
56970
+ stderr: (r.stderr ?? "").trim()
56971
+ };
56972
+ }
56973
+ function parsePrCreate(stdout) {
56974
+ const urlMatch = stdout.match(/https?:\/\/\S+\/pull\/(\d+)/);
56975
+ if (urlMatch) {
56976
+ return { prNumber: Number(urlMatch[1]), prUrl: urlMatch[0] };
56977
+ }
56978
+ const numberMatch = stdout.match(/#(\d+)/);
56979
+ if (numberMatch) {
56980
+ return { prNumber: Number(numberMatch[1]), prUrl: null };
56981
+ }
56982
+ return { prNumber: null, prUrl: null };
56983
+ }
56984
+ function getConflictFiles(cwd) {
56985
+ const out = run2("git", ["diff", "--name-only", "--diff-filter=U"], cwd);
56986
+ if (out.code !== 0 || !out.stdout) return [];
56987
+ return out.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
56988
+ }
56989
+ async function delay2(ms) {
56990
+ if (ms <= 0) return;
56991
+ await new Promise((resolve2) => setTimeout(resolve2, ms));
56992
+ }
56993
+ function ensureCleanPhaseTransition(cwd, phase, patch = {}) {
56994
+ try {
56995
+ updateSessionPhase(phase, cwd, patch);
56996
+ } catch {
56997
+ }
56998
+ }
56999
+ function handleRebaseAndPush(cwd) {
57000
+ const fetch = run2("git", ["fetch", "origin"], cwd);
57001
+ if (fetch.code !== 0) return { ok: false, error: fetch.stderr || fetch.stdout };
57002
+ const rebase = run2("git", ["rebase", "origin/main"], cwd);
57003
+ if (rebase.code !== 0) {
57004
+ const conflicts = getConflictFiles(cwd);
57005
+ return { ok: false, conflicts, error: rebase.stderr || rebase.stdout };
57006
+ }
57007
+ const push = run2("git", ["push", "--force-with-lease"], cwd);
57008
+ if (push.code !== 0) {
57009
+ return { ok: false, error: push.stderr || push.stdout };
57010
+ }
57011
+ return { ok: true };
57012
+ }
57013
+ function cleanupPhase(cwd, state) {
57014
+ if ((0, import_node_fs5.existsSync)(state.worktreePath)) {
57015
+ const rm = run2("git", ["worktree", "remove", state.worktreePath, "--force"], cwd);
57016
+ if (rm.code !== 0) {
57017
+ return { ok: false, message: rm.stderr || rm.stdout || `Failed to remove worktree ${state.worktreePath}` };
57018
+ }
57019
+ }
57020
+ run2("git", ["fetch", "--prune"], cwd);
57021
+ ensureCleanPhaseTransition(cwd, "cleanup-done");
57022
+ const prLabel = state.prNumber != null ? `#${state.prNumber}` : "(unknown PR)";
57023
+ return { ok: true, message: `Done. PR ${prLabel} merged. Worktree removed.` };
57024
+ }
57025
+ async function pollUntilMerged(cwd, state, opts) {
57026
+ if (state.prNumber == null) {
57027
+ return { ok: false, message: "Session state missing prNumber. Re-run phase 1 before polling." };
57028
+ }
57029
+ const started = Date.now();
57030
+ while (Date.now() - started < opts.timeoutMs) {
57031
+ const view = run2("gh", ["pr", "view", String(state.prNumber), "--json", "state,mergeStateStatus,mergeable"], cwd);
57032
+ if (view.code !== 0) {
57033
+ return { ok: false, message: view.stderr || view.stdout || `Failed to inspect PR #${state.prNumber}` };
57034
+ }
57035
+ let payload = null;
57036
+ try {
57037
+ payload = JSON.parse(view.stdout);
57038
+ } catch {
57039
+ return { ok: false, message: `Unable to parse gh pr view output for #${state.prNumber}` };
57040
+ }
57041
+ ensureCleanPhaseTransition(cwd, "waiting-merge");
57042
+ if (payload.state === "MERGED") {
57043
+ ensureCleanPhaseTransition(cwd, "merged");
57044
+ const latest = readSessionState(cwd) ?? state;
57045
+ return cleanupPhase(cwd, latest);
57046
+ }
57047
+ if (payload.mergeStateStatus === "BEHIND") {
57048
+ run2("git", ["fetch", "origin"], cwd);
57049
+ run2("git", ["push"], cwd);
57050
+ await delay2(opts.pollIntervalMs);
57051
+ continue;
57052
+ }
57053
+ if (payload.mergeable === "CONFLICTING") {
57054
+ const rebased = handleRebaseAndPush(cwd);
57055
+ if (!rebased.ok) {
57056
+ const conflictFiles = rebased.conflicts ?? getConflictFiles(cwd);
57057
+ ensureCleanPhaseTransition(cwd, "conflicting", { conflictFiles });
57058
+ return {
57059
+ ok: false,
57060
+ message: `Conflicts in: ${conflictFiles.join(", ") || "unknown files"}. Resolve, push, then re-run xtrm finish.`
57061
+ };
57062
+ }
57063
+ ensureCleanPhaseTransition(cwd, "waiting-merge", { conflictFiles: [] });
57064
+ await delay2(opts.pollIntervalMs);
57065
+ continue;
57066
+ }
57067
+ await delay2(opts.pollIntervalMs);
57068
+ }
57069
+ ensureCleanPhaseTransition(cwd, "pending-cleanup");
57070
+ return {
57071
+ ok: false,
57072
+ message: `PR #${state.prNumber} not yet merged. Run xtrm finish when ready.`
57073
+ };
57074
+ }
57075
+ function isWorkingTreeDirty(cwd) {
57076
+ const st = run2("git", ["status", "--porcelain"], cwd);
57077
+ return st.code === 0 && st.stdout.length > 0;
57078
+ }
57079
+ function runPhase1(cwd, state) {
57080
+ if (isWorkingTreeDirty(cwd)) {
57081
+ const add = run2("git", ["add", "-A"], cwd);
57082
+ if (add.code !== 0) return { ok: false, message: add.stderr || add.stdout };
57083
+ const msg = `feat(${state.issueId}): ${state.branch}`;
57084
+ const commit = run2("git", ["commit", "-m", msg], cwd);
57085
+ if (commit.code !== 0) {
57086
+ return { ok: false, message: commit.stderr || commit.stdout || "git commit failed" };
57087
+ }
57088
+ }
57089
+ const push = run2("git", ["push", "-u", "origin", state.branch], cwd);
57090
+ if (push.code !== 0) return { ok: false, message: push.stderr || push.stdout || "git push failed" };
57091
+ const create = run2("gh", ["pr", "create", "--fill"], cwd);
57092
+ if (create.code !== 0) return { ok: false, message: create.stderr || create.stdout || "gh pr create failed" };
57093
+ const parsed = parsePrCreate(create.stdout);
57094
+ const merge2 = run2("gh", ["pr", "merge", "--squash", "--auto"], cwd);
57095
+ if (merge2.code !== 0) return { ok: false, message: merge2.stderr || merge2.stdout || "gh pr merge failed" };
57096
+ ensureCleanPhaseTransition(cwd, "phase1-done", {
57097
+ prNumber: parsed.prNumber,
57098
+ prUrl: parsed.prUrl
57099
+ });
57100
+ ensureCleanPhaseTransition(cwd, "waiting-merge", {
57101
+ prNumber: parsed.prNumber,
57102
+ prUrl: parsed.prUrl
57103
+ });
57104
+ return { ok: true, message: "phase1 complete" };
57105
+ }
57106
+ async function runXtrmFinish(options = {}) {
57107
+ const cwd = options.cwd ?? process.cwd();
57108
+ const state = readSessionState(cwd);
57109
+ if (!state) {
57110
+ return { ok: false, message: "No .xtrm-session-state.json found. Claim an issue first (bd update <id> --claim)." };
57111
+ }
57112
+ const opts = {
57113
+ cwd,
57114
+ pollIntervalMs: options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,
57115
+ timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS
57116
+ };
57117
+ if (state.phase === "cleanup-done") {
57118
+ return { ok: true, message: "Session is already cleanup-done." };
57119
+ }
57120
+ if (state.phase === "conflicting") {
57121
+ const resolved = handleRebaseAndPush(cwd);
57122
+ if (!resolved.ok) {
57123
+ const files = resolved.conflicts ?? getConflictFiles(cwd);
57124
+ ensureCleanPhaseTransition(cwd, "conflicting", { conflictFiles: files });
57125
+ return { ok: false, message: `Conflicts in: ${files.join(", ") || "unknown files"}. Resolve, push, then re-run xtrm finish.` };
57126
+ }
57127
+ ensureCleanPhaseTransition(cwd, "waiting-merge", { conflictFiles: [] });
57128
+ const refreshed2 = readSessionState(cwd) ?? state;
57129
+ return pollUntilMerged(cwd, refreshed2, opts);
57130
+ }
57131
+ if (state.phase === "waiting-merge" || state.phase === "pending-cleanup" || state.phase === "merged") {
57132
+ const refreshed2 = readSessionState(cwd) ?? state;
57133
+ if (refreshed2.phase === "merged") return cleanupPhase(cwd, refreshed2);
57134
+ return pollUntilMerged(cwd, refreshed2, opts);
57135
+ }
57136
+ const phase1 = runPhase1(cwd, state);
57137
+ if (!phase1.ok) return phase1;
57138
+ const refreshed = readSessionState(cwd) ?? state;
57139
+ return pollUntilMerged(cwd, refreshed, opts);
57140
+ }
57141
+
57142
+ // src/commands/finish.ts
57143
+ function createFinishCommand() {
57144
+ return new Command("finish").description("Complete session closure lifecycle (phase1 + merge polling + cleanup)").option("--poll-interval-ms <ms>", "Polling interval for PR state checks", (v) => Number(v), 5e3).option("--timeout-ms <ms>", "Maximum wait time before pending-cleanup", (v) => Number(v), 10 * 60 * 1e3).action(async (opts) => {
57145
+ const result = await runXtrmFinish({
57146
+ cwd: process.cwd(),
57147
+ pollIntervalMs: opts.pollIntervalMs,
57148
+ timeoutMs: opts.timeoutMs
57149
+ });
57150
+ if (result.ok) {
57151
+ console.log(kleur_default.green(`
57152
+ \u2713 ${result.message}
57153
+ `));
57154
+ return;
57155
+ }
57156
+ console.error(kleur_default.red(`
57157
+ \u2717 ${result.message}
57158
+ `));
57159
+ process.exitCode = 1;
57160
+ });
57161
+ }
57162
+
56668
57163
  // src/utils/banner.ts
56669
57164
  var ART = [
56670
57165
  " \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
@@ -56732,7 +57227,7 @@ function pressAnyKey() {
56732
57227
  setTimeout(finish, 4e3);
56733
57228
  });
56734
57229
  }
56735
- function delay2(ms) {
57230
+ function delay3(ms) {
56736
57231
  return new Promise((r) => setTimeout(r, ms));
56737
57232
  }
56738
57233
  async function typewriterTagline(text) {
@@ -56742,7 +57237,7 @@ async function typewriterTagline(text) {
56742
57237
  process.stdout.write(prefix);
56743
57238
  for (const ch of text) {
56744
57239
  process.stdout.write(ch);
56745
- await delay2(CHAR_DELAY);
57240
+ await delay3(CHAR_DELAY);
56746
57241
  }
56747
57242
  process.stdout.write(suffix + "\n");
56748
57243
  }
@@ -56837,7 +57332,7 @@ async function printBanner(version3) {
56837
57332
  // src/index.ts
56838
57333
  var version2 = "0.0.0";
56839
57334
  try {
56840
- version2 = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path5.resolve)(__dirname, "../package.json"), "utf8")).version;
57335
+ version2 = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path6.resolve)(__dirname, "../package.json"), "utf8")).version;
56841
57336
  } catch {
56842
57337
  }
56843
57338
  var program2 = new Command();
@@ -56853,9 +57348,13 @@ program2.exitOverride((err) => {
56853
57348
  });
56854
57349
  program2.addCommand(createInstallCommand());
56855
57350
  program2.addCommand(createProjectCommand());
57351
+ program2.command("init").description("Alias for xtrm project init").action(async () => {
57352
+ await runProjectInit();
57353
+ });
56856
57354
  program2.addCommand(createStatusCommand());
56857
57355
  program2.addCommand(createResetCommand());
56858
57356
  program2.addCommand(createCleanCommand());
57357
+ program2.addCommand(createFinishCommand());
56859
57358
  program2.addCommand(createHelpCommand());
56860
57359
  program2.action(async () => {
56861
57360
  program2.help();