@osfactory/har 0.56.1 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -553,8 +553,8 @@ var init_parseUtil = __esm({
553
553
  init_errors();
554
554
  init_en();
555
555
  makeIssue = (params) => {
556
- const { data, path: path62, errorMaps, issueData } = params;
557
- const fullPath = [...path62, ...issueData.path || []];
556
+ const { data, path: path65, errorMaps, issueData } = params;
557
+ const fullPath = [...path65, ...issueData.path || []];
558
558
  const fullIssue = {
559
559
  ...issueData,
560
560
  path: fullPath
@@ -862,11 +862,11 @@ var init_types = __esm({
862
862
  init_parseUtil();
863
863
  init_util();
864
864
  ParseInputLazyPath = class {
865
- constructor(parent, value, path62, key) {
865
+ constructor(parent, value, path65, key) {
866
866
  this._cachedPath = [];
867
867
  this.parent = parent;
868
868
  this.data = value;
869
- this._path = path62;
869
+ this._path = path65;
870
870
  this._key = key;
871
871
  }
872
872
  get path() {
@@ -28353,6 +28353,7 @@ var init_manifest = __esm({
28353
28353
  DEFAULT_HAR_DIR = ".har";
28354
28354
  CHECKSUM_SKIP = /* @__PURE__ */ new Set([
28355
28355
  "manifest.json",
28356
+ "plugins.json",
28356
28357
  "AGENTS.md.proposed",
28357
28358
  "AGENTS.md.proposed.meta.json",
28358
28359
  "AGENT.md.proposed",
@@ -28757,7 +28758,7 @@ function runScript(scriptPath, args = [], options = {}) {
28757
28758
  function runScriptCapture(scriptPath, args = [], options = {}) {
28758
28759
  const stream = options.stream ?? false;
28759
28760
  const { stream: _stream, ...spawnOptions } = options;
28760
- return new Promise((resolve47) => {
28761
+ return new Promise((resolve49) => {
28761
28762
  const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
28762
28763
  ...spawnOptions,
28763
28764
  stdio: ["inherit", "pipe", "pipe"]
@@ -28772,13 +28773,13 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
28772
28773
  stderr += d;
28773
28774
  if (stream) process.stderr.write(d);
28774
28775
  });
28775
- proc.on("close", (code) => resolve47({ stdout, stderr, code: code ?? 0 }));
28776
+ proc.on("close", (code) => resolve49({ stdout, stderr, code: code ?? 0 }));
28776
28777
  });
28777
28778
  }
28778
28779
  function runShellCommand(command2, options = {}) {
28779
28780
  const stream = options.stream ?? false;
28780
28781
  const { stream: _stream, ...spawnOptions } = options;
28781
- return new Promise((resolve47) => {
28782
+ return new Promise((resolve49) => {
28782
28783
  const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
28783
28784
  ...spawnOptions,
28784
28785
  stdio: ["inherit", "pipe", "pipe"]
@@ -28793,7 +28794,7 @@ function runShellCommand(command2, options = {}) {
28793
28794
  stderr += d;
28794
28795
  if (stream) process.stderr.write(d);
28795
28796
  });
28796
- proc.on("close", (code) => resolve47({ stdout, stderr, code: code ?? 0 }));
28797
+ proc.on("close", (code) => resolve49({ stdout, stderr, code: code ?? 0 }));
28797
28798
  });
28798
28799
  }
28799
28800
  var import_child_process;
@@ -29495,6 +29496,22 @@ var init_runs = __esm({
29495
29496
  }
29496
29497
  });
29497
29498
 
29499
+ // src/harness/capabilities.ts
29500
+ function harnessUsesPm2(repoPath) {
29501
+ const harnessRoot = resolveHarnessRoot(repoPath);
29502
+ return fs13.existsSync(path13.join(harnessRoot, ".har", "ecosystem.agent.template.cjs"));
29503
+ }
29504
+ var fs13, path13;
29505
+ var init_capabilities = __esm({
29506
+ "src/harness/capabilities.ts"() {
29507
+ "use strict";
29508
+ fs13 = __toESM(require("fs"));
29509
+ path13 = __toESM(require("path"));
29510
+ init_manifest();
29511
+ init_env();
29512
+ }
29513
+ });
29514
+
29498
29515
  // src/core/slot-ports.ts
29499
29516
  function portStep(env3) {
29500
29517
  return Number(env3.HARNESS_PORT_STEP ?? 10);
@@ -29549,19 +29566,14 @@ function allocateAppPorts(repoPath, agentId) {
29549
29566
  allocated: frontend !== feDefault || api !== apiDefault || debug !== debugDefault
29550
29567
  };
29551
29568
  }
29552
- function harnessUsesPm2(repoPath) {
29553
- const harnessRoot = resolveHarnessRoot(repoPath);
29554
- return fs13.existsSync(path13.join(harnessRoot, ".har", "ecosystem.agent.template.cjs"));
29555
- }
29556
- var import_child_process3, fs13, path13;
29569
+ var import_child_process3;
29557
29570
  var init_slot_ports = __esm({
29558
29571
  "src/core/slot-ports.ts"() {
29559
29572
  "use strict";
29560
29573
  import_child_process3 = require("child_process");
29561
- fs13 = __toESM(require("fs"));
29562
- path13 = __toESM(require("path"));
29563
29574
  init_env();
29564
29575
  init_manifest();
29576
+ init_capabilities();
29565
29577
  }
29566
29578
  });
29567
29579
 
@@ -30628,6 +30640,7 @@ var init_slot_preflight = __esm({
30628
30640
  init_control_port();
30629
30641
  init_slot_launch_guard_occupied();
30630
30642
  init_slot_ports();
30643
+ init_capabilities();
30631
30644
  init_slot_registry();
30632
30645
  init_worktree_untracked();
30633
30646
  import_child_process8 = require("child_process");
@@ -32418,7 +32431,7 @@ async function postForResponse(url, headers, payload) {
32418
32431
  } catch (err) {
32419
32432
  lastErr = err;
32420
32433
  if (attempt < MAX_FETCH_ATTEMPTS) {
32421
- await new Promise((resolve47) => setTimeout(resolve47, attempt * 100));
32434
+ await new Promise((resolve49) => setTimeout(resolve49, attempt * 100));
32422
32435
  }
32423
32436
  }
32424
32437
  }
@@ -32618,7 +32631,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
32618
32631
  const deadline = Date.now() + timeoutMs;
32619
32632
  while (Date.now() < deadline) {
32620
32633
  if (await isControlApiReachable(apiUrl)) return true;
32621
- await new Promise((resolve47) => setTimeout(resolve47, intervalMs));
32634
+ await new Promise((resolve49) => setTimeout(resolve49, intervalMs));
32622
32635
  }
32623
32636
  return false;
32624
32637
  }
@@ -34115,15 +34128,15 @@ var require_route = __commonJS({
34115
34128
  };
34116
34129
  }
34117
34130
  function wrapConversion(toModel, graph) {
34118
- const path62 = [graph[toModel].parent, toModel];
34131
+ const path65 = [graph[toModel].parent, toModel];
34119
34132
  let fn = conversions[graph[toModel].parent][toModel];
34120
34133
  let cur = graph[toModel].parent;
34121
34134
  while (graph[cur].parent) {
34122
- path62.unshift(graph[cur].parent);
34135
+ path65.unshift(graph[cur].parent);
34123
34136
  fn = link(conversions[graph[cur].parent][cur], fn);
34124
34137
  cur = graph[cur].parent;
34125
34138
  }
34126
- fn.conversion = path62;
34139
+ fn.conversion = path65;
34127
34140
  return fn;
34128
34141
  }
34129
34142
  module2.exports = function(fromModel) {
@@ -40053,7 +40066,7 @@ var require_iso2022 = __commonJS({
40053
40066
  // node_modules/chardet/index.js
40054
40067
  var require_chardet = __commonJS({
40055
40068
  "node_modules/chardet/index.js"(exports2, module2) {
40056
- var fs48 = require("fs");
40069
+ var fs51 = require("fs");
40057
40070
  var utf8 = require_utf8();
40058
40071
  var unicode = require_unicode();
40059
40072
  var mbcs = require_mbcs();
@@ -40127,28 +40140,28 @@ var require_chardet = __commonJS({
40127
40140
  var fd;
40128
40141
  var handler = function(err, buffer) {
40129
40142
  if (fd) {
40130
- fs48.closeSync(fd);
40143
+ fs51.closeSync(fd);
40131
40144
  }
40132
40145
  if (err) return cb(err, null);
40133
40146
  cb(null, self.detect(buffer, opts));
40134
40147
  };
40135
40148
  if (opts && opts.sampleSize) {
40136
- fd = fs48.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40137
- fs48.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40149
+ fd = fs51.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40150
+ fs51.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40138
40151
  handler(err, sample);
40139
40152
  });
40140
40153
  return;
40141
40154
  }
40142
- fs48.readFile(filepath, handler);
40155
+ fs51.readFile(filepath, handler);
40143
40156
  };
40144
40157
  module2.exports.detectFileSync = function(filepath, opts) {
40145
40158
  if (opts && opts.sampleSize) {
40146
- var fd = fs48.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40147
- fs48.readSync(fd, sample2, 0, opts.sampleSize);
40148
- fs48.closeSync(fd);
40159
+ var fd = fs51.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40160
+ fs51.readSync(fd, sample2, 0, opts.sampleSize);
40161
+ fs51.closeSync(fd);
40149
40162
  return self.detect(sample2, opts);
40150
40163
  }
40151
- return self.detect(fs48.readFileSync(filepath), opts);
40164
+ return self.detect(fs51.readFileSync(filepath), opts);
40152
40165
  };
40153
40166
  module2.exports.detectAll = function(buffer, opts) {
40154
40167
  if (typeof opts !== "object") {
@@ -43613,16 +43626,16 @@ var require_os_tmpdir = __commonJS({
43613
43626
  var isWindows = process.platform === "win32";
43614
43627
  var trailingSlashRe = isWindows ? /[^:]\\$/ : /.\/$/;
43615
43628
  module2.exports = function() {
43616
- var path62;
43629
+ var path65;
43617
43630
  if (isWindows) {
43618
- path62 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43631
+ path65 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43619
43632
  } else {
43620
- path62 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43633
+ path65 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43621
43634
  }
43622
- if (trailingSlashRe.test(path62)) {
43623
- path62 = path62.slice(0, -1);
43635
+ if (trailingSlashRe.test(path65)) {
43636
+ path65 = path65.slice(0, -1);
43624
43637
  }
43625
- return path62;
43638
+ return path65;
43626
43639
  };
43627
43640
  }
43628
43641
  });
@@ -43630,8 +43643,8 @@ var require_os_tmpdir = __commonJS({
43630
43643
  // node_modules/tmp/lib/tmp.js
43631
43644
  var require_tmp = __commonJS({
43632
43645
  "node_modules/tmp/lib/tmp.js"(exports2, module2) {
43633
- var fs48 = require("fs");
43634
- var path62 = require("path");
43646
+ var fs51 = require("fs");
43647
+ var path65 = require("path");
43635
43648
  var crypto6 = require("crypto");
43636
43649
  var osTmpDir = require_os_tmpdir();
43637
43650
  var _c2 = process.binding("constants");
@@ -43673,7 +43686,7 @@ var require_tmp = __commonJS({
43673
43686
  }
43674
43687
  function _generateTmpName(opts) {
43675
43688
  if (opts.name) {
43676
- return path62.join(opts.dir || tmpDir, opts.name);
43689
+ return path65.join(opts.dir || tmpDir, opts.name);
43677
43690
  }
43678
43691
  if (opts.template) {
43679
43692
  return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
@@ -43684,7 +43697,7 @@ var require_tmp = __commonJS({
43684
43697
  _randomChars(12),
43685
43698
  opts.postfix || ""
43686
43699
  ].join("");
43687
- return path62.join(opts.dir || tmpDir, name);
43700
+ return path65.join(opts.dir || tmpDir, name);
43688
43701
  }
43689
43702
  function tmpName(options, callback) {
43690
43703
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1], tries = opts.name ? 1 : opts.tries || DEFAULT_TRIES;
@@ -43694,7 +43707,7 @@ var require_tmp = __commonJS({
43694
43707
  return cb(new Error("Invalid template provided"));
43695
43708
  (function _getUniqueName() {
43696
43709
  const name = _generateTmpName(opts);
43697
- fs48.stat(name, function(err) {
43710
+ fs51.stat(name, function(err) {
43698
43711
  if (!err) {
43699
43712
  if (tries-- > 0) return _getUniqueName();
43700
43713
  return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
@@ -43712,7 +43725,7 @@ var require_tmp = __commonJS({
43712
43725
  do {
43713
43726
  const name = _generateTmpName(opts);
43714
43727
  try {
43715
- fs48.statSync(name);
43728
+ fs51.statSync(name);
43716
43729
  } catch (e) {
43717
43730
  return name;
43718
43731
  }
@@ -43724,13 +43737,13 @@ var require_tmp = __commonJS({
43724
43737
  opts.postfix = _isUndefined(opts.postfix) ? ".tmp" : opts.postfix;
43725
43738
  tmpName(opts, function _tmpNameCreated(err, name) {
43726
43739
  if (err) return cb(err);
43727
- fs48.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43740
+ fs51.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43728
43741
  if (err2) return cb(err2);
43729
43742
  if (opts.discardDescriptor) {
43730
- return fs48.close(fd, function _discardCallback(err3) {
43743
+ return fs51.close(fd, function _discardCallback(err3) {
43731
43744
  if (err3) {
43732
43745
  try {
43733
- fs48.unlinkSync(name);
43746
+ fs51.unlinkSync(name);
43734
43747
  } catch (e) {
43735
43748
  if (!isENOENT(e)) {
43736
43749
  err3 = e;
@@ -43753,9 +43766,9 @@ var require_tmp = __commonJS({
43753
43766
  opts.postfix = opts.postfix || ".tmp";
43754
43767
  const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
43755
43768
  const name = tmpNameSync(opts);
43756
- var fd = fs48.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43769
+ var fd = fs51.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43757
43770
  if (opts.discardDescriptor) {
43758
- fs48.closeSync(fd);
43771
+ fs51.closeSync(fd);
43759
43772
  fd = void 0;
43760
43773
  }
43761
43774
  return {
@@ -43767,9 +43780,9 @@ var require_tmp = __commonJS({
43767
43780
  function _rmdirRecursiveSync(root) {
43768
43781
  const dirs = [root];
43769
43782
  do {
43770
- var dir2 = dirs.pop(), deferred = false, files = fs48.readdirSync(dir2);
43783
+ var dir2 = dirs.pop(), deferred = false, files = fs51.readdirSync(dir2);
43771
43784
  for (var i = 0, length = files.length; i < length; i++) {
43772
- var file2 = path62.join(dir2, files[i]), stat = fs48.lstatSync(file2);
43785
+ var file2 = path65.join(dir2, files[i]), stat = fs51.lstatSync(file2);
43773
43786
  if (stat.isDirectory()) {
43774
43787
  if (!deferred) {
43775
43788
  deferred = true;
@@ -43777,11 +43790,11 @@ var require_tmp = __commonJS({
43777
43790
  }
43778
43791
  dirs.push(file2);
43779
43792
  } else {
43780
- fs48.unlinkSync(file2);
43793
+ fs51.unlinkSync(file2);
43781
43794
  }
43782
43795
  }
43783
43796
  if (!deferred) {
43784
- fs48.rmdirSync(dir2);
43797
+ fs51.rmdirSync(dir2);
43785
43798
  }
43786
43799
  } while (dirs.length !== 0);
43787
43800
  }
@@ -43789,7 +43802,7 @@ var require_tmp = __commonJS({
43789
43802
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1];
43790
43803
  tmpName(opts, function _tmpNameCreated(err, name) {
43791
43804
  if (err) return cb(err);
43792
- fs48.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43805
+ fs51.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43793
43806
  if (err2) return cb(err2);
43794
43807
  cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
43795
43808
  });
@@ -43798,7 +43811,7 @@ var require_tmp = __commonJS({
43798
43811
  function dirSync(options) {
43799
43812
  var args = _parseArguments(options), opts = args[0];
43800
43813
  const name = tmpNameSync(opts);
43801
- fs48.mkdirSync(name, opts.mode || DIR_MODE);
43814
+ fs51.mkdirSync(name, opts.mode || DIR_MODE);
43802
43815
  return {
43803
43816
  name,
43804
43817
  removeCallback: _prepareTmpDirRemoveCallback(name, opts)
@@ -43808,7 +43821,7 @@ var require_tmp = __commonJS({
43808
43821
  const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
43809
43822
  try {
43810
43823
  if (0 <= fdPath[0]) {
43811
- fs48.closeSync(fdPath[0]);
43824
+ fs51.closeSync(fdPath[0]);
43812
43825
  }
43813
43826
  } catch (e) {
43814
43827
  if (!isEBADF(e) && !isENOENT(e)) {
@@ -43816,7 +43829,7 @@ var require_tmp = __commonJS({
43816
43829
  }
43817
43830
  }
43818
43831
  try {
43819
- fs48.unlinkSync(fdPath[1]);
43832
+ fs51.unlinkSync(fdPath[1]);
43820
43833
  } catch (e) {
43821
43834
  if (!isENOENT(e)) {
43822
43835
  throw e;
@@ -43829,7 +43842,7 @@ var require_tmp = __commonJS({
43829
43842
  return removeCallback;
43830
43843
  }
43831
43844
  function _prepareTmpDirRemoveCallback(name, opts) {
43832
- const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs48.rmdirSync.bind(fs48);
43845
+ const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs51.rmdirSync.bind(fs51);
43833
43846
  const removeCallback = _prepareRemoveCallback(removeFunction, name);
43834
43847
  if (!opts.keep) {
43835
43848
  _removeObjects.unshift(removeCallback);
@@ -44980,7 +44993,7 @@ var require_Observable = __commonJS({
44980
44993
  Observable2.prototype.forEach = function(next, promiseCtor) {
44981
44994
  var _this = this;
44982
44995
  promiseCtor = getPromiseCtor(promiseCtor);
44983
- return new promiseCtor(function(resolve47, reject) {
44996
+ return new promiseCtor(function(resolve49, reject) {
44984
44997
  var subscriber = new Subscriber_1.SafeSubscriber({
44985
44998
  next: function(value) {
44986
44999
  try {
@@ -44991,7 +45004,7 @@ var require_Observable = __commonJS({
44991
45004
  }
44992
45005
  },
44993
45006
  error: reject,
44994
- complete: resolve47
45007
+ complete: resolve49
44995
45008
  });
44996
45009
  _this.subscribe(subscriber);
44997
45010
  });
@@ -45013,14 +45026,14 @@ var require_Observable = __commonJS({
45013
45026
  Observable2.prototype.toPromise = function(promiseCtor) {
45014
45027
  var _this = this;
45015
45028
  promiseCtor = getPromiseCtor(promiseCtor);
45016
- return new promiseCtor(function(resolve47, reject) {
45029
+ return new promiseCtor(function(resolve49, reject) {
45017
45030
  var value;
45018
45031
  _this.subscribe(function(x) {
45019
45032
  return value = x;
45020
45033
  }, function(err) {
45021
45034
  return reject(err);
45022
45035
  }, function() {
45023
- return resolve47(value);
45036
+ return resolve49(value);
45024
45037
  });
45025
45038
  });
45026
45039
  };
@@ -47116,11 +47129,11 @@ var require_innerFrom = __commonJS({
47116
47129
  "use strict";
47117
47130
  var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
47118
47131
  function adopt(value) {
47119
- return value instanceof P2 ? value : new P2(function(resolve47) {
47120
- resolve47(value);
47132
+ return value instanceof P2 ? value : new P2(function(resolve49) {
47133
+ resolve49(value);
47121
47134
  });
47122
47135
  }
47123
- return new (P2 || (P2 = Promise))(function(resolve47, reject) {
47136
+ return new (P2 || (P2 = Promise))(function(resolve49, reject) {
47124
47137
  function fulfilled(value) {
47125
47138
  try {
47126
47139
  step(generator.next(value));
@@ -47136,7 +47149,7 @@ var require_innerFrom = __commonJS({
47136
47149
  }
47137
47150
  }
47138
47151
  function step(result) {
47139
- result.done ? resolve47(result.value) : adopt(result.value).then(fulfilled, rejected);
47152
+ result.done ? resolve49(result.value) : adopt(result.value).then(fulfilled, rejected);
47140
47153
  }
47141
47154
  step((generator = generator.apply(thisArg, _arguments || [])).next());
47142
47155
  });
@@ -47218,14 +47231,14 @@ var require_innerFrom = __commonJS({
47218
47231
  }, i);
47219
47232
  function verb(n) {
47220
47233
  i[n] = o[n] && function(v2) {
47221
- return new Promise(function(resolve47, reject) {
47222
- v2 = o[n](v2), settle(resolve47, reject, v2.done, v2.value);
47234
+ return new Promise(function(resolve49, reject) {
47235
+ v2 = o[n](v2), settle(resolve49, reject, v2.done, v2.value);
47223
47236
  });
47224
47237
  };
47225
47238
  }
47226
- function settle(resolve47, reject, d, v2) {
47239
+ function settle(resolve49, reject, d, v2) {
47227
47240
  Promise.resolve(v2).then(function(v3) {
47228
- resolve47({ value: v3, done: d });
47241
+ resolve49({ value: v3, done: d });
47229
47242
  }, reject);
47230
47243
  }
47231
47244
  };
@@ -47844,7 +47857,7 @@ var require_lastValueFrom = __commonJS({
47844
47857
  var EmptyError_1 = require_EmptyError();
47845
47858
  function lastValueFrom2(source, config2) {
47846
47859
  var hasConfig = typeof config2 === "object";
47847
- return new Promise(function(resolve47, reject) {
47860
+ return new Promise(function(resolve49, reject) {
47848
47861
  var _hasValue = false;
47849
47862
  var _value;
47850
47863
  source.subscribe({
@@ -47855,9 +47868,9 @@ var require_lastValueFrom = __commonJS({
47855
47868
  error: reject,
47856
47869
  complete: function() {
47857
47870
  if (_hasValue) {
47858
- resolve47(_value);
47871
+ resolve49(_value);
47859
47872
  } else if (hasConfig) {
47860
- resolve47(config2.defaultValue);
47873
+ resolve49(config2.defaultValue);
47861
47874
  } else {
47862
47875
  reject(new EmptyError_1.EmptyError());
47863
47876
  }
@@ -47879,16 +47892,16 @@ var require_firstValueFrom = __commonJS({
47879
47892
  var Subscriber_1 = require_Subscriber();
47880
47893
  function firstValueFrom(source, config2) {
47881
47894
  var hasConfig = typeof config2 === "object";
47882
- return new Promise(function(resolve47, reject) {
47895
+ return new Promise(function(resolve49, reject) {
47883
47896
  var subscriber = new Subscriber_1.SafeSubscriber({
47884
47897
  next: function(value) {
47885
- resolve47(value);
47898
+ resolve49(value);
47886
47899
  subscriber.unsubscribe();
47887
47900
  },
47888
47901
  error: reject,
47889
47902
  complete: function() {
47890
47903
  if (hasConfig) {
47891
- resolve47(config2.defaultValue);
47904
+ resolve49(config2.defaultValue);
47892
47905
  } else {
47893
47906
  reject(new EmptyError_1.EmptyError());
47894
47907
  }
@@ -53681,14 +53694,14 @@ var require_run_async = __commonJS({
53681
53694
  return function() {
53682
53695
  var args = arguments;
53683
53696
  var originalThis = this;
53684
- var promise = new Promise(function(resolve47, reject) {
53697
+ var promise = new Promise(function(resolve49, reject) {
53685
53698
  var resolved = false;
53686
53699
  const wrappedResolve = function(value) {
53687
53700
  if (resolved) {
53688
53701
  console.warn("Run-async promise already resolved.");
53689
53702
  }
53690
53703
  resolved = true;
53691
- resolve47(value);
53704
+ resolve49(value);
53692
53705
  };
53693
53706
  var rejected = false;
53694
53707
  const wrappedReject = function(value) {
@@ -53788,32 +53801,32 @@ __export(otel_hooks_exports, {
53788
53801
  });
53789
53802
  function getOtelHooksHome() {
53790
53803
  if (process.env.HAR_OTEL_HOOKS_HOME) {
53791
- return path48.resolve(process.env.HAR_OTEL_HOOKS_HOME);
53804
+ return path51.resolve(process.env.HAR_OTEL_HOOKS_HOME);
53792
53805
  }
53793
- return path48.join(os16.homedir(), ".har", "otel-hooks");
53806
+ return path51.join(os17.homedir(), ".har", "otel-hooks");
53794
53807
  }
53795
53808
  function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
53796
- return path48.join(hooksHome, "otel_config.json");
53809
+ return path51.join(hooksHome, "otel_config.json");
53797
53810
  }
53798
53811
  function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
53799
- return path48.join(hooksHome, "run-otel-hook.sh");
53812
+ return path51.join(hooksHome, "run-otel-hook.sh");
53800
53813
  }
53801
53814
  function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
53802
- return path48.join(hooksHome, "state");
53815
+ return path51.join(hooksHome, "state");
53803
53816
  }
53804
53817
  function localOtelHookBin(hooksHome) {
53805
- return path48.join(hooksHome, "node_modules", ".bin", "otel-hook");
53818
+ return path51.join(hooksHome, "node_modules", ".bin", "otel-hook");
53806
53819
  }
53807
53820
  function installedPackageVersion(hooksHome) {
53808
53821
  try {
53809
- const pkgPath = path48.join(
53822
+ const pkgPath = path51.join(
53810
53823
  hooksHome,
53811
53824
  "node_modules",
53812
53825
  "@osfactory",
53813
53826
  "otel-hook",
53814
53827
  "package.json"
53815
53828
  );
53816
- const pkg = JSON.parse(fs42.readFileSync(pkgPath, "utf8"));
53829
+ const pkg = JSON.parse(fs45.readFileSync(pkgPath, "utf8"));
53817
53830
  return typeof pkg.version === "string" ? pkg.version : null;
53818
53831
  } catch {
53819
53832
  return null;
@@ -53864,15 +53877,15 @@ function buildOtelHooksConfig(options) {
53864
53877
  };
53865
53878
  }
53866
53879
  function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
53867
- fs42.mkdirSync(hooksHome, { recursive: true });
53880
+ fs45.mkdirSync(hooksHome, { recursive: true });
53868
53881
  const configPath = getOtelHooksConfigPath(hooksHome);
53869
- fs42.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
53882
+ fs45.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
53870
53883
  `);
53871
53884
  return configPath;
53872
53885
  }
53873
53886
  function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
53874
- fs42.mkdirSync(hooksHome, { recursive: true });
53875
- fs42.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
53887
+ fs45.mkdirSync(hooksHome, { recursive: true });
53888
+ fs45.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
53876
53889
  const wrapperPath = getOtelHooksWrapperPath(hooksHome);
53877
53890
  const configPath = getOtelHooksConfigPath(hooksHome);
53878
53891
  const stateDir = getOtelHooksStateDir(hooksHome);
@@ -53884,22 +53897,22 @@ exec "${otelHookCommand}" run \\
53884
53897
  --state-dir "${stateDir}" \\
53885
53898
  "$@"
53886
53899
  `;
53887
- fs42.writeFileSync(wrapperPath, script, { mode: 493 });
53900
+ fs45.writeFileSync(wrapperPath, script, { mode: 493 });
53888
53901
  try {
53889
- fs42.chmodSync(wrapperPath, 493);
53902
+ fs45.chmodSync(wrapperPath, 493);
53890
53903
  } catch {
53891
53904
  }
53892
53905
  return wrapperPath;
53893
53906
  }
53894
53907
  function commandExists3(command2) {
53895
- const result = (0, import_child_process12.spawnSync)("sh", ["-c", `command -v ${JSON.stringify(command2)}`], {
53908
+ const result = (0, import_child_process13.spawnSync)("sh", ["-c", `command -v ${JSON.stringify(command2)}`], {
53896
53909
  encoding: "utf8"
53897
53910
  });
53898
53911
  return result.status === 0 && Boolean(result.stdout?.trim());
53899
53912
  }
53900
53913
  function resolveOtelHookCommand(hooksHome) {
53901
53914
  const local = localOtelHookBin(hooksHome);
53902
- if (fs42.existsSync(local)) return local;
53915
+ if (fs45.existsSync(local)) return local;
53903
53916
  return null;
53904
53917
  }
53905
53918
  function resolveHooksInstaller(hooksHome) {
@@ -53914,7 +53927,7 @@ function resolveHooksInstaller(hooksHome) {
53914
53927
  return candidates.find((candidate) => commandExists3(candidate.command)) ?? null;
53915
53928
  }
53916
53929
  function tryInstallPackage(hooksHome) {
53917
- fs42.mkdirSync(hooksHome, { recursive: true });
53930
+ fs45.mkdirSync(hooksHome, { recursive: true });
53918
53931
  const installer = resolveHooksInstaller(hooksHome);
53919
53932
  if (!installer) {
53920
53933
  return {
@@ -53923,11 +53936,11 @@ function tryInstallPackage(hooksHome) {
53923
53936
  };
53924
53937
  }
53925
53938
  const described = `${installer.command} ${installer.args.join(" ")}`;
53926
- const result = (0, import_child_process12.spawnSync)(installer.command, installer.args, {
53939
+ const result = (0, import_child_process13.spawnSync)(installer.command, installer.args, {
53927
53940
  encoding: "utf8",
53928
53941
  timeout: 18e4
53929
53942
  });
53930
- if (result.status === 0 && fs42.existsSync(localOtelHookBin(hooksHome))) {
53943
+ if (result.status === 0 && fs45.existsSync(localOtelHookBin(hooksHome))) {
53931
53944
  return { ok: true, detail: described };
53932
53945
  }
53933
53946
  return {
@@ -53945,7 +53958,7 @@ function uninstallLegacyPythonHooks(hooksHome) {
53945
53958
  for (const [cmd, args] of attempts) {
53946
53959
  if (!commandExists3(cmd)) continue;
53947
53960
  try {
53948
- (0, import_child_process12.spawnSync)(cmd, args, { encoding: "utf8", timeout: 6e4 });
53961
+ (0, import_child_process13.spawnSync)(cmd, args, { encoding: "utf8", timeout: 6e4 });
53949
53962
  } catch {
53950
53963
  }
53951
53964
  }
@@ -53953,14 +53966,14 @@ function uninstallLegacyPythonHooks(hooksHome) {
53953
53966
  }
53954
53967
  function removeLegacyPythonArtifacts(hooksHome) {
53955
53968
  const legacyPaths = [
53956
- path48.join(hooksHome, ".venv"),
53957
- path48.join(hooksHome, "otel_config.yaml"),
53958
- path48.join(hooksHome, "venv")
53969
+ path51.join(hooksHome, ".venv"),
53970
+ path51.join(hooksHome, "otel_config.yaml"),
53971
+ path51.join(hooksHome, "venv")
53959
53972
  ];
53960
53973
  for (const target of legacyPaths) {
53961
53974
  try {
53962
- if (fs42.existsSync(target)) {
53963
- fs42.rmSync(target, { recursive: true, force: true });
53975
+ if (fs45.existsSync(target)) {
53976
+ fs45.rmSync(target, { recursive: true, force: true });
53964
53977
  }
53965
53978
  } catch {
53966
53979
  }
@@ -53977,7 +53990,7 @@ function normalizeLegacyProviderFlagsInCommand(command2) {
53977
53990
  }
53978
53991
  function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
53979
53992
  const hookCommand = `${wrapperPath} --provider ${providerId}`;
53980
- const result = (0, import_child_process12.spawnSync)(
53993
+ const result = (0, import_child_process13.spawnSync)(
53981
53994
  otelHookCommand,
53982
53995
  [
53983
53996
  "setup",
@@ -54001,10 +54014,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
54001
54014
  };
54002
54015
  }
54003
54016
  function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
54004
- if (!fs42.existsSync(filePath)) return false;
54017
+ if (!fs45.existsSync(filePath)) return false;
54005
54018
  let raw;
54006
54019
  try {
54007
- raw = fs42.readFileSync(filePath, "utf8");
54020
+ raw = fs45.readFileSync(filePath, "utf8");
54008
54021
  } catch {
54009
54022
  return false;
54010
54023
  }
@@ -54051,15 +54064,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
54051
54064
  return changed;
54052
54065
  };
54053
54066
  if (!walk(parsed)) return false;
54054
- fs42.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
54067
+ fs45.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
54055
54068
  `);
54056
54069
  return true;
54057
54070
  }
54058
54071
  function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
54059
- if (!fs42.existsSync(filePath)) return false;
54072
+ if (!fs45.existsSync(filePath)) return false;
54060
54073
  let raw;
54061
54074
  try {
54062
- raw = fs42.readFileSync(filePath, "utf8");
54075
+ raw = fs45.readFileSync(filePath, "utf8");
54063
54076
  } catch {
54064
54077
  return false;
54065
54078
  }
@@ -54094,21 +54107,21 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
54094
54107
  }
54095
54108
  }
54096
54109
  if (!changed) return false;
54097
- fs42.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
54110
+ fs45.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
54098
54111
  `);
54099
54112
  return true;
54100
54113
  }
54101
54114
  function rewriteKnownHookRegistrations(wrapperPath) {
54102
- const home = os16.homedir();
54115
+ const home = os17.homedir();
54103
54116
  const candidates = [
54104
- path48.join(home, ".cursor", "hooks.json"),
54105
- path48.join(home, ".claude", "settings.json"),
54106
- path48.join(home, ".codex", "hooks.json")
54117
+ path51.join(home, ".cursor", "hooks.json"),
54118
+ path51.join(home, ".claude", "settings.json"),
54119
+ path51.join(home, ".codex", "hooks.json")
54107
54120
  ];
54108
54121
  for (const filePath of candidates) {
54109
54122
  try {
54110
54123
  rewriteHookCommandsToWrapper(filePath, wrapperPath);
54111
- if (filePath.endsWith(`${path48.sep}.cursor${path48.sep}hooks.json`)) {
54124
+ if (filePath.endsWith(`${path51.sep}.cursor${path51.sep}hooks.json`)) {
54112
54125
  pruneLegacyCursorHookEvents(filePath, wrapperPath);
54113
54126
  }
54114
54127
  } catch {
@@ -54124,7 +54137,7 @@ function ensureOtelHooks(options) {
54124
54137
  const hooksHome = getOtelHooksHome();
54125
54138
  const errors = [];
54126
54139
  const providersSetup = [];
54127
- fs42.mkdirSync(hooksHome, { recursive: true });
54140
+ fs45.mkdirSync(hooksHome, { recursive: true });
54128
54141
  let otelHookCommand = resolveOtelHookCommand(hooksHome);
54129
54142
  const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
54130
54143
  if (needsInstall) {
@@ -54218,14 +54231,14 @@ function ensureOtelHooks(options) {
54218
54231
  function disableOtelHooksExport() {
54219
54232
  return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
54220
54233
  }
54221
- var import_child_process12, fs42, os16, path48, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
54234
+ var import_child_process13, fs45, os17, path51, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
54222
54235
  var init_otel_hooks = __esm({
54223
54236
  "src/core/otel-hooks.ts"() {
54224
54237
  "use strict";
54225
- import_child_process12 = require("child_process");
54226
- fs42 = __toESM(require("fs"));
54227
- os16 = __toESM(require("os"));
54228
- path48 = __toESM(require("path"));
54238
+ import_child_process13 = require("child_process");
54239
+ fs45 = __toESM(require("fs"));
54240
+ os17 = __toESM(require("os"));
54241
+ path51 = __toESM(require("path"));
54229
54242
  init_control_config();
54230
54243
  init_telemetry_config();
54231
54244
  OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.2.0";
@@ -57200,7 +57213,7 @@ var require_compile = __commonJS({
57200
57213
  const schOrFunc = root.refs[ref];
57201
57214
  if (schOrFunc)
57202
57215
  return schOrFunc;
57203
- let _sch = resolve47.call(this, root, ref);
57216
+ let _sch = resolve49.call(this, root, ref);
57204
57217
  if (_sch === void 0) {
57205
57218
  const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
57206
57219
  const { schemaId } = this.opts;
@@ -57227,7 +57240,7 @@ var require_compile = __commonJS({
57227
57240
  function sameSchemaEnv(s1, s2) {
57228
57241
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
57229
57242
  }
57230
- function resolve47(root, ref) {
57243
+ function resolve49(root, ref) {
57231
57244
  let sch;
57232
57245
  while (typeof (sch = this.refs[ref]) == "string")
57233
57246
  ref = sch;
@@ -57445,8 +57458,8 @@ var require_utils = __commonJS({
57445
57458
  }
57446
57459
  return ind;
57447
57460
  }
57448
- function removeDotSegments(path62) {
57449
- let input = path62;
57461
+ function removeDotSegments(path65) {
57462
+ let input = path65;
57450
57463
  const output = [];
57451
57464
  let nextSlash = -1;
57452
57465
  let len = 0;
@@ -57698,8 +57711,8 @@ var require_schemes = __commonJS({
57698
57711
  wsComponent.secure = void 0;
57699
57712
  }
57700
57713
  if (wsComponent.resourceName) {
57701
- const [path62, query] = wsComponent.resourceName.split("?");
57702
- wsComponent.path = path62 && path62 !== "/" ? path62 : void 0;
57714
+ const [path65, query] = wsComponent.resourceName.split("?");
57715
+ wsComponent.path = path65 && path65 !== "/" ? path65 : void 0;
57703
57716
  wsComponent.query = query;
57704
57717
  wsComponent.resourceName = void 0;
57705
57718
  }
@@ -57858,7 +57871,7 @@ var require_fast_uri = __commonJS({
57858
57871
  }
57859
57872
  return uri;
57860
57873
  }
57861
- function resolve47(baseURI, relativeURI, options) {
57874
+ function resolve49(baseURI, relativeURI, options) {
57862
57875
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
57863
57876
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
57864
57877
  schemelessOptions.skipEscape = true;
@@ -58116,7 +58129,7 @@ var require_fast_uri = __commonJS({
58116
58129
  var fastUri = {
58117
58130
  SCHEMES,
58118
58131
  normalize: normalize3,
58119
- resolve: resolve47,
58132
+ resolve: resolve49,
58120
58133
  resolveComponent,
58121
58134
  equal,
58122
58135
  serialize,
@@ -61092,12 +61105,12 @@ var require_dist = __commonJS({
61092
61105
  throw new Error(`Unknown format "${name}"`);
61093
61106
  return f;
61094
61107
  };
61095
- function addFormats(ajv, list, fs48, exportName) {
61108
+ function addFormats(ajv, list, fs51, exportName) {
61096
61109
  var _a2;
61097
61110
  var _b2;
61098
61111
  (_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
61099
61112
  for (const f of list)
61100
- ajv.addFormat(f, fs48[f]);
61113
+ ajv.addFormat(f, fs51[f]);
61101
61114
  }
61102
61115
  module2.exports = exports2 = formatsPlugin;
61103
61116
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -62381,11 +62394,11 @@ var parser = new YargsParser({
62381
62394
  resolve: import_path2.resolve,
62382
62395
  // TODO: figure out a way to combine ESM and CJS coverage, such that
62383
62396
  // we can exercise all the lines below:
62384
- require: (path62) => {
62397
+ require: (path65) => {
62385
62398
  if (typeof require !== "undefined") {
62386
- return require(path62);
62387
- } else if (path62.match(/\.json$/)) {
62388
- return JSON.parse((0, import_fs2.readFileSync)(path62, "utf8"));
62399
+ return require(path65);
62400
+ } else if (path65.match(/\.json$/)) {
62401
+ return JSON.parse((0, import_fs2.readFileSync)(path65, "utf8"));
62389
62402
  } else {
62390
62403
  throw Error("only .json config files are supported in ESM");
62391
62404
  }
@@ -64911,12 +64924,12 @@ var YargsInstance = class {
64911
64924
  async getCompletion(args, done) {
64912
64925
  argsert("<array> [function]", [args, done], arguments.length);
64913
64926
  if (!done) {
64914
- return new Promise((resolve47, reject) => {
64927
+ return new Promise((resolve49, reject) => {
64915
64928
  __classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
64916
64929
  if (err)
64917
64930
  reject(err);
64918
64931
  else
64919
- resolve47(completions);
64932
+ resolve49(completions);
64920
64933
  });
64921
64934
  });
64922
64935
  } else {
@@ -66205,16 +66218,16 @@ async function handleAgentSkills(options) {
66205
66218
  }
66206
66219
  async function askYesNo(question) {
66207
66220
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
66208
- return new Promise((resolve47) => {
66221
+ return new Promise((resolve49) => {
66209
66222
  process.stderr.write(`${question} `);
66210
66223
  rl.once("line", (answer) => {
66211
66224
  rl.close();
66212
66225
  const trimmed = answer.trim();
66213
66226
  if (trimmed === "") {
66214
- resolve47(true);
66227
+ resolve49(true);
66215
66228
  return;
66216
66229
  }
66217
- resolve47(/^y(es)?$/i.test(trimmed));
66230
+ resolve49(/^y(es)?$/i.test(trimmed));
66218
66231
  });
66219
66232
  });
66220
66233
  }
@@ -66294,7 +66307,7 @@ function handleRemove(argv) {
66294
66307
  }
66295
66308
 
66296
66309
  // src/cli/commands/env.ts
66297
- var path51 = __toESM(require("path"));
66310
+ var path54 = __toESM(require("path"));
66298
66311
 
66299
66312
  // src/cli/finish-command.ts
66300
66313
  init_sync_context();
@@ -66304,12 +66317,12 @@ async function finishCommand(code) {
66304
66317
  }
66305
66318
 
66306
66319
  // src/core/harness.ts
66307
- var fs38 = __toESM(require("fs"));
66308
- var path43 = __toESM(require("path"));
66320
+ var fs41 = __toESM(require("fs"));
66321
+ var path46 = __toESM(require("path"));
66309
66322
 
66310
66323
  // src/harness/generator.ts
66311
- var fs29 = __toESM(require("fs"));
66312
- var path35 = __toESM(require("path"));
66324
+ var fs31 = __toESM(require("fs"));
66325
+ var path37 = __toESM(require("path"));
66313
66326
  init_file_ops();
66314
66327
  init_logging();
66315
66328
 
@@ -66363,12 +66376,163 @@ function isExpectedHarnessOnlyFile(harnessFile, templateFiles) {
66363
66376
 
66364
66377
  // src/harness/generator.ts
66365
66378
  init_manifest();
66366
- init_stages();
66379
+
66380
+ // src/harness/plugin-ledger.ts
66381
+ var fs29 = __toESM(require("fs"));
66382
+ var path35 = __toESM(require("path"));
66383
+ init_zod();
66384
+ init_file_ops();
66385
+ init_manifest();
66386
+ var PluginLedgerEntrySchema = external_exports.object({
66387
+ id: external_exports.string().min(1),
66388
+ source: external_exports.enum(["bundled", "path", "npm", "git"]),
66389
+ /** Original install spec (id, path, package, or git URL). */
66390
+ spec: external_exports.string().min(1),
66391
+ /** Package/plugin version when known. */
66392
+ version: external_exports.string().optional(),
66393
+ stageIds: external_exports.array(external_exports.string().min(1)).min(1),
66394
+ installedAt: external_exports.string()
66395
+ });
66396
+ var PluginLedgerSchema = external_exports.object({
66397
+ version: external_exports.literal("1"),
66398
+ /** Profile used at init, when known. */
66399
+ profile: external_exports.enum(["default", "cli", "ios"]).optional(),
66400
+ /** Ordered runtime bundles that composed the harness scaffold. */
66401
+ bundles: external_exports.array(external_exports.string().min(1)).optional(),
66402
+ plugins: external_exports.array(PluginLedgerEntrySchema).default([])
66403
+ });
66404
+ function getPluginLedgerPath(repoPath) {
66405
+ return path35.join(path35.resolve(repoPath), DEFAULT_HAR_DIR, "plugins.json");
66406
+ }
66407
+ function readPluginLedger(repoPath) {
66408
+ const ledgerPath = getPluginLedgerPath(repoPath);
66409
+ if (!fs29.existsSync(ledgerPath)) return null;
66410
+ try {
66411
+ const raw = JSON.parse(fs29.readFileSync(ledgerPath, "utf8"));
66412
+ const parsed = PluginLedgerSchema.safeParse(raw);
66413
+ return parsed.success ? parsed.data : null;
66414
+ } catch {
66415
+ return null;
66416
+ }
66417
+ }
66418
+ function writePluginLedger(repoPath, ledger) {
66419
+ const ledgerPath = getPluginLedgerPath(repoPath);
66420
+ const harnessDir = path35.dirname(ledgerPath);
66421
+ if (!fs29.existsSync(harnessDir)) {
66422
+ fs29.mkdirSync(harnessDir, { recursive: true });
66423
+ }
66424
+ writeFileSafe(ledgerPath, `${JSON.stringify(ledger, null, 2)}
66425
+ `);
66426
+ }
66427
+ function upsertPluginLedgerEntry(repoPath, entry, extras) {
66428
+ const existing = readPluginLedger(repoPath) ?? {
66429
+ version: "1",
66430
+ plugins: []
66431
+ };
66432
+ const plugins = existing.plugins.filter((p) => p.id !== entry.id);
66433
+ plugins.push(entry);
66434
+ plugins.sort((a, b2) => a.id.localeCompare(b2.id));
66435
+ const ledger = {
66436
+ version: "1",
66437
+ profile: extras?.profile ?? existing.profile,
66438
+ bundles: extras?.bundles ?? existing.bundles,
66439
+ plugins
66440
+ };
66441
+ writePluginLedger(repoPath, ledger);
66442
+ return ledger;
66443
+ }
66444
+ function ensurePluginLedgerScaffold(repoPath, options) {
66445
+ const existing = readPluginLedger(repoPath);
66446
+ const ledger = {
66447
+ version: "1",
66448
+ profile: options.profile ?? existing?.profile,
66449
+ bundles: options.bundles ?? existing?.bundles,
66450
+ plugins: existing?.plugins ?? []
66451
+ };
66452
+ writePluginLedger(repoPath, ledger);
66453
+ return ledger;
66454
+ }
66455
+
66456
+ // src/harness/profiles.ts
66457
+ var fs30 = __toESM(require("fs"));
66458
+ var path36 = __toESM(require("path"));
66459
+ init_zod();
66460
+ var HARNESS_PROFILES = ["default", "cli", "ios"];
66461
+ var ProfileBundleRefSchema = external_exports.object({
66462
+ /** Stable bundle id recorded in .har/plugins.json */
66463
+ id: external_exports.string().min(1),
66464
+ /**
66465
+ * Directory under src/templates/ (e.g. "runtime-bundles/shared-kernel"
66466
+ * or "har-boilerplate").
66467
+ */
66468
+ path: external_exports.string().min(1)
66469
+ });
66470
+ var ProfileManifestSchema = external_exports.object({
66471
+ id: external_exports.enum(HARNESS_PROFILES),
66472
+ description: external_exports.string().min(1),
66473
+ /** Ordered runtime bundles — later bundles overwrite earlier files on conflict. */
66474
+ bundles: external_exports.array(ProfileBundleRefSchema).min(1)
66475
+ });
66476
+ var PROFILE_COMPOSITIONS = {
66477
+ default: {
66478
+ id: "default",
66479
+ description: "Web app \u2014 shared kernel + PM2 runtime + Docker infra",
66480
+ bundles: [
66481
+ { id: "shared-kernel", path: "runtime-bundles/shared-kernel" },
66482
+ { id: "pm2-runtime", path: "runtime-bundles/pm2-runtime" },
66483
+ { id: "runtime-default", path: "har-boilerplate" }
66484
+ ]
66485
+ },
66486
+ cli: {
66487
+ id: "cli",
66488
+ description: "CLI/library \u2014 shared kernel + CLI overlay (no PM2)",
66489
+ bundles: [
66490
+ { id: "shared-kernel", path: "runtime-bundles/shared-kernel" },
66491
+ { id: "runtime-cli", path: "har-boilerplate-cli" }
66492
+ ]
66493
+ },
66494
+ ios: {
66495
+ id: "ios",
66496
+ description: "iOS \u2014 shared kernel + Xcode/Simulator overlay",
66497
+ bundles: [
66498
+ { id: "shared-kernel", path: "runtime-bundles/shared-kernel" },
66499
+ { id: "xcode-sim", path: "runtime-bundles/xcode-sim" },
66500
+ { id: "runtime-ios", path: "har-boilerplate-ios" }
66501
+ ]
66502
+ }
66503
+ };
66367
66504
  var PROFILE_DIRS = {
66368
66505
  default: "har-boilerplate",
66369
66506
  cli: "har-boilerplate-cli",
66370
66507
  ios: "har-boilerplate-ios"
66371
66508
  };
66509
+ function readProfileManifest(profile) {
66510
+ const templates = resolveTemplatesDir();
66511
+ const manifestPath = path36.join(templates, "profiles", profile, "profile.manifest.json");
66512
+ if (fs30.existsSync(manifestPath)) {
66513
+ const parsed = ProfileManifestSchema.safeParse(
66514
+ JSON.parse(fs30.readFileSync(manifestPath, "utf8"))
66515
+ );
66516
+ if (!parsed.success) {
66517
+ throw new Error(`Invalid profile manifest for ${profile}: ${parsed.error.message}`);
66518
+ }
66519
+ if (parsed.data.id !== profile) {
66520
+ throw new Error(`Profile manifest id mismatch: expected ${profile}, got ${parsed.data.id}`);
66521
+ }
66522
+ return parsed.data;
66523
+ }
66524
+ return PROFILE_COMPOSITIONS[profile];
66525
+ }
66526
+ function resolveProfileBundleDir(bundle) {
66527
+ const dir = path36.join(resolveTemplatesDir(), bundle.path);
66528
+ if (!fs30.existsSync(dir)) {
66529
+ throw new Error(`Profile bundle not found: ${bundle.id} (${bundle.path}). Run npm run build.`);
66530
+ }
66531
+ return dir;
66532
+ }
66533
+
66534
+ // src/harness/generator.ts
66535
+ init_stages();
66372
66536
  var CLI_PRUNE_FILES = [
66373
66537
  "ecosystem.agent.template.cjs",
66374
66538
  "env.template",
@@ -66376,39 +66540,46 @@ var CLI_PRUNE_FILES = [
66376
66540
  ];
66377
66541
  function pruneCliProfile(harnessDir) {
66378
66542
  for (const file of CLI_PRUNE_FILES) {
66379
- const filePath = path35.join(harnessDir, file);
66380
- if (fs29.existsSync(filePath)) {
66381
- fs29.unlinkSync(filePath);
66543
+ const filePath = path37.join(harnessDir, file);
66544
+ if (fs31.existsSync(filePath)) {
66545
+ fs31.unlinkSync(filePath);
66382
66546
  }
66383
66547
  }
66384
66548
  }
66385
66549
  function scaffoldHarnessBoilerplate(repoPath, options = {}) {
66386
- const harnessDir = path35.join(repoPath, DEFAULT_HAR_DIR);
66387
- const projectName = path35.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66550
+ const harnessDir = path37.join(repoPath, DEFAULT_HAR_DIR);
66551
+ const projectName = path37.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66388
66552
  const profile = options.profile ?? "default";
66389
- const boilerplateDir = path35.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
66390
- if (fs29.existsSync(harnessDir) && !options.force) {
66553
+ const profileManifest = readProfileManifest(profile);
66554
+ const bundleIds = profileManifest.bundles.map((b2) => b2.id);
66555
+ const primaryOverlay = PROFILE_DIRS[profile];
66556
+ const boilerplateDir = path37.join(resolveTemplatesDir(), primaryOverlay);
66557
+ if (fs31.existsSync(harnessDir) && !options.force) {
66391
66558
  throw new Error(
66392
66559
  '.har/ already exists. Use --force to overwrite or run "har env maintain" to update in place.'
66393
66560
  );
66394
66561
  }
66395
- if (!fs29.existsSync(boilerplateDir)) {
66562
+ if (!fs31.existsSync(boilerplateDir)) {
66396
66563
  throw new Error(`Boilerplate template not found at ${boilerplateDir}`);
66397
66564
  }
66398
- if (options.force && fs29.existsSync(harnessDir)) {
66399
- fs29.rmSync(harnessDir, { recursive: true, force: true });
66565
+ if (options.force && fs31.existsSync(harnessDir)) {
66566
+ fs31.rmSync(harnessDir, { recursive: true, force: true });
66567
+ }
66568
+ fs31.mkdirSync(harnessDir, { recursive: true });
66569
+ for (const bundle of profileManifest.bundles) {
66570
+ const bundleDir = resolveProfileBundleDir(bundle);
66571
+ copyDirRecursive(bundleDir, harnessDir);
66400
66572
  }
66401
- copyDirRecursive(boilerplateDir, harnessDir);
66402
66573
  writeHarnessGitignore(harnessDir, boilerplateDir);
66403
66574
  if (profile === "cli") {
66404
66575
  pruneCliProfile(harnessDir);
66405
66576
  }
66406
66577
  syncAgentSlotsToHarnessEnv(repoPath);
66407
- const harnessEnvPath = path35.join(harnessDir, "harness.env");
66408
- if (fs29.existsSync(harnessEnvPath)) {
66409
- let content = fs29.readFileSync(harnessEnvPath, "utf8");
66578
+ const harnessEnvPath = path37.join(harnessDir, "harness.env");
66579
+ if (fs31.existsSync(harnessEnvPath)) {
66580
+ let content = fs31.readFileSync(harnessEnvPath, "utf8");
66410
66581
  content = content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
66411
- fs29.writeFileSync(harnessEnvPath, content);
66582
+ fs31.writeFileSync(harnessEnvPath, content);
66412
66583
  }
66413
66584
  const manifest = createManifest(
66414
66585
  repoPath,
@@ -66417,10 +66588,12 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
66417
66588
  profile
66418
66589
  );
66419
66590
  writeManifest(repoPath, manifest);
66591
+ ensurePluginLedgerScaffold(repoPath, { profile, bundles: bundleIds });
66420
66592
  ensureRootGitignorePatterns(repoPath);
66421
66593
  success(`Copied harness boilerplate to .har/ (profile: ${profile})`);
66422
66594
  info(`Project name: ${projectName}`);
66423
- return { harnessDir, projectName };
66595
+ info(`Bundles: ${bundleIds.join(" \u2192 ")}`);
66596
+ return { harnessDir, projectName, bundles: bundleIds };
66424
66597
  }
66425
66598
  function finalizeHarness(repoPath, adaptationSummary, stack) {
66426
66599
  const existing = readManifest(repoPath);
@@ -66430,16 +66603,16 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
66430
66603
  }
66431
66604
 
66432
66605
  // src/harness/agent-md.ts
66433
- var fs31 = __toESM(require("fs"));
66434
- var path37 = __toESM(require("path"));
66606
+ var fs33 = __toESM(require("fs"));
66607
+ var path39 = __toESM(require("path"));
66435
66608
  init_file_ops();
66436
66609
  init_logging();
66437
66610
  init_manifest();
66438
66611
 
66439
66612
  // src/harness/instruction-files.ts
66440
- var fs30 = __toESM(require("fs"));
66613
+ var fs32 = __toESM(require("fs"));
66441
66614
  var os14 = __toESM(require("os"));
66442
- var path36 = __toESM(require("path"));
66615
+ var path38 = __toESM(require("path"));
66443
66616
 
66444
66617
  // node_modules/@inquirer/core/dist/esm/lib/key.mjs
66445
66618
  var isUpKey = (key) => (
@@ -67459,13 +67632,13 @@ var PromisePolyfill = class extends Promise {
67459
67632
  // Available starting from Node 22
67460
67633
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
67461
67634
  static withResolver() {
67462
- let resolve47;
67635
+ let resolve49;
67463
67636
  let reject;
67464
67637
  const promise = new Promise((res, rej) => {
67465
- resolve47 = res;
67638
+ resolve49 = res;
67466
67639
  reject = rej;
67467
67640
  });
67468
- return { promise, resolve: resolve47, reject };
67641
+ return { promise, resolve: resolve49, reject };
67469
67642
  }
67470
67643
  };
67471
67644
 
@@ -67482,7 +67655,7 @@ function createPrompt(view) {
67482
67655
  output
67483
67656
  });
67484
67657
  const screen = new ScreenManager(rl);
67485
- const { promise, resolve: resolve47, reject } = PromisePolyfill.withResolver();
67658
+ const { promise, resolve: resolve49, reject } = PromisePolyfill.withResolver();
67486
67659
  const cancel = () => reject(new CancelPromptError());
67487
67660
  if (signal) {
67488
67661
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -67506,7 +67679,7 @@ function createPrompt(view) {
67506
67679
  cycle(() => {
67507
67680
  try {
67508
67681
  const nextView = view(config2, (value) => {
67509
- setImmediate(() => resolve47(value));
67682
+ setImmediate(() => resolve49(value));
67510
67683
  });
67511
67684
  const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
67512
67685
  screen.render(content, bottomContent);
@@ -68493,9 +68666,9 @@ var import_run_async = __toESM(require_run_async(), 1);
68493
68666
  var import_mute_stream2 = __toESM(require_lib(), 1);
68494
68667
  var import_ansi_escapes5 = __toESM(require_ansi_escapes(), 1);
68495
68668
  var _ = {
68496
- set: (obj, path62 = "", value) => {
68669
+ set: (obj, path65 = "", value) => {
68497
68670
  let pointer = obj;
68498
- path62.split(".").forEach((key, index, arr) => {
68671
+ path65.split(".").forEach((key, index, arr) => {
68499
68672
  if (key === "__proto__" || key === "constructor")
68500
68673
  return;
68501
68674
  if (index === arr.length - 1) {
@@ -68506,8 +68679,8 @@ var _ = {
68506
68679
  pointer = pointer[key];
68507
68680
  });
68508
68681
  },
68509
- get: (obj, path62 = "", defaultValue) => {
68510
- const travel = (regexp) => String.prototype.split.call(path62, regexp).filter(Boolean).reduce(
68682
+ get: (obj, path65 = "", defaultValue) => {
68683
+ const travel = (regexp) => String.prototype.split.call(path65, regexp).filter(Boolean).reduce(
68511
68684
  // @ts-expect-error implicit any on res[key]
68512
68685
  (res, key) => res !== null && res !== void 0 ? res[key] : res,
68513
68686
  obj
@@ -68621,7 +68794,7 @@ var PromptsRunner = class {
68621
68794
  throw new Error(`Prompt for type ${question.type} not found`);
68622
68795
  }
68623
68796
  let cleanupSignal;
68624
- const promptFn = isPromptConstructor(prompt2) ? (q, { signal: signal2 } = {}) => new Promise((resolve47, reject) => {
68797
+ const promptFn = isPromptConstructor(prompt2) ? (q, { signal: signal2 } = {}) => new Promise((resolve49, reject) => {
68625
68798
  const rl = import_node_readline.default.createInterface(setupReadlineOptions(this.opt));
68626
68799
  rl.resume();
68627
68800
  const onClose = () => {
@@ -68657,7 +68830,7 @@ var PromptsRunner = class {
68657
68830
  cleanupSignal = void 0;
68658
68831
  };
68659
68832
  }
68660
- activePrompt.run().then(resolve47, reject).finally(cleanup);
68833
+ activePrompt.run().then(resolve49, reject).finally(cleanup);
68661
68834
  }) : prompt2;
68662
68835
  const { signal: moduleSignal } = this.opt;
68663
68836
  if (moduleSignal?.aborted) {
@@ -68833,12 +69006,12 @@ function outsideContentShrinkMessage(beforeLines, afterLines) {
68833
69006
  }
68834
69007
  function detectInstructionFiles(repoPath) {
68835
69008
  return {
68836
- agentsMd: fs30.existsSync(path36.join(repoPath, AGENTS_MD)),
68837
- agentMd: fs30.existsSync(path36.join(repoPath, LEGACY_AGENT_MD)),
68838
- claudeMd: fs30.existsSync(path36.join(repoPath, CLAUDE_MD)),
68839
- cursorDir: fs30.existsSync(path36.join(repoPath, ".cursor")),
68840
- claudeDir: fs30.existsSync(path36.join(repoPath, ".claude")),
68841
- codexHome: fs30.existsSync(path36.join(os14.homedir(), ".codex"))
69009
+ agentsMd: fs32.existsSync(path38.join(repoPath, AGENTS_MD)),
69010
+ agentMd: fs32.existsSync(path38.join(repoPath, LEGACY_AGENT_MD)),
69011
+ claudeMd: fs32.existsSync(path38.join(repoPath, CLAUDE_MD)),
69012
+ cursorDir: fs32.existsSync(path38.join(repoPath, ".cursor")),
69013
+ claudeDir: fs32.existsSync(path38.join(repoPath, ".claude")),
69014
+ codexHome: fs32.existsSync(path38.join(os14.homedir(), ".codex"))
68842
69015
  };
68843
69016
  }
68844
69017
  function formatDetectionReport(detection) {
@@ -68893,7 +69066,7 @@ function loadHarAgentsSectionFromTemplate() {
68893
69066
  if (!templatePath) {
68894
69067
  throw new Error("AGENTS.md.template not found. Run npm run build.");
68895
69068
  }
68896
- const content = fs30.readFileSync(templatePath, "utf8");
69069
+ const content = fs32.readFileSync(templatePath, "utf8");
68897
69070
  const start = content.indexOf(HAR_SECTION_START);
68898
69071
  const end = content.indexOf(HAR_SECTION_END);
68899
69072
  if (start === -1 || end === -1 || end < start) {
@@ -68906,7 +69079,7 @@ function loadAgentsMdTemplate() {
68906
69079
  if (!templatePath) {
68907
69080
  throw new Error("AGENTS.md.template not found. Run npm run build.");
68908
69081
  }
68909
- return fs30.readFileSync(templatePath, "utf8");
69082
+ return fs32.readFileSync(templatePath, "utf8");
68910
69083
  }
68911
69084
  function upsertMarkedBlock2(content, block, startMarker, endMarker) {
68912
69085
  const existingBlock = findLastCompleteMarkedBlock(content, startMarker, endMarker);
@@ -68939,13 +69112,13 @@ function mergeAgentsMdContent(existing, incoming) {
68939
69112
  return content;
68940
69113
  }
68941
69114
  function upsertAgentsMdHarSection(repoPath, options = {}) {
68942
- const dest = path36.join(repoPath, AGENTS_MD);
69115
+ const dest = path38.join(repoPath, AGENTS_MD);
68943
69116
  const section = loadHarAgentsSectionFromTemplate();
68944
- if (!fs30.existsSync(dest)) {
69117
+ if (!fs32.existsSync(dest)) {
68945
69118
  writeFileSafe(dest, loadAgentsMdTemplate());
68946
69119
  return "created";
68947
69120
  }
68948
- const existing = fs30.readFileSync(dest, "utf8");
69121
+ const existing = fs32.readFileSync(dest, "utf8");
68949
69122
  const sanitized = stripClaudePointerFromAgentsMd(existing);
68950
69123
  const { content, action } = upsertMarkedBlock2(
68951
69124
  sanitized,
@@ -68970,15 +69143,15 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
68970
69143
  return action;
68971
69144
  }
68972
69145
  function migrateLegacyAgentMd(repoPath) {
68973
- const legacyPath = path36.join(repoPath, LEGACY_AGENT_MD);
68974
- const agentsPath = path36.join(repoPath, AGENTS_MD);
68975
- if (!fs30.existsSync(legacyPath)) return false;
68976
- const legacy = fs30.readFileSync(legacyPath, "utf8");
68977
- if (!fs30.existsSync(agentsPath)) {
69146
+ const legacyPath = path38.join(repoPath, LEGACY_AGENT_MD);
69147
+ const agentsPath = path38.join(repoPath, AGENTS_MD);
69148
+ if (!fs32.existsSync(legacyPath)) return false;
69149
+ const legacy = fs32.readFileSync(legacyPath, "utf8");
69150
+ if (!fs32.existsSync(agentsPath)) {
68978
69151
  writeFileSafe(agentsPath, legacy);
68979
69152
  upsertAgentsMdHarSection(repoPath);
68980
69153
  } else {
68981
- const agents = fs30.readFileSync(agentsPath, "utf8");
69154
+ const agents = fs32.readFileSync(agentsPath, "utf8");
68982
69155
  const legacyTrimmed = legacy.trim();
68983
69156
  if (legacyTrimmed.length > 0 && !agents.includes(legacyTrimmed)) {
68984
69157
  const suffix = agents.endsWith("\n") ? "" : "\n";
@@ -68988,7 +69161,7 @@ ${legacyTrimmed}
68988
69161
  }
68989
69162
  upsertAgentsMdHarSection(repoPath);
68990
69163
  }
68991
- fs30.unlinkSync(legacyPath);
69164
+ fs32.unlinkSync(legacyPath);
68992
69165
  info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
68993
69166
  return true;
68994
69167
  }
@@ -68998,7 +69171,7 @@ function loadClaudeMdTemplate(projectName) {
68998
69171
  throw new Error("CLAUDE.md.template not found. Run npm run build.");
68999
69172
  }
69000
69173
  const displayName = projectName.replace(/_/g, " ");
69001
- return fs30.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
69174
+ return fs32.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
69002
69175
  }
69003
69176
  function isThinClaudePointer(content) {
69004
69177
  const trimmed = content.trim();
@@ -69012,14 +69185,14 @@ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
69012
69185
  [\`.har/README.md\`](./.har/README.md) before making changes.
69013
69186
  ${CLAUDE_HAR_SECTION_END}`;
69014
69187
  function ensureClaudeMdPointer(repoPath, options = {}) {
69015
- const dest = path36.join(repoPath, CLAUDE_MD);
69016
- const projectName = path36.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
69188
+ const dest = path38.join(repoPath, CLAUDE_MD);
69189
+ const projectName = path38.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
69017
69190
  const thin = loadClaudeMdTemplate(projectName);
69018
- if (!fs30.existsSync(dest)) {
69191
+ if (!fs32.existsSync(dest)) {
69019
69192
  writeFileSafe(dest, thin);
69020
69193
  return "created";
69021
69194
  }
69022
- const existing = fs30.readFileSync(dest, "utf8");
69195
+ const existing = fs32.readFileSync(dest, "utf8");
69023
69196
  if (isThinClaudePointer(existing) || options.force) {
69024
69197
  writeFileSafe(dest, thin);
69025
69198
  return "updated";
@@ -69168,19 +69341,19 @@ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
69168
69341
  var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
69169
69342
  function readAgentMdProposal(repoPath) {
69170
69343
  const harnessDir = getHarnessDir(repoPath);
69171
- const proposalPath = path37.join(harnessDir, AGENTS_MD_PROPOSAL);
69172
- const metaPath = path37.join(harnessDir, AGENTS_MD_PROPOSAL_META);
69173
- const legacyProposalPath = path37.join(harnessDir, AGENT_MD_PROPOSAL);
69174
- const legacyMetaPath = path37.join(harnessDir, AGENT_MD_PROPOSAL_META);
69175
- const resolvedProposal = fs31.existsSync(proposalPath) ? proposalPath : fs31.existsSync(legacyProposalPath) ? legacyProposalPath : null;
69344
+ const proposalPath = path39.join(harnessDir, AGENTS_MD_PROPOSAL);
69345
+ const metaPath = path39.join(harnessDir, AGENTS_MD_PROPOSAL_META);
69346
+ const legacyProposalPath = path39.join(harnessDir, AGENT_MD_PROPOSAL);
69347
+ const legacyMetaPath = path39.join(harnessDir, AGENT_MD_PROPOSAL_META);
69348
+ const resolvedProposal = fs33.existsSync(proposalPath) ? proposalPath : fs33.existsSync(legacyProposalPath) ? legacyProposalPath : null;
69176
69349
  if (!resolvedProposal) return null;
69177
69350
  const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
69178
- const content = fs31.readFileSync(resolvedProposal, "utf8");
69351
+ const content = fs33.readFileSync(resolvedProposal, "utf8");
69179
69352
  let rationale = "";
69180
69353
  let createdAt = (/* @__PURE__ */ new Date()).toISOString();
69181
- if (fs31.existsSync(resolvedMeta)) {
69354
+ if (fs33.existsSync(resolvedMeta)) {
69182
69355
  try {
69183
- const meta = JSON.parse(fs31.readFileSync(resolvedMeta, "utf8"));
69356
+ const meta = JSON.parse(fs33.readFileSync(resolvedMeta, "utf8"));
69184
69357
  rationale = meta.rationale ?? "";
69185
69358
  createdAt = meta.createdAt ?? createdAt;
69186
69359
  } catch {
@@ -69197,8 +69370,8 @@ function clearAgentMdProposal(repoPath) {
69197
69370
  AGENT_MD_PROPOSAL,
69198
69371
  AGENT_MD_PROPOSAL_META
69199
69372
  ]) {
69200
- const p = path37.join(harnessDir, file);
69201
- if (fs31.existsSync(p)) fs31.unlinkSync(p);
69373
+ const p = path39.join(harnessDir, file);
69374
+ if (fs33.existsSync(p)) fs33.unlinkSync(p);
69202
69375
  }
69203
69376
  }
69204
69377
  function wouldProposalShrinkExisting(existing, proposal) {
@@ -69211,9 +69384,9 @@ function wouldProposalShrinkExisting(existing, proposal) {
69211
69384
  function applyAgentMdProposalMerge(repoPath, options = {}) {
69212
69385
  const proposal = readAgentMdProposal(repoPath);
69213
69386
  if (!proposal) return false;
69214
- const agentsMdPath = path37.join(repoPath, AGENTS_MD);
69215
- if (fs31.existsSync(agentsMdPath)) {
69216
- const existing = fs31.readFileSync(agentsMdPath, "utf8");
69387
+ const agentsMdPath = path39.join(repoPath, AGENTS_MD);
69388
+ if (fs33.existsSync(agentsMdPath)) {
69389
+ const existing = fs33.readFileSync(agentsMdPath, "utf8");
69217
69390
  if (wouldProposalShrinkExisting(existing, proposal.content)) {
69218
69391
  const message = `${AGENTS_MD} proposal would drop project-specific content outside har:agent-environment markers \u2014 merge custom sections from .har/${AGENTS_MD_PROPOSAL} manually, then delete the proposal.`;
69219
69392
  if (options.rejectSignificantShrink) {
@@ -69236,8 +69409,8 @@ function finalizeAgentsMdInstructionFiles(repoPath) {
69236
69409
  }
69237
69410
 
69238
69411
  // src/harness/validator.ts
69239
- var fs32 = __toESM(require("fs"));
69240
- var path38 = __toESM(require("path"));
69412
+ var fs34 = __toESM(require("fs"));
69413
+ var path40 = __toESM(require("path"));
69241
69414
  init_shell();
69242
69415
  init_manifest();
69243
69416
  init_stages();
@@ -69292,22 +69465,22 @@ var SHELL_SCRIPTS = [
69292
69465
  function validateHarness(repoPath) {
69293
69466
  const harnessDir = getHarnessDir(repoPath);
69294
69467
  const issues = [];
69295
- if (!fs32.existsSync(harnessDir)) {
69468
+ if (!fs34.existsSync(harnessDir)) {
69296
69469
  return {
69297
69470
  pass: false,
69298
69471
  issues: [{ file: ".har", message: "Harness directory not found", severity: "error" }]
69299
69472
  };
69300
69473
  }
69301
69474
  for (const file of getRequiredFiles(repoPath)) {
69302
- const filePath = path38.join(harnessDir, file);
69303
- if (!fs32.existsSync(filePath)) {
69475
+ const filePath = path40.join(harnessDir, file);
69476
+ if (!fs34.existsSync(filePath)) {
69304
69477
  issues.push({ file, message: "Required file missing", severity: "error" });
69305
69478
  }
69306
69479
  }
69307
69480
  for (const script of SHELL_SCRIPTS) {
69308
- const scriptPath = path38.join(harnessDir, script);
69309
- if (!fs32.existsSync(scriptPath)) continue;
69310
- const stat = fs32.statSync(scriptPath);
69481
+ const scriptPath = path40.join(harnessDir, script);
69482
+ if (!fs34.existsSync(scriptPath)) continue;
69483
+ const stat = fs34.statSync(scriptPath);
69311
69484
  if (!(stat.mode & 73)) {
69312
69485
  issues.push({ file: script, message: "Script is not executable", severity: "warning" });
69313
69486
  }
@@ -69322,9 +69495,9 @@ function validateHarness(repoPath) {
69322
69495
  }
69323
69496
  const manifest = readManifest(repoPath);
69324
69497
  const profile = manifest?.profile ?? "default";
69325
- const ecosystemPath = path38.join(harnessDir, "ecosystem.agent.template.cjs");
69326
- if (profile !== "cli" && fs32.existsSync(ecosystemPath)) {
69327
- const content = fs32.readFileSync(ecosystemPath, "utf8");
69498
+ const ecosystemPath = path40.join(harnessDir, "ecosystem.agent.template.cjs");
69499
+ if (profile !== "cli" && fs34.existsSync(ecosystemPath)) {
69500
+ const content = fs34.readFileSync(ecosystemPath, "utf8");
69328
69501
  if (!content.includes("module.exports")) {
69329
69502
  issues.push({
69330
69503
  file: "ecosystem.agent.template.cjs",
@@ -69333,9 +69506,9 @@ function validateHarness(repoPath) {
69333
69506
  });
69334
69507
  }
69335
69508
  }
69336
- const harnessEnvPath = path38.join(harnessDir, "harness.env");
69337
- if (fs32.existsSync(harnessEnvPath)) {
69338
- const content = fs32.readFileSync(harnessEnvPath, "utf8");
69509
+ const harnessEnvPath = path40.join(harnessDir, "harness.env");
69510
+ if (fs34.existsSync(harnessEnvPath)) {
69511
+ const content = fs34.readFileSync(harnessEnvPath, "utf8");
69339
69512
  if (content.includes("TODO: set migrate command")) {
69340
69513
  issues.push({ file: "harness.env", message: "Migrate command still has TODO", severity: "warning" });
69341
69514
  }
@@ -69343,17 +69516,17 @@ function validateHarness(repoPath) {
69343
69516
  issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
69344
69517
  }
69345
69518
  }
69346
- const verifyPath = path38.join(harnessDir, "verify.sh");
69347
- if (fs32.existsSync(verifyPath)) {
69348
- const content = fs32.readFileSync(verifyPath, "utf8");
69519
+ const verifyPath = path40.join(harnessDir, "verify.sh");
69520
+ if (fs34.existsSync(verifyPath)) {
69521
+ const content = fs34.readFileSync(verifyPath, "utf8");
69349
69522
  if (content.includes("echo 'TODO:")) {
69350
69523
  issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
69351
69524
  }
69352
69525
  }
69353
- const stagesPath = path38.join(harnessDir, "stages.json");
69354
- if (fs32.existsSync(stagesPath)) {
69526
+ const stagesPath = path40.join(harnessDir, "stages.json");
69527
+ if (fs34.existsSync(stagesPath)) {
69355
69528
  try {
69356
- JSON.parse(fs32.readFileSync(stagesPath, "utf8"));
69529
+ JSON.parse(fs34.readFileSync(stagesPath, "utf8"));
69357
69530
  const registry2 = readStageRegistry(repoPath);
69358
69531
  if (registry2.stages.length === 0) {
69359
69532
  issues.push({ file: "stages.json", message: "No harness stages declared", severity: "warning" });
@@ -69368,9 +69541,9 @@ function validateHarness(repoPath) {
69368
69541
  } else {
69369
69542
  issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
69370
69543
  }
69371
- const readmePath = path38.join(harnessDir, "README.md");
69372
- if (fs32.existsSync(readmePath)) {
69373
- const content = fs32.readFileSync(readmePath, "utf8");
69544
+ const readmePath = path40.join(harnessDir, "README.md");
69545
+ if (fs34.existsSync(readmePath)) {
69546
+ const content = fs34.readFileSync(readmePath, "utf8");
69374
69547
  if (!content.includes(".har")) {
69375
69548
  issues.push({ file: "README.md", message: "README should document .har/ paths", severity: "warning" });
69376
69549
  }
@@ -69384,8 +69557,8 @@ function validateHarness(repoPath) {
69384
69557
  async function smokeTestHarness(repoPath) {
69385
69558
  const harnessDir = getHarnessDir(repoPath);
69386
69559
  const issues = [];
69387
- const setupScript = path38.join(harnessDir, "setup-infra.sh");
69388
- if (fs32.existsSync(setupScript)) {
69560
+ const setupScript = path40.join(harnessDir, "setup-infra.sh");
69561
+ if (fs34.existsSync(setupScript)) {
69389
69562
  const result = run(`bash "${setupScript}"`, { cwd: repoPath });
69390
69563
  if (result.code !== 0) {
69391
69564
  issues.push({
@@ -69400,16 +69573,11 @@ async function smokeTestHarness(repoPath) {
69400
69573
  }
69401
69574
 
69402
69575
  // src/harness/drift.ts
69403
- var fs33 = __toESM(require("fs"));
69404
- var path39 = __toESM(require("path"));
69576
+ var fs35 = __toESM(require("fs"));
69577
+ var path41 = __toESM(require("path"));
69405
69578
  init_env();
69406
69579
  init_manifest();
69407
69580
  init_stages();
69408
- var PROFILE_DIRS2 = {
69409
- default: "har-boilerplate",
69410
- cli: "har-boilerplate-cli",
69411
- ios: "har-boilerplate-ios"
69412
- };
69413
69581
  var CLI_EXPECTED_ABSENT = /* @__PURE__ */ new Set([
69414
69582
  "ecosystem.agent.template.cjs",
69415
69583
  "env.template",
@@ -69472,16 +69640,16 @@ function substituteProjectName(content, projectName) {
69472
69640
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
69473
69641
  }
69474
69642
  function listBoilerplateFiles(boilerplateDir) {
69475
- if (!fs33.existsSync(boilerplateDir)) return [];
69476
- return fs33.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
69643
+ if (!fs35.existsSync(boilerplateDir)) return [];
69644
+ return fs35.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
69477
69645
  }
69478
69646
  function compareHarnessToTemplate(repoPath) {
69479
- const resolved = path39.resolve(repoPath);
69647
+ const resolved = path41.resolve(repoPath);
69480
69648
  const manifest = readManifest(resolved);
69481
69649
  const profile = manifest?.profile ?? "default";
69482
69650
  const harnessDir = getHarnessDir(resolved);
69483
- const projectName = path39.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
69484
- const boilerplateDir = path39.join(resolveTemplatesDir(), PROFILE_DIRS2[profile]);
69651
+ const projectName = path41.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
69652
+ const boilerplateDir = path41.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
69485
69653
  const templateFiles = listBoilerplateFiles(boilerplateDir);
69486
69654
  const missing = [];
69487
69655
  const checksumMismatch = [];
@@ -69489,17 +69657,17 @@ function compareHarnessToTemplate(repoPath) {
69489
69657
  const unchanged = [];
69490
69658
  for (const file of templateFiles) {
69491
69659
  const harnessFile = harnessFileForTemplate(file);
69492
- const templatePath = path39.join(boilerplateDir, file);
69493
- const harnessPath = path39.join(harnessDir, harnessFile);
69494
- let templateContent = fs33.readFileSync(templatePath, "utf8");
69660
+ const templatePath = path41.join(boilerplateDir, file);
69661
+ const harnessPath = path41.join(harnessDir, harnessFile);
69662
+ let templateContent = fs35.readFileSync(templatePath, "utf8");
69495
69663
  if (file === "harness.env") {
69496
69664
  templateContent = substituteProjectName(templateContent, projectName);
69497
69665
  }
69498
- if (!fs33.existsSync(harnessPath)) {
69666
+ if (!fs35.existsSync(harnessPath)) {
69499
69667
  missing.push(harnessFile);
69500
69668
  continue;
69501
69669
  }
69502
- const harnessChecksum = computeFileChecksum(fs33.readFileSync(harnessPath, "utf8"));
69670
+ const harnessChecksum = computeFileChecksum(fs35.readFileSync(harnessPath, "utf8"));
69503
69671
  const templateChecksum = computeFileChecksum(templateContent);
69504
69672
  if (harnessChecksum === templateChecksum) {
69505
69673
  unchanged.push(harnessFile);
@@ -69507,11 +69675,13 @@ function compareHarnessToTemplate(repoPath) {
69507
69675
  checksumMismatch.push(harnessFile);
69508
69676
  }
69509
69677
  }
69510
- if (fs33.existsSync(harnessDir)) {
69511
- for (const file of fs33.readdirSync(harnessDir)) {
69512
- const full = path39.join(harnessDir, file);
69513
- if (!fs33.statSync(full).isFile()) continue;
69514
- if (file === "manifest.json" || file.startsWith("ADAPT-PROMPT")) continue;
69678
+ if (fs35.existsSync(harnessDir)) {
69679
+ for (const file of fs35.readdirSync(harnessDir)) {
69680
+ const full = path41.join(harnessDir, file);
69681
+ if (!fs35.statSync(full).isFile()) continue;
69682
+ if (file === "manifest.json" || file === "plugins.json" || file.startsWith("ADAPT-PROMPT")) {
69683
+ continue;
69684
+ }
69515
69685
  if (profile === "cli" && CLI_EXPECTED_ABSENT.has(file)) {
69516
69686
  extra.push(file);
69517
69687
  } else if (isExpectedHarnessOnlyFile(file, templateFiles)) {
@@ -69541,107 +69711,356 @@ function compareHarnessToTemplate(repoPath) {
69541
69711
  }
69542
69712
 
69543
69713
  // src/harness/maintain-bundle.ts
69544
- var fs37 = __toESM(require("fs"));
69545
- var os15 = __toESM(require("os"));
69546
- var path42 = __toESM(require("path"));
69714
+ var fs40 = __toESM(require("fs"));
69715
+ var os16 = __toESM(require("os"));
69716
+ var path45 = __toESM(require("path"));
69547
69717
  init_file_ops();
69548
69718
  init_shell();
69549
69719
  init_manifest();
69550
69720
 
69551
69721
  // src/harness/plugin-drift.ts
69552
- var fs36 = __toESM(require("fs"));
69553
- var path41 = __toESM(require("path"));
69722
+ var fs39 = __toESM(require("fs"));
69723
+ var path44 = __toESM(require("path"));
69554
69724
  init_manifest();
69555
69725
 
69556
69726
  // src/harness/plugins.ts
69557
- var fs35 = __toESM(require("fs"));
69558
- var path40 = __toESM(require("path"));
69727
+ var fs38 = __toESM(require("fs"));
69728
+ var path43 = __toESM(require("path"));
69559
69729
  init_zod();
69560
69730
  init_logging();
69561
69731
 
69562
69732
  // src/harness/parser.ts
69563
- var fs34 = __toESM(require("fs"));
69733
+ var fs36 = __toESM(require("fs"));
69564
69734
  init_manifest();
69565
69735
  function harnessExists(repoPath) {
69566
- return fs34.existsSync(`${repoPath}/.har/setup-infra.sh`);
69736
+ return fs36.existsSync(`${repoPath}/.har/setup-infra.sh`);
69737
+ }
69738
+
69739
+ // src/harness/plugin-resolve.ts
69740
+ var import_child_process10 = require("child_process");
69741
+ var fs37 = __toESM(require("fs"));
69742
+ var os15 = __toESM(require("os"));
69743
+ var path42 = __toESM(require("path"));
69744
+ function hasManifest(dir) {
69745
+ return fs37.existsSync(path42.join(dir, "template.manifest.json"));
69746
+ }
69747
+ function readPackageVersion(dir) {
69748
+ const pkgPath = path42.join(dir, "package.json");
69749
+ if (!fs37.existsSync(pkgPath)) return void 0;
69750
+ try {
69751
+ const pkg = JSON.parse(fs37.readFileSync(pkgPath, "utf8"));
69752
+ return typeof pkg.version === "string" ? pkg.version : void 0;
69753
+ } catch {
69754
+ return void 0;
69755
+ }
69756
+ }
69757
+ function readManifestId(dir) {
69758
+ const manifestPath = path42.join(dir, "template.manifest.json");
69759
+ if (!fs37.existsSync(manifestPath)) return void 0;
69760
+ try {
69761
+ const raw = JSON.parse(fs37.readFileSync(manifestPath, "utf8"));
69762
+ return typeof raw.id === "string" ? raw.id : void 0;
69763
+ } catch {
69764
+ return void 0;
69765
+ }
69766
+ }
69767
+ function looksLikePath(spec) {
69768
+ return spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("~") || spec.startsWith("file:");
69769
+ }
69770
+ function looksLikeGit(spec) {
69771
+ return spec.startsWith("git+") || spec.startsWith("github:") || spec.startsWith("gitlab:") || spec.startsWith("bitbucket:") || /^https?:\/\/.+\.git$/i.test(spec) || /^git@/.test(spec);
69772
+ }
69773
+ function looksLikeNpm(spec) {
69774
+ if (looksLikePath(spec) || looksLikeGit(spec)) return false;
69775
+ if (spec.includes("/") && !spec.startsWith("@")) return false;
69776
+ return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@.+)?$/i.test(spec);
69777
+ }
69778
+ function resolveBundledDir(pluginId) {
69779
+ const dir = path42.join(resolveTemplatesDir(), "plugins", pluginId);
69780
+ return hasManifest(dir) ? dir : null;
69781
+ }
69782
+ function expandHome(p) {
69783
+ if (p.startsWith("~/")) return path42.join(os15.homedir(), p.slice(2));
69784
+ if (p === "~") return os15.homedir();
69785
+ return p;
69786
+ }
69787
+ function resolvePathSpec(spec) {
69788
+ const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
69789
+ const dir = path42.resolve(expandHome(raw));
69790
+ if (!fs37.existsSync(dir) || !fs37.statSync(dir).isDirectory()) {
69791
+ throw new Error(`Plugin path not found: ${spec}`);
69792
+ }
69793
+ if (!hasManifest(dir)) {
69794
+ throw new Error(`No template.manifest.json in ${dir}`);
69795
+ }
69796
+ const id = readManifestId(dir) ?? path42.basename(dir);
69797
+ return {
69798
+ id,
69799
+ kind: "path",
69800
+ dir,
69801
+ spec,
69802
+ version: readPackageVersion(dir),
69803
+ cleanupDirs: []
69804
+ };
69805
+ }
69806
+ function makeTempDir(prefix) {
69807
+ return fs37.mkdtempSync(path42.join(os15.tmpdir(), prefix));
69808
+ }
69809
+ function resolveNpmSpec(spec) {
69810
+ const tmp = makeTempDir("har-plugin-npm-");
69811
+ const cleanupDirs = [tmp];
69812
+ try {
69813
+ (0, import_child_process10.execFileSync)("npm", ["pack", spec, "--pack-destination", tmp], {
69814
+ encoding: "utf8",
69815
+ stdio: ["ignore", "pipe", "pipe"],
69816
+ timeout: 12e4
69817
+ });
69818
+ const tarballs = fs37.readdirSync(tmp).filter((f) => f.endsWith(".tgz"));
69819
+ if (tarballs.length === 0) {
69820
+ throw new Error(`npm pack produced no tarball for ${spec}`);
69821
+ }
69822
+ const extractDir = path42.join(tmp, "extract");
69823
+ fs37.mkdirSync(extractDir);
69824
+ (0, import_child_process10.execFileSync)("tar", ["-xzf", path42.join(tmp, tarballs[0]), "-C", extractDir], {
69825
+ encoding: "utf8",
69826
+ stdio: ["ignore", "pipe", "pipe"]
69827
+ });
69828
+ const packageDir = path42.join(extractDir, "package");
69829
+ let dir = packageDir;
69830
+ if (!hasManifest(dir)) {
69831
+ const nested = fs37.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path42.join(extractDir, e.name)).find((d) => hasManifest(d));
69832
+ if (!nested) {
69833
+ throw new Error(
69834
+ `npm package ${spec} has no template.manifest.json (not a HAR plugin bundle)`
69835
+ );
69836
+ }
69837
+ dir = nested;
69838
+ }
69839
+ const id = readManifestId(dir) ?? spec.replace(/^@/, "").replace(/[/:].*/g, "");
69840
+ return {
69841
+ id,
69842
+ kind: "npm",
69843
+ dir,
69844
+ spec,
69845
+ version: readPackageVersion(dir),
69846
+ cleanupDirs
69847
+ };
69848
+ } catch (err) {
69849
+ for (const d of cleanupDirs) {
69850
+ fs37.rmSync(d, { recursive: true, force: true });
69851
+ }
69852
+ const message = err instanceof Error ? err.message : String(err);
69853
+ throw new Error(`Failed to install plugin from npm (${spec}): ${message}`);
69854
+ }
69855
+ }
69856
+ function resolveGitSpec(spec) {
69857
+ const tmp = makeTempDir("har-plugin-git-");
69858
+ const cleanupDirs = [tmp];
69859
+ const cloneDir = path42.join(tmp, "repo");
69860
+ try {
69861
+ let url = spec;
69862
+ if (spec.startsWith("github:")) {
69863
+ url = `https://github.com/${spec.slice("github:".length)}.git`;
69864
+ } else if (spec.startsWith("gitlab:")) {
69865
+ url = `https://gitlab.com/${spec.slice("gitlab:".length)}.git`;
69866
+ } else if (spec.startsWith("bitbucket:")) {
69867
+ url = `https://bitbucket.org/${spec.slice("bitbucket:".length)}.git`;
69868
+ } else if (spec.startsWith("git+")) {
69869
+ url = spec.slice("git+".length);
69870
+ }
69871
+ (0, import_child_process10.execFileSync)("git", ["clone", "--depth", "1", url, cloneDir], {
69872
+ encoding: "utf8",
69873
+ stdio: ["ignore", "pipe", "pipe"],
69874
+ timeout: 18e4
69875
+ });
69876
+ let dir = cloneDir;
69877
+ if (!hasManifest(dir)) {
69878
+ const pluginsRoot = path42.join(cloneDir, "plugins");
69879
+ if (fs37.existsSync(pluginsRoot)) {
69880
+ const child = fs37.readdirSync(pluginsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path42.join(pluginsRoot, e.name)).find((d) => hasManifest(d));
69881
+ if (child) dir = child;
69882
+ }
69883
+ }
69884
+ if (!hasManifest(dir)) {
69885
+ throw new Error(`Git repo ${spec} has no template.manifest.json (not a HAR plugin bundle)`);
69886
+ }
69887
+ const id = readManifestId(dir) ?? path42.basename(url.replace(/\.git$/, ""));
69888
+ return {
69889
+ id,
69890
+ kind: "git",
69891
+ dir,
69892
+ spec,
69893
+ version: readPackageVersion(dir),
69894
+ cleanupDirs
69895
+ };
69896
+ } catch (err) {
69897
+ for (const d of cleanupDirs) {
69898
+ fs37.rmSync(d, { recursive: true, force: true });
69899
+ }
69900
+ const message = err instanceof Error ? err.message : String(err);
69901
+ throw new Error(`Failed to install plugin from git (${spec}): ${message}`);
69902
+ }
69903
+ }
69904
+ function resolvePluginSource(spec) {
69905
+ const trimmed = spec.trim();
69906
+ if (!trimmed) {
69907
+ throw new Error("Plugin spec is empty");
69908
+ }
69909
+ if (looksLikePath(trimmed)) {
69910
+ return resolvePathSpec(trimmed);
69911
+ }
69912
+ if (looksLikeGit(trimmed)) {
69913
+ return resolveGitSpec(trimmed);
69914
+ }
69915
+ const bundled = resolveBundledDir(trimmed);
69916
+ if (bundled) {
69917
+ return {
69918
+ id: trimmed,
69919
+ kind: "bundled",
69920
+ dir: bundled,
69921
+ spec: trimmed,
69922
+ version: readPackageVersion(bundled),
69923
+ cleanupDirs: []
69924
+ };
69925
+ }
69926
+ if (looksLikeNpm(trimmed) && (trimmed.includes("@") || trimmed.includes("/"))) {
69927
+ return resolveNpmSpec(trimmed);
69928
+ }
69929
+ if (looksLikeNpm(trimmed)) {
69930
+ try {
69931
+ return resolveNpmSpec(trimmed);
69932
+ } catch (npmErr) {
69933
+ const available2 = listBundledPluginIds();
69934
+ const npmMessage = npmErr instanceof Error ? npmErr.message : String(npmErr);
69935
+ throw new Error(
69936
+ `Unknown plugin: ${trimmed}. Bundled: ${available2.join(", ") || "(none)"}. Or pass a path, npm package, or git URL. (${npmMessage})`
69937
+ );
69938
+ }
69939
+ }
69940
+ const available = listBundledPluginIds();
69941
+ throw new Error(
69942
+ `Unknown plugin: ${trimmed}. Bundled: ${available.join(", ") || "(none)"}. Or pass a path (./plugin), npm package (@org/pkg), or git URL (github:org/repo).`
69943
+ );
69944
+ }
69945
+ function listBundledPluginIds() {
69946
+ const root = path42.join(resolveTemplatesDir(), "plugins");
69947
+ if (!fs37.existsSync(root)) return [];
69948
+ return fs37.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path42.join(root, name))).sort();
69949
+ }
69950
+ function cleanupResolvedPlugin(source) {
69951
+ for (const dir of source.cleanupDirs) {
69952
+ fs37.rmSync(dir, { recursive: true, force: true });
69953
+ }
69567
69954
  }
69568
69955
 
69569
69956
  // src/harness/plugins.ts
69570
69957
  init_schema2();
69571
69958
  init_stages();
69572
- var PLUGIN_IDS = ["playwright", "rocketsim", "kerno", "gitleaks", "trivy", "semgrep"];
69573
69959
  var PluginManifestFileSchema = external_exports.object({
69574
69960
  src: external_exports.string().min(1),
69575
69961
  dest: external_exports.string().min(1),
69576
69962
  executable: external_exports.boolean().optional(),
69577
69963
  skipFlag: external_exports.string().optional()
69578
69964
  });
69965
+ var PluginIdSchema = external_exports.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/i, "Plugin id must be a slug (letters, digits, ._-)");
69579
69966
  var PluginManifestSchema = external_exports.object({
69580
- id: external_exports.enum(PLUGIN_IDS),
69581
- stageId: external_exports.string().min(1),
69967
+ id: PluginIdSchema,
69968
+ /** @deprecated Prefer `stages` — primary stage id for single-stage plugins. */
69969
+ stageId: external_exports.string().min(1).optional(),
69582
69970
  verificationStages: external_exports.array(external_exports.string().min(1)).min(1),
69583
- stage: external_exports.record(external_exports.unknown()),
69971
+ /** @deprecated Prefer `stages` — single stage object. */
69972
+ stage: external_exports.record(external_exports.unknown()).optional(),
69973
+ /** One or more stages registered by this plugin. */
69974
+ stages: external_exports.array(external_exports.record(external_exports.unknown())).optional(),
69584
69975
  files: external_exports.array(PluginManifestFileSchema).min(1),
69585
69976
  optionalFiles: external_exports.array(PluginManifestFileSchema).optional(),
69586
69977
  merge: external_exports.record(external_exports.string()).optional(),
69587
69978
  nextSteps: external_exports.array(external_exports.string().min(1)).min(1),
69588
69979
  docsPath: external_exports.string().min(1)
69980
+ }).superRefine((data, ctx) => {
69981
+ const hasStages = Array.isArray(data.stages) && data.stages.length > 0;
69982
+ const hasLegacy = data.stage !== void 0 && data.stageId !== void 0;
69983
+ if (!hasStages && !hasLegacy) {
69984
+ ctx.addIssue({
69985
+ code: external_exports.ZodIssueCode.custom,
69986
+ message: "Plugin manifest requires `stages` (preferred) or legacy `stage` + `stageId`"
69987
+ });
69988
+ }
69589
69989
  });
69590
- function resolvePluginDir(pluginId) {
69591
- const dir = path40.join(resolveTemplatesDir(), "plugins", pluginId);
69592
- if (!fs35.existsSync(dir)) {
69990
+ function normalizePluginStages(manifest) {
69991
+ if (manifest.stages && manifest.stages.length > 0) {
69992
+ return manifest.stages.map((s) => HarnessStageSchema.parse(s));
69993
+ }
69994
+ if (manifest.stage) {
69995
+ return [HarnessStageSchema.parse(manifest.stage)];
69996
+ }
69997
+ throw new Error(`Plugin ${manifest.id} has no stages`);
69998
+ }
69999
+ function primaryStageId(manifest) {
70000
+ const stages = normalizePluginStages(manifest);
70001
+ return manifest.stageId ?? stages[0].id;
70002
+ }
70003
+ function resolveBundledPluginDir(pluginId) {
70004
+ const dir = path43.join(resolveTemplatesDir(), "plugins", pluginId);
70005
+ if (!fs38.existsSync(dir)) {
69593
70006
  throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
69594
70007
  }
69595
70008
  return dir;
69596
70009
  }
69597
- function readPluginManifest(pluginId) {
69598
- const manifestPath = path40.join(resolvePluginDir(pluginId), "template.manifest.json");
70010
+ function readPluginManifestFromDir(pluginDir, expectedId) {
70011
+ const manifestPath = path43.join(pluginDir, "template.manifest.json");
70012
+ if (!fs38.existsSync(manifestPath)) {
70013
+ throw new Error(`No template.manifest.json in ${pluginDir}`);
70014
+ }
69599
70015
  const parsed = PluginManifestSchema.safeParse(
69600
- JSON.parse(fs35.readFileSync(manifestPath, "utf8"))
70016
+ JSON.parse(fs38.readFileSync(manifestPath, "utf8"))
69601
70017
  );
69602
70018
  if (!parsed.success) {
69603
- throw new Error(`Invalid plugin manifest for ${pluginId}: ${parsed.error.message}`);
70019
+ throw new Error(`Invalid plugin manifest: ${parsed.error.message}`);
69604
70020
  }
69605
- if (parsed.data.id !== pluginId) {
69606
- throw new Error(`Plugin manifest id mismatch: expected ${pluginId}, got ${parsed.data.id}`);
70021
+ if (expectedId && parsed.data.id !== expectedId) {
70022
+ throw new Error(`Plugin manifest id mismatch: expected ${expectedId}, got ${parsed.data.id}`);
69607
70023
  }
69608
70024
  return parsed.data;
69609
70025
  }
70026
+ function readPluginManifest(pluginId) {
70027
+ return readPluginManifestFromDir(resolveBundledPluginDir(pluginId), pluginId);
70028
+ }
69610
70029
  function ensureParentDir(filePath) {
69611
- const parent = path40.dirname(filePath);
69612
- if (!fs35.existsSync(parent)) {
69613
- fs35.mkdirSync(parent, { recursive: true });
70030
+ const parent = path43.dirname(filePath);
70031
+ if (!fs38.existsSync(parent)) {
70032
+ fs38.mkdirSync(parent, { recursive: true });
69614
70033
  }
69615
70034
  }
69616
70035
  function copyPluginFile(pluginDir, file, repoPath, force) {
69617
- const srcPath = path40.join(pluginDir, file.src);
69618
- const destPath = path40.join(repoPath, file.dest);
69619
- if (!fs35.existsSync(srcPath)) {
70036
+ const srcPath = path43.join(pluginDir, file.src);
70037
+ const destPath = path43.join(repoPath, file.dest);
70038
+ if (!fs38.existsSync(srcPath)) {
69620
70039
  throw new Error(`Plugin file missing: ${file.src}`);
69621
70040
  }
69622
- if (fs35.existsSync(destPath) && !force) {
70041
+ if (fs38.existsSync(destPath) && !force) {
69623
70042
  throw new Error(
69624
70043
  `File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
69625
70044
  );
69626
70045
  }
69627
70046
  ensureParentDir(destPath);
69628
- fs35.copyFileSync(srcPath, destPath);
70047
+ fs38.copyFileSync(srcPath, destPath);
69629
70048
  if (file.executable) {
69630
- fs35.chmodSync(destPath, 493);
70049
+ fs38.chmodSync(destPath, 493);
69631
70050
  }
69632
70051
  return { written: true, path: file.dest };
69633
70052
  }
69634
70053
  function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
69635
- const packagePath = path40.join(repoPath, "package.json");
69636
- if (!fs35.existsSync(packagePath)) {
70054
+ const packagePath = path43.join(repoPath, "package.json");
70055
+ if (!fs38.existsSync(packagePath)) {
69637
70056
  throw new Error("No package.json in repo root. Add one before applying this plugin.");
69638
70057
  }
69639
- const fragmentPath = path40.join(pluginDir, fragmentRelPath);
69640
- if (!fs35.existsSync(fragmentPath)) {
70058
+ const fragmentPath = path43.join(pluginDir, fragmentRelPath);
70059
+ if (!fs38.existsSync(fragmentPath)) {
69641
70060
  throw new Error(`Package fragment missing: ${fragmentRelPath}`);
69642
70061
  }
69643
- const pkg = JSON.parse(fs35.readFileSync(packagePath, "utf8"));
69644
- const fragment = JSON.parse(fs35.readFileSync(fragmentPath, "utf8"));
70062
+ const pkg = JSON.parse(fs38.readFileSync(packagePath, "utf8"));
70063
+ const fragment = JSON.parse(fs38.readFileSync(fragmentPath, "utf8"));
69645
70064
  for (const section of ["scripts", "devDependencies"]) {
69646
70065
  const existing = pkg[section] ?? {};
69647
70066
  const incoming = fragment[section] ?? {};
@@ -69654,35 +70073,37 @@ function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
69654
70073
  }
69655
70074
  pkg[section] = existing;
69656
70075
  }
69657
- fs35.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
70076
+ fs38.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
69658
70077
  }
69659
- function patchStageRegistry(repoPath, manifest, force) {
70078
+ function patchStageRegistry(repoPath, stages, verificationStageIds, force) {
69660
70079
  const registry2 = readStageRegistry(repoPath);
69661
- const stage = HarnessStageSchema.parse(manifest.stage);
69662
- const existing = registry2.stages.find((s) => s.id === stage.id);
69663
- if (existing && !force) {
69664
- throw new Error(
69665
- `Stage "${stage.id}" already registered in .har/stages.json. Use --force to replace.`
69666
- );
70080
+ let nextStages = [...registry2.stages];
70081
+ for (const stage of stages) {
70082
+ const existing = nextStages.find((s) => s.id === stage.id);
70083
+ if (existing && !force) {
70084
+ throw new Error(
70085
+ `Stage "${stage.id}" already registered in .har/stages.json. Use --force to replace.`
70086
+ );
70087
+ }
70088
+ nextStages = existing ? nextStages.map((s) => s.id === stage.id ? stage : s) : [...nextStages, stage];
69667
70089
  }
69668
- const stages = existing ? registry2.stages.map((s) => s.id === stage.id ? stage : s) : [...registry2.stages, stage];
69669
70090
  const verificationStages = [...registry2.verificationStages ?? []];
69670
- for (const id of manifest.verificationStages) {
70091
+ for (const id of verificationStageIds) {
69671
70092
  if (!verificationStages.includes(id)) {
69672
70093
  verificationStages.push(id);
69673
70094
  }
69674
70095
  }
69675
- const verifyIdx = stages.findIndex((s) => s.id === "verify");
70096
+ const verifyIdx = nextStages.findIndex((s) => s.id === "verify");
69676
70097
  if (verifyIdx >= 0) {
69677
- stages[verifyIdx] = {
69678
- ...stages[verifyIdx],
70098
+ nextStages[verifyIdx] = {
70099
+ ...nextStages[verifyIdx],
69679
70100
  description: `Verification pipeline (quick smoke by default; --full runs the registry's verificationStages: ${verificationStages.join(", ")})`,
69680
70101
  acceptsArgs: ["--full"]
69681
70102
  };
69682
70103
  }
69683
70104
  const updated = {
69684
70105
  ...registry2,
69685
- stages,
70106
+ stages: nextStages,
69686
70107
  verificationStages
69687
70108
  };
69688
70109
  writeStageRegistry(repoPath, updated);
@@ -69692,30 +70113,33 @@ function assertHarnessPresent(repoPath) {
69692
70113
  throw new Error('No .har/ harness found. Run "har env init" first.');
69693
70114
  }
69694
70115
  }
69695
- function assertStageNotPresent(repoPath, stageId, force) {
70116
+ function assertStagesNotPresent(repoPath, stageIds, force) {
69696
70117
  if (force) return;
69697
- const scriptPath = path40.join(repoPath, ".har", "stages", `${stageId}.sh`);
69698
- if (fs35.existsSync(scriptPath)) {
69699
- throw new Error(
69700
- `Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
69701
- );
69702
- }
69703
70118
  const registry2 = readStageRegistry(repoPath);
69704
- if (registry2.stages.some((s) => s.id === stageId)) {
69705
- throw new Error(
69706
- `Stage "${stageId}" already registered in .har/stages.json. Use --force to replace.`
69707
- );
70119
+ for (const stageId of stageIds) {
70120
+ const scriptPath = path43.join(repoPath, ".har", "stages", `${stageId}.sh`);
70121
+ if (fs38.existsSync(scriptPath)) {
70122
+ throw new Error(
70123
+ `Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
70124
+ );
70125
+ }
70126
+ if (registry2.stages.some((s) => s.id === stageId)) {
70127
+ throw new Error(
70128
+ `Stage "${stageId}" already registered in .har/stages.json. Use --force to replace.`
70129
+ );
70130
+ }
69708
70131
  }
69709
70132
  }
69710
- function applyPlugin(repoPath, pluginId, options = {}) {
69711
- const resolved = path40.resolve(repoPath);
70133
+ function applyPluginFromDir(repoPath, pluginDir, options, meta) {
70134
+ const resolved = path43.resolve(repoPath);
69712
70135
  const force = options.force ?? false;
69713
70136
  const warnings = [];
69714
70137
  const filesWritten = [];
69715
70138
  assertHarnessPresent(resolved);
69716
- const manifest = readPluginManifest(pluginId);
69717
- assertStageNotPresent(resolved, manifest.stageId, force);
69718
- const pluginDir = resolvePluginDir(pluginId);
70139
+ const manifest = readPluginManifestFromDir(pluginDir);
70140
+ const stages = normalizePluginStages(manifest);
70141
+ const stageIds = stages.map((s) => s.id);
70142
+ assertStagesNotPresent(resolved, stageIds, force);
69719
70143
  for (const file of manifest.files) {
69720
70144
  const result = copyPluginFile(pluginDir, file, resolved, force);
69721
70145
  if (result.written) {
@@ -69727,7 +70151,7 @@ function applyPlugin(repoPath, pluginId, options = {}) {
69727
70151
  if (file.skipFlag === "skipCi" && options.skipCi) {
69728
70152
  continue;
69729
70153
  }
69730
- if (fs35.existsSync(path40.join(resolved, file.dest)) && !force) {
70154
+ if (fs38.existsSync(path43.join(resolved, file.dest)) && !force) {
69731
70155
  warnings.push(`Skipped optional file (exists): ${file.dest}`);
69732
70156
  continue;
69733
70157
  }
@@ -69743,9 +70167,18 @@ function applyPlugin(repoPath, pluginId, options = {}) {
69743
70167
  filesWritten.push("package.json");
69744
70168
  }
69745
70169
  }
69746
- patchStageRegistry(resolved, manifest, force);
69747
- success(`Applied plugin: ${pluginId}`);
69748
- info(`Registered stage: ${manifest.stageId}`);
70170
+ patchStageRegistry(resolved, stages, manifest.verificationStages, force);
70171
+ upsertPluginLedgerEntry(resolved, {
70172
+ id: manifest.id,
70173
+ source: meta.source,
70174
+ spec: meta.spec,
70175
+ version: meta.version,
70176
+ stageIds,
70177
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
70178
+ });
70179
+ const primary = primaryStageId(manifest);
70180
+ success(`Applied plugin: ${manifest.id}`);
70181
+ info(`Registered stage(s): ${stageIds.join(", ")}`);
69749
70182
  for (const file of filesWritten) {
69750
70183
  info(` + ${file}`);
69751
70184
  }
@@ -69753,50 +70186,88 @@ function applyPlugin(repoPath, pluginId, options = {}) {
69753
70186
  warn(` \u26A0 ${warning}`);
69754
70187
  }
69755
70188
  return {
69756
- pluginId,
69757
- stageId: manifest.stageId,
70189
+ pluginId: manifest.id,
70190
+ stageId: primary,
70191
+ stageIds,
69758
70192
  filesWritten,
69759
70193
  warnings,
69760
70194
  nextSteps: manifest.nextSteps,
69761
- docsPath: manifest.docsPath
70195
+ docsPath: manifest.docsPath,
70196
+ source: meta.source
69762
70197
  };
69763
70198
  }
70199
+ function applyPlugin(repoPath, pluginSpec, options = {}) {
70200
+ const spec = options.spec ?? pluginSpec;
70201
+ const source = resolvePluginSource(spec);
70202
+ try {
70203
+ return applyPluginFromDir(repoPath, source.dir, options, {
70204
+ source: source.kind,
70205
+ spec: source.spec,
70206
+ version: source.version
70207
+ });
70208
+ } finally {
70209
+ cleanupResolvedPlugin(source);
70210
+ }
70211
+ }
69764
70212
  function listPluginIds() {
69765
- const root = path40.join(resolveTemplatesDir(), "plugins");
69766
- if (!fs35.existsSync(root)) return [...PLUGIN_IDS];
69767
- return fs35.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
70213
+ return listBundledPluginIds();
69768
70214
  }
69769
70215
 
69770
70216
  // src/harness/plugin-drift.ts
69771
70217
  init_stages();
69772
70218
  var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
69773
70219
  function detectInstalledPlugins(repoPath) {
69774
- const resolved = path41.resolve(repoPath);
69775
- const registryPath = path41.join(resolved, ".har", "stages.json");
69776
- if (!fs36.existsSync(registryPath)) return [];
70220
+ const resolved = path44.resolve(repoPath);
70221
+ const ledger = readPluginLedger(resolved);
70222
+ if (ledger && ledger.plugins.length > 0) {
70223
+ return ledger.plugins.map((p) => p.id).sort();
70224
+ }
70225
+ const registryPath = path44.join(resolved, ".har", "stages.json");
70226
+ if (!fs39.existsSync(registryPath)) return [];
69777
70227
  const registry2 = readStageRegistry(resolved);
69778
70228
  const stageIds = new Set(registry2.stages.map((stage) => stage.id));
69779
70229
  const installed = [];
69780
- for (const pluginId of PLUGIN_IDS) {
69781
- const manifest = readPluginManifest(pluginId);
69782
- if (stageIds.has(manifest.stageId)) {
69783
- installed.push(pluginId);
70230
+ for (const pluginId of listPluginIds()) {
70231
+ try {
70232
+ const manifest = readPluginManifest(pluginId);
70233
+ const primary = primaryStageId(manifest);
70234
+ if (stageIds.has(primary)) {
70235
+ installed.push(pluginId);
70236
+ }
70237
+ } catch {
69784
70238
  }
69785
70239
  }
69786
- return installed;
70240
+ return installed.sort();
69787
70241
  }
69788
70242
  function pluginTemplatePath(pluginId, srcRel) {
69789
- return path41.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
70243
+ return path44.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
70244
+ }
70245
+ function resolvePluginTemplateDir(repoPath, pluginId) {
70246
+ const ledger = readPluginLedger(repoPath);
70247
+ const entry = ledger?.plugins.find((p) => p.id === pluginId);
70248
+ if (entry && entry.source !== "bundled") {
70249
+ try {
70250
+ const source = resolvePluginSource(entry.spec);
70251
+ cleanupResolvedPlugin(source);
70252
+ } catch {
70253
+ }
70254
+ }
70255
+ const bundled = path44.join(resolveTemplatesDir(), "plugins", pluginId);
70256
+ if (fs39.existsSync(path44.join(bundled, "template.manifest.json"))) {
70257
+ return bundled;
70258
+ }
70259
+ return null;
69790
70260
  }
69791
70261
  function readBundledPluginFile(pluginId, srcRel) {
69792
- return fs36.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
70262
+ return fs39.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
69793
70263
  }
69794
70264
  function listPluginDestPaths(pluginId, repoPath) {
69795
- const manifest = readPluginManifest(pluginId);
70265
+ const templateDir = resolvePluginTemplateDir(repoPath, pluginId);
70266
+ const manifest = templateDir ? readPluginManifestFromDir(templateDir) : readPluginManifest(pluginId);
69796
70267
  const paths = manifest.files.map((file) => file.dest);
69797
70268
  if (manifest.optionalFiles) {
69798
70269
  for (const file of manifest.optionalFiles) {
69799
- if (fs36.existsSync(path41.join(repoPath, file.dest))) {
70270
+ if (fs39.existsSync(path44.join(repoPath, file.dest))) {
69800
70271
  paths.push(file.dest);
69801
70272
  }
69802
70273
  }
@@ -69855,9 +70326,9 @@ function readTemplatePluginFile(pluginId, dest) {
69855
70326
  return null;
69856
70327
  }
69857
70328
  function readInstalledPluginFile(repoPath, pluginId, dest) {
69858
- const installedPath = path41.join(path41.resolve(repoPath), dest);
69859
- if (!fs36.existsSync(installedPath)) return null;
69860
- const content = fs36.readFileSync(installedPath, "utf8");
70329
+ const installedPath = path44.join(path44.resolve(repoPath), dest);
70330
+ if (!fs39.existsSync(installedPath)) return null;
70331
+ const content = fs39.readFileSync(installedPath, "utf8");
69861
70332
  const manifest = readPluginManifest(pluginId);
69862
70333
  const fragmentRel = manifest.merge?.[dest];
69863
70334
  if (fragmentRel) {
@@ -69876,7 +70347,7 @@ function pluginActionHint(pluginId, dest, kind) {
69876
70347
  }
69877
70348
  function comparePluginToTemplate(repoPath, pluginId) {
69878
70349
  const manifest = readPluginManifest(pluginId);
69879
- const resolved = path41.resolve(repoPath);
70350
+ const resolved = path44.resolve(repoPath);
69880
70351
  const destPaths = listPluginDestPaths(pluginId, resolved);
69881
70352
  const missing = [];
69882
70353
  const checksumMismatch = [];
@@ -69891,8 +70362,8 @@ function comparePluginToTemplate(repoPath, pluginId) {
69891
70362
  }
69892
70363
  if (dest === "package.json") {
69893
70364
  const fragmentRel = manifest.merge?.[dest];
69894
- const installedPath = path41.join(resolved, dest);
69895
- const installedRaw = fs36.readFileSync(installedPath, "utf8");
70365
+ const installedPath = path44.join(resolved, dest);
70366
+ const installedRaw = fs39.readFileSync(installedPath, "utf8");
69896
70367
  if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
69897
70368
  unchanged.push(dest);
69898
70369
  } else if (computeFileChecksum(installedContent) === computeFileChecksum(templateContent)) {
@@ -69910,16 +70381,17 @@ function comparePluginToTemplate(repoPath, pluginId) {
69910
70381
  }
69911
70382
  return {
69912
70383
  pluginId,
69913
- stageId: manifest.stageId,
70384
+ stageId: primaryStageId(manifest),
69914
70385
  missing,
69915
70386
  checksumMismatch,
69916
70387
  unchanged
69917
70388
  };
69918
70389
  }
69919
70390
  function compareInstalledPluginsToTemplate(repoPath) {
69920
- return detectInstalledPlugins(repoPath).map(
69921
- (pluginId) => comparePluginToTemplate(repoPath, pluginId)
69922
- );
70391
+ return detectInstalledPlugins(repoPath).filter((pluginId) => {
70392
+ const bundled = path44.join(resolveTemplatesDir(), "plugins", pluginId, "template.manifest.json");
70393
+ return fs39.existsSync(bundled);
70394
+ }).map((pluginId) => comparePluginToTemplate(repoPath, pluginId));
69923
70395
  }
69924
70396
  function buildPluginDriftActions(repoPath, pluginDrift) {
69925
70397
  const actions = [];
@@ -69952,23 +70424,18 @@ function buildPluginDriftActions(repoPath, pluginDrift) {
69952
70424
 
69953
70425
  // src/harness/maintain-bundle.ts
69954
70426
  var MAINTAIN_DIR = "maintain";
69955
- var PROFILE_DIRS3 = {
69956
- default: "har-boilerplate",
69957
- cli: "har-boilerplate-cli",
69958
- ios: "har-boilerplate-ios"
69959
- };
69960
70427
  function substituteProjectName2(content, projectName) {
69961
70428
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
69962
70429
  }
69963
70430
  function projectNameFromRepo(repoPath) {
69964
- return path42.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
70431
+ return path45.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
69965
70432
  }
69966
70433
  function boilerplateDirForProfile(profile) {
69967
- return path42.join(resolveTemplatesDir(), PROFILE_DIRS3[profile]);
70434
+ return path45.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
69968
70435
  }
69969
70436
  function readBundledTemplateContent(repoPath, profile, file) {
69970
- const templatePath = path42.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
69971
- let content = fs37.readFileSync(templatePath, "utf8");
70437
+ const templatePath = path45.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
70438
+ let content = fs40.readFileSync(templatePath, "utf8");
69972
70439
  if (file === "harness.env") {
69973
70440
  content = substituteProjectName2(content, projectNameFromRepo(repoPath));
69974
70441
  }
@@ -69999,12 +70466,12 @@ function actionHint(file, kind) {
69999
70466
  return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
70000
70467
  }
70001
70468
  function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
70002
- const tmpDir = fs37.mkdtempSync(path42.join(os15.tmpdir(), "har-maintain-diff-"));
70469
+ const tmpDir = fs40.mkdtempSync(path45.join(os16.tmpdir(), "har-maintain-diff-"));
70003
70470
  try {
70004
- const installedPath = path42.join(tmpDir, "installed");
70005
- const templatePath = path42.join(tmpDir, "template");
70006
- fs37.writeFileSync(installedPath, installedContent);
70007
- fs37.writeFileSync(templatePath, templateContent);
70471
+ const installedPath = path45.join(tmpDir, "installed");
70472
+ const templatePath = path45.join(tmpDir, "template");
70473
+ fs40.writeFileSync(installedPath, installedContent);
70474
+ fs40.writeFileSync(templatePath, templateContent);
70008
70475
  const result = run(`diff -u "${installedPath}" "${templatePath}"`);
70009
70476
  const body = result.stdout.trim();
70010
70477
  if (!body) return "";
@@ -70013,7 +70480,7 @@ function createUnifiedDiff(installedContent, templateContent, installedLabel, te
70013
70480
  ${body.split("\n").slice(2).join("\n")}
70014
70481
  `;
70015
70482
  } finally {
70016
- fs37.rmSync(tmpDir, { recursive: true, force: true });
70483
+ fs40.rmSync(tmpDir, { recursive: true, force: true });
70017
70484
  }
70018
70485
  }
70019
70486
  function buildActions(repoPath, profile, drift) {
@@ -70028,7 +70495,7 @@ function buildActions(repoPath, profile, drift) {
70028
70495
  });
70029
70496
  }
70030
70497
  for (const file of drift.checksumMismatch) {
70031
- const installedPath = path42.join(harnessDir, file);
70498
+ const installedPath = path45.join(harnessDir, file);
70032
70499
  const installedRel = `maintain/installed/${file}`;
70033
70500
  const templateRel = `maintain/templates/${file}`;
70034
70501
  const diffRel = `maintain/diffs/${file}.diff`;
@@ -70036,7 +70503,7 @@ function buildActions(repoPath, profile, drift) {
70036
70503
  file,
70037
70504
  kind: "drift",
70038
70505
  template: templateRel,
70039
- installed: fs37.existsSync(installedPath) ? installedRel : void 0,
70506
+ installed: fs40.existsSync(installedPath) ? installedRel : void 0,
70040
70507
  diff: diffRel,
70041
70508
  hint: actionHint(file, "drift")
70042
70509
  });
@@ -70188,28 +70655,28 @@ function buildReadme(report) {
70188
70655
  }
70189
70656
  function writeBundleArtifacts(repoPath, profile, drift, report) {
70190
70657
  const harnessDir = getHarnessDir(repoPath);
70191
- const bundleDir = path42.join(harnessDir, MAINTAIN_DIR);
70192
- if (fs37.existsSync(bundleDir)) {
70193
- fs37.rmSync(bundleDir, { recursive: true, force: true });
70658
+ const bundleDir = path45.join(harnessDir, MAINTAIN_DIR);
70659
+ if (fs40.existsSync(bundleDir)) {
70660
+ fs40.rmSync(bundleDir, { recursive: true, force: true });
70194
70661
  }
70195
70662
  const dirs = [
70196
70663
  bundleDir,
70197
- path42.join(bundleDir, "templates"),
70198
- path42.join(bundleDir, "installed"),
70199
- path42.join(bundleDir, "diffs"),
70200
- path42.join(bundleDir, "stale")
70664
+ path45.join(bundleDir, "templates"),
70665
+ path45.join(bundleDir, "installed"),
70666
+ path45.join(bundleDir, "diffs"),
70667
+ path45.join(bundleDir, "stale")
70201
70668
  ];
70202
70669
  for (const dir of dirs) {
70203
- fs37.mkdirSync(dir, { recursive: true });
70670
+ fs40.mkdirSync(dir, { recursive: true });
70204
70671
  }
70205
70672
  const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
70206
70673
  for (const file of affectedFiles) {
70207
70674
  const templateContent = readBundledTemplateContent(repoPath, profile, file);
70208
- writeFileSafe(path42.join(bundleDir, "templates", file), templateContent);
70209
- const harnessPath = path42.join(harnessDir, file);
70210
- if (fs37.existsSync(harnessPath)) {
70211
- const installedContent = fs37.readFileSync(harnessPath, "utf8");
70212
- writeFileSafe(path42.join(bundleDir, "installed", file), installedContent);
70675
+ writeFileSafe(path45.join(bundleDir, "templates", file), templateContent);
70676
+ const harnessPath = path45.join(harnessDir, file);
70677
+ if (fs40.existsSync(harnessPath)) {
70678
+ const installedContent = fs40.readFileSync(harnessPath, "utf8");
70679
+ writeFileSafe(path45.join(bundleDir, "installed", file), installedContent);
70213
70680
  const diff = createUnifiedDiff(
70214
70681
  installedContent,
70215
70682
  templateContent,
@@ -70217,14 +70684,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
70217
70684
  `templates/${file}`
70218
70685
  );
70219
70686
  if (diff) {
70220
- writeFileSafe(path42.join(bundleDir, "diffs", `${file}.diff`), diff);
70687
+ writeFileSafe(path45.join(bundleDir, "diffs", `${file}.diff`), diff);
70221
70688
  }
70222
70689
  }
70223
70690
  }
70224
- writeFileSafe(path42.join(bundleDir, "README.md"), buildReadme(report));
70225
- writeFileSafe(path42.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
70691
+ writeFileSafe(path45.join(bundleDir, "README.md"), buildReadme(report));
70692
+ writeFileSafe(path45.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
70226
70693
  writeFileSafe(
70227
- path42.join(bundleDir, "validation.json"),
70694
+ path45.join(bundleDir, "validation.json"),
70228
70695
  JSON.stringify(report.validation, null, 2) + "\n"
70229
70696
  );
70230
70697
  if (report.stale.length > 0) {
@@ -70236,34 +70703,34 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
70236
70703
  ...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
70237
70704
  ""
70238
70705
  ];
70239
- writeFileSafe(path42.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
70706
+ writeFileSafe(path45.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
70240
70707
  }
70241
70708
  return bundleDir;
70242
70709
  }
70243
70710
  function ensureParentDir2(filePath) {
70244
- const parent = path42.dirname(filePath);
70245
- if (!fs37.existsSync(parent)) {
70246
- fs37.mkdirSync(parent, { recursive: true });
70711
+ const parent = path45.dirname(filePath);
70712
+ if (!fs40.existsSync(parent)) {
70713
+ fs40.mkdirSync(parent, { recursive: true });
70247
70714
  }
70248
70715
  }
70249
70716
  function writePluginBundleArtifacts(repoPath, bundleDir, report) {
70250
70717
  if (report.pluginActions.length === 0) return;
70251
70718
  for (const action of report.pluginActions) {
70252
- const pluginRoot = path42.join(bundleDir, "plugins", action.pluginId);
70253
- const templatesDir = path42.join(pluginRoot, "templates");
70254
- const installedDir = path42.join(pluginRoot, "installed");
70255
- const diffsDir = path42.join(pluginRoot, "diffs");
70719
+ const pluginRoot = path45.join(bundleDir, "plugins", action.pluginId);
70720
+ const templatesDir = path45.join(pluginRoot, "templates");
70721
+ const installedDir = path45.join(pluginRoot, "installed");
70722
+ const diffsDir = path45.join(pluginRoot, "diffs");
70256
70723
  for (const dir of [templatesDir, installedDir, diffsDir]) {
70257
- fs37.mkdirSync(dir, { recursive: true });
70724
+ fs40.mkdirSync(dir, { recursive: true });
70258
70725
  }
70259
70726
  const templateContent = readTemplatePluginFile(action.pluginId, action.file);
70260
70727
  if (templateContent === null) continue;
70261
- const templatePath = path42.join(templatesDir, action.file);
70728
+ const templatePath = path45.join(templatesDir, action.file);
70262
70729
  ensureParentDir2(templatePath);
70263
70730
  writeFileSafe(templatePath, templateContent);
70264
70731
  const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
70265
70732
  if (installedContent !== null) {
70266
- const installedPath = path42.join(installedDir, action.file);
70733
+ const installedPath = path45.join(installedDir, action.file);
70267
70734
  ensureParentDir2(installedPath);
70268
70735
  writeFileSafe(installedPath, installedContent);
70269
70736
  const diff = createUnifiedDiff(
@@ -70273,7 +70740,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
70273
70740
  `templates/${action.file}`
70274
70741
  );
70275
70742
  if (diff) {
70276
- const diffPath = path42.join(diffsDir, `${action.file}.diff`);
70743
+ const diffPath = path45.join(diffsDir, `${action.file}.diff`);
70277
70744
  ensureParentDir2(diffPath);
70278
70745
  writeFileSafe(diffPath, diff);
70279
70746
  }
@@ -70309,9 +70776,9 @@ function buildMaintainBundle(repoPath, validation2, drift) {
70309
70776
  return { bundleDir, report };
70310
70777
  }
70311
70778
  function removeMaintainBundle(repoPath) {
70312
- const bundleDir = path42.join(getHarnessDir(repoPath), MAINTAIN_DIR);
70313
- if (fs37.existsSync(bundleDir)) {
70314
- fs37.rmSync(bundleDir, { recursive: true, force: true });
70779
+ const bundleDir = path45.join(getHarnessDir(repoPath), MAINTAIN_DIR);
70780
+ if (fs40.existsSync(bundleDir)) {
70781
+ fs40.rmSync(bundleDir, { recursive: true, force: true });
70315
70782
  }
70316
70783
  }
70317
70784
  function formatMaintainBundlePromptSection(report) {
@@ -70400,11 +70867,11 @@ init_manifest();
70400
70867
  init_stages();
70401
70868
  function listHarnessScripts(repoPath) {
70402
70869
  const harnessDir = getHarnessDir(repoPath);
70403
- if (!fs38.existsSync(harnessDir)) return [];
70404
- return fs38.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
70870
+ if (!fs41.existsSync(harnessDir)) return [];
70871
+ return fs41.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
70405
70872
  }
70406
70873
  function describeProject(repoPath) {
70407
- const resolved = path43.resolve(repoPath);
70874
+ const resolved = path46.resolve(repoPath);
70408
70875
  const manifest = readManifest(resolved);
70409
70876
  const present = harnessExists(resolved);
70410
70877
  return {
@@ -70424,8 +70891,8 @@ function describeProject(repoPath) {
70424
70891
  };
70425
70892
  }
70426
70893
  async function initHarness(options) {
70427
- const repoPath = path43.resolve(options.repoPath);
70428
- if (!fs38.existsSync(repoPath)) {
70894
+ const repoPath = path46.resolve(options.repoPath);
70895
+ if (!fs41.existsSync(repoPath)) {
70429
70896
  throw new Error(`Path not found: ${repoPath}`);
70430
70897
  }
70431
70898
  const scaffold = scaffoldHarnessBoilerplate(repoPath, {
@@ -70445,9 +70912,9 @@ async function initHarness(options) {
70445
70912
  };
70446
70913
  }
70447
70914
  async function maintainHarness(options) {
70448
- const repoPath = path43.resolve(options.repoPath);
70915
+ const repoPath = path46.resolve(options.repoPath);
70449
70916
  const harnessDir = getHarnessDir(repoPath);
70450
- if (!fs38.existsSync(harnessDir)) {
70917
+ if (!fs41.existsSync(harnessDir)) {
70451
70918
  throw new Error('No .har/ found. Run "har env init" first.');
70452
70919
  }
70453
70920
  const drift = compareHarnessToTemplate(repoPath);
@@ -70482,13 +70949,13 @@ function addPlugin(repoPath, pluginId, options = {}) {
70482
70949
  }
70483
70950
 
70484
70951
  // src/harness/custom-stage.ts
70485
- var fs39 = __toESM(require("fs"));
70486
- var path44 = __toESM(require("path"));
70952
+ var fs42 = __toESM(require("fs"));
70953
+ var path47 = __toESM(require("path"));
70487
70954
  init_schema2();
70488
70955
  init_stages();
70489
70956
  var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
70490
70957
  function addCustomStage(repoPath, options) {
70491
- const resolved = path44.resolve(repoPath);
70958
+ const resolved = path47.resolve(repoPath);
70492
70959
  if (!harnessExists(resolved)) {
70493
70960
  throw new Error('No .har/ harness found. Run "har env init" first.');
70494
70961
  }
@@ -70525,20 +70992,20 @@ function addCustomStage(repoPath, options) {
70525
70992
  if (options.command) {
70526
70993
  stage.command = options.command;
70527
70994
  } else {
70528
- const scriptRel = path44.join("stages", `${id}.sh`);
70529
- const scriptAbs = path44.join(resolved, ".har", scriptRel);
70530
- if (fs39.existsSync(scriptAbs) && !options.force) {
70995
+ const scriptRel = path47.join("stages", `${id}.sh`);
70996
+ const scriptAbs = path47.join(resolved, ".har", scriptRel);
70997
+ if (fs42.existsSync(scriptAbs) && !options.force) {
70531
70998
  throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
70532
70999
  }
70533
- const skeletonPath = path44.join(
71000
+ const skeletonPath = path47.join(
70534
71001
  resolveTemplatesDir(),
70535
71002
  "plugins",
70536
71003
  "custom-stage-skeleton.sh"
70537
71004
  );
70538
- const skeleton = fs39.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
70539
- fs39.mkdirSync(path44.dirname(scriptAbs), { recursive: true });
70540
- fs39.writeFileSync(scriptAbs, skeleton);
70541
- fs39.chmodSync(scriptAbs, 493);
71005
+ const skeleton = fs42.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
71006
+ fs42.mkdirSync(path47.dirname(scriptAbs), { recursive: true });
71007
+ fs42.writeFileSync(scriptAbs, skeleton);
71008
+ fs42.chmodSync(scriptAbs, 493);
70542
71009
  filesWritten.push(`.har/${scriptRel}`);
70543
71010
  stage.script = scriptRel;
70544
71011
  stage.artifacts = [
@@ -70586,18 +71053,18 @@ function addCustomStage(repoPath, options) {
70586
71053
  }
70587
71054
 
70588
71055
  // src/harness/adaptation-prompt.ts
70589
- var fs40 = __toESM(require("fs"));
70590
- var path45 = __toESM(require("path"));
71056
+ var fs43 = __toESM(require("fs"));
71057
+ var path48 = __toESM(require("path"));
70591
71058
  var readline5 = __toESM(require("readline"));
70592
71059
 
70593
71060
  // src/utils/clipboard.ts
70594
- var import_child_process10 = require("child_process");
71061
+ var import_child_process11 = require("child_process");
70595
71062
  function commandExists2(command2) {
70596
- const probe = process.platform === "win32" ? (0, import_child_process10.spawnSync)("where", [command2], { encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] }) : (0, import_child_process10.spawnSync)("which", [command2], { encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] });
71063
+ const probe = process.platform === "win32" ? (0, import_child_process11.spawnSync)("where", [command2], { encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] }) : (0, import_child_process11.spawnSync)("which", [command2], { encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] });
70597
71064
  return probe.status === 0;
70598
71065
  }
70599
71066
  function tryPipeCommand(command2, args, text) {
70600
- const result = (0, import_child_process10.spawnSync)(command2, args, {
71067
+ const result = (0, import_child_process11.spawnSync)(command2, args, {
70601
71068
  input: text,
70602
71069
  encoding: "utf8",
70603
71070
  stdio: ["pipe", "ignore", "ignore"]
@@ -70617,7 +71084,7 @@ function copyViaPlatformTools(text) {
70617
71084
  }
70618
71085
  if (process.platform === "win32") {
70619
71086
  if (commandExists2("powershell")) {
70620
- const result = (0, import_child_process10.spawnSync)(
71087
+ const result = (0, import_child_process11.spawnSync)(
70621
71088
  "powershell",
70622
71089
  [
70623
71090
  "-NoProfile",
@@ -70677,7 +71144,7 @@ function loadTemplate(name) {
70677
71144
  if (!filePath) {
70678
71145
  throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
70679
71146
  }
70680
- return fs40.readFileSync(filePath, "utf8");
71147
+ return fs43.readFileSync(filePath, "utf8");
70681
71148
  }
70682
71149
  function applyProfilePlaceholders(content, profile) {
70683
71150
  return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
@@ -70699,7 +71166,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
70699
71166
  }
70700
71167
  function writeAdaptationPrompt(repoPath, content) {
70701
71168
  const harnessDir = getHarnessDir(repoPath);
70702
- const filePath = path45.join(harnessDir, ADAPTATION_PROMPT_FILE);
71169
+ const filePath = path48.join(harnessDir, ADAPTATION_PROMPT_FILE);
70703
71170
  writeFileSafe(filePath, content);
70704
71171
  return filePath;
70705
71172
  }
@@ -70718,12 +71185,12 @@ function printAdaptationPrompt(content) {
70718
71185
  }
70719
71186
  function askYesNo2(question) {
70720
71187
  const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
70721
- return new Promise((resolve47) => {
71188
+ return new Promise((resolve49) => {
70722
71189
  process.stderr.write(`${question} `);
70723
71190
  rl.once("line", (answer) => {
70724
71191
  rl.close();
70725
71192
  const trimmed = answer.trim();
70726
- resolve47(trimmed === "" || /^y(es)?$/i.test(trimmed));
71193
+ resolve49(trimmed === "" || /^y(es)?$/i.test(trimmed));
70727
71194
  });
70728
71195
  });
70729
71196
  }
@@ -70754,27 +71221,27 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
70754
71221
  }
70755
71222
 
70756
71223
  // src/harness/cursor-rule.ts
70757
- var fs41 = __toESM(require("fs"));
70758
- var path46 = __toESM(require("path"));
71224
+ var fs44 = __toESM(require("fs"));
71225
+ var path49 = __toESM(require("path"));
70759
71226
  var readline6 = __toESM(require("readline"));
70760
71227
  init_file_ops();
70761
71228
  init_logging();
70762
71229
  var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
70763
71230
  function getCursorRulePath(repoPath) {
70764
- return path46.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
71231
+ return path49.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
70765
71232
  }
70766
71233
  function isCursorWorkspace(repoPath) {
70767
- return fs41.existsSync(path46.join(repoPath, ".cursor"));
71234
+ return fs44.existsSync(path49.join(repoPath, ".cursor"));
70768
71235
  }
70769
71236
  function cursorRuleExists(repoPath) {
70770
- return fs41.existsSync(getCursorRulePath(repoPath));
71237
+ return fs44.existsSync(getCursorRulePath(repoPath));
70771
71238
  }
70772
71239
  function scaffoldCursorRule(repoPath) {
70773
71240
  const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
70774
71241
  if (!templatePath) {
70775
71242
  throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
70776
71243
  }
70777
- const content = fs41.readFileSync(templatePath, "utf8");
71244
+ const content = fs44.readFileSync(templatePath, "utf8");
70778
71245
  writeFileSafe(getCursorRulePath(repoPath), content);
70779
71246
  }
70780
71247
  async function handleCursorRule(options) {
@@ -70812,16 +71279,16 @@ async function promptScaffoldCursorRule(exists) {
70812
71279
  }
70813
71280
  async function askYesNo3(question) {
70814
71281
  const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
70815
- return new Promise((resolve47) => {
71282
+ return new Promise((resolve49) => {
70816
71283
  process.stderr.write(`${question} `);
70817
71284
  rl.once("line", (answer) => {
70818
71285
  rl.close();
70819
71286
  const trimmed = answer.trim();
70820
71287
  if (trimmed === "") {
70821
- resolve47(true);
71288
+ resolve49(true);
70822
71289
  return;
70823
71290
  }
70824
- resolve47(/^y(es)?$/i.test(trimmed));
71291
+ resolve49(/^y(es)?$/i.test(trimmed));
70825
71292
  });
70826
71293
  });
70827
71294
  }
@@ -70863,8 +71330,8 @@ init_validation();
70863
71330
  init_control_config();
70864
71331
 
70865
71332
  // src/core/control-lifecycle.ts
70866
- var import_child_process11 = require("child_process");
70867
- var path47 = __toESM(require("path"));
71333
+ var import_child_process12 = require("child_process");
71334
+ var path50 = __toESM(require("path"));
70868
71335
 
70869
71336
  // src/core/control-image.ts
70870
71337
  var DEFAULT_CONTROL_IMAGE = "theosfactory/har-control";
@@ -70890,10 +71357,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
70890
71357
  var CONTROL_CONTAINER_PORT = 3847;
70891
71358
  var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
70892
71359
  function resolveControlDir() {
70893
- return path47.resolve(__dirname, "..", "control");
71360
+ return path50.resolve(__dirname, "..", "control");
70894
71361
  }
70895
71362
  function resolveControlBuildContext() {
70896
- return path47.resolve(resolveControlDir(), "..");
71363
+ return path50.resolve(resolveControlDir(), "..");
70897
71364
  }
70898
71365
  function buildDockerRunArgs(options) {
70899
71366
  const name = options.containerName ?? CONTROL_CONTAINER_NAME;
@@ -70916,7 +71383,7 @@ function buildDockerRunArgs(options) {
70916
71383
  return args;
70917
71384
  }
70918
71385
  function runDocker(args) {
70919
- const result = (0, import_child_process11.spawnSync)("docker", args, {
71386
+ const result = (0, import_child_process12.spawnSync)("docker", args, {
70920
71387
  stdio: "inherit",
70921
71388
  env: process.env
70922
71389
  });
@@ -70926,7 +71393,7 @@ function runDocker(args) {
70926
71393
  return result.status ?? 1;
70927
71394
  }
70928
71395
  function controlContainerExists(name = CONTROL_CONTAINER_NAME) {
70929
- const result = (0, import_child_process11.spawnSync)("docker", ["ps", "-aq", "-f", `name=^${name}$`], {
71396
+ const result = (0, import_child_process12.spawnSync)("docker", ["ps", "-aq", "-f", `name=^${name}$`], {
70930
71397
  encoding: "utf8",
70931
71398
  stdio: ["pipe", "pipe", "ignore"]
70932
71399
  });
@@ -70949,7 +71416,7 @@ async function startMissionControl(options) {
70949
71416
  "-t",
70950
71417
  imageRef,
70951
71418
  "-f",
70952
- path47.join(resolveControlDir(), "Dockerfile"),
71419
+ path50.join(resolveControlDir(), "Dockerfile"),
70953
71420
  resolveControlBuildContext()
70954
71421
  ]);
70955
71422
  if (buildCode !== 0) {
@@ -71096,7 +71563,7 @@ async function ensureTelemetryInfrastructure(options) {
71096
71563
  // src/core/run-service.ts
71097
71564
  init_telemetry_config();
71098
71565
  init_telemetry_env();
71099
- var path49 = __toESM(require("path"));
71566
+ var path52 = __toESM(require("path"));
71100
71567
  init_local_executor();
71101
71568
  function extractShellOutput(result) {
71102
71569
  const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
@@ -71301,12 +71768,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
71301
71768
  suffix: session.suffix,
71302
71769
  createdAt: session.createdAt
71303
71770
  });
71304
- const envFile = path49.join(session.workDir, `.env.agent.${options.agentId}`);
71771
+ const envFile = path52.join(session.workDir, `.env.agent.${options.agentId}`);
71305
71772
  try {
71306
71773
  appendTelemetryEnvToFile(envFile, {
71307
71774
  sessionKey,
71308
71775
  agentId: options.agentId,
71309
- repoPath: path49.resolve(options.repoPath),
71776
+ repoPath: path52.resolve(options.repoPath),
71310
71777
  workDir: session.workDir,
71311
71778
  branch: session.branch,
71312
71779
  suffix: session.suffix,
@@ -71547,12 +72014,12 @@ init_stages();
71547
72014
  init_logging();
71548
72015
  function askYesNo4(question) {
71549
72016
  const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
71550
- return new Promise((resolve47) => {
72017
+ return new Promise((resolve49) => {
71551
72018
  process.stderr.write(`${question} `);
71552
72019
  rl.once("line", (answer) => {
71553
72020
  rl.close();
71554
72021
  const trimmed = answer.trim();
71555
- resolve47(trimmed === "" || /^y(es)?$/i.test(trimmed));
72022
+ resolve49(trimmed === "" || /^y(es)?$/i.test(trimmed));
71556
72023
  });
71557
72024
  });
71558
72025
  }
@@ -71594,21 +72061,21 @@ async function handleCommitGateOnboarding(options) {
71594
72061
  }
71595
72062
 
71596
72063
  // src/core/onboarding-preferences.ts
71597
- var fs43 = __toESM(require("fs"));
71598
- var os17 = __toESM(require("os"));
71599
- var path50 = __toESM(require("path"));
72064
+ var fs46 = __toESM(require("fs"));
72065
+ var os18 = __toESM(require("os"));
72066
+ var path53 = __toESM(require("path"));
71600
72067
  init_schema2();
71601
72068
  function getOnboardingPreferencesPath() {
71602
72069
  if (process.env.HAR_PREFERENCES_PATH) {
71603
- return path50.resolve(process.env.HAR_PREFERENCES_PATH);
72070
+ return path53.resolve(process.env.HAR_PREFERENCES_PATH);
71604
72071
  }
71605
- return path50.join(os17.homedir(), ".har", "preferences.json");
72072
+ return path53.join(os18.homedir(), ".har", "preferences.json");
71606
72073
  }
71607
72074
  function readOnboardingPreferences() {
71608
72075
  const preferencePath = getOnboardingPreferencesPath();
71609
72076
  try {
71610
- if (!fs43.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
71611
- return OnboardingPreferencesSchema.parse(JSON.parse(fs43.readFileSync(preferencePath, "utf8")));
72077
+ if (!fs46.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
72078
+ return OnboardingPreferencesSchema.parse(JSON.parse(fs46.readFileSync(preferencePath, "utf8")));
71612
72079
  } catch {
71613
72080
  return OnboardingPreferencesSchema.parse({});
71614
72081
  }
@@ -71633,8 +72100,8 @@ function writeOnboardingPreferences(overrides) {
71633
72100
  };
71634
72101
  const parsed = OnboardingPreferencesSchema.parse(preference);
71635
72102
  const preferencePath = getOnboardingPreferencesPath();
71636
- fs43.mkdirSync(path50.dirname(preferencePath), { recursive: true });
71637
- fs43.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
72103
+ fs46.mkdirSync(path53.dirname(preferencePath), { recursive: true });
72104
+ fs46.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
71638
72105
  `);
71639
72106
  return parsed;
71640
72107
  }
@@ -71768,14 +72235,14 @@ var envCommand = {
71768
72235
  handleMaintain
71769
72236
  ).command(
71770
72237
  "add-plugin [plugin]",
71771
- `Install a verification plugin (${PLUGIN_IDS.join(", ")}) that registers stages`,
72238
+ "Install a verification plugin (bundled id, path, npm package, or git URL) that registers stages",
71772
72239
  (y) => y.positional("plugin", {
71773
72240
  type: "string",
71774
- describe: `Plugin id (${PLUGIN_IDS.join(", ")})`
72241
+ describe: "Bundled plugin id, local path (./plugin), npm package (@org/pkg), or git URL (github:org/repo)"
71775
72242
  }).option("list", {
71776
72243
  type: "boolean",
71777
72244
  default: false,
71778
- describe: "List available plugins and exit"
72245
+ describe: "List bundled plugins and exit"
71779
72246
  }).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("force", {
71780
72247
  type: "boolean",
71781
72248
  default: false,
@@ -71791,7 +72258,7 @@ var envCommand = {
71791
72258
  `Register a custom stage (--custom), or install a plugin (deprecated alias for add-plugin)`,
71792
72259
  (y) => y.positional("template", {
71793
72260
  type: "string",
71794
- describe: `Custom stage id with --custom, or a plugin id (${PLUGIN_IDS.join(", ")}) as a deprecated alias`
72261
+ describe: "Custom stage id with --custom, or a plugin id / path / npm / git spec as a deprecated alias"
71795
72262
  }).option("list", {
71796
72263
  type: "boolean",
71797
72264
  default: false,
@@ -71925,7 +72392,7 @@ var envCommand = {
71925
72392
  }
71926
72393
  };
71927
72394
  async function handleInit(argv) {
71928
- const repoPath = path51.resolve(argv.repo);
72395
+ const repoPath = path54.resolve(argv.repo);
71929
72396
  const onboarding = resolveOnboardingOptions(argv);
71930
72397
  header("har env init");
71931
72398
  info(`Repository: ${repoPath}`);
@@ -71971,7 +72438,7 @@ async function handleInit(argv) {
71971
72438
  }
71972
72439
  }
71973
72440
  async function handleMaintain(argv) {
71974
- const repoPath = path51.resolve(argv.repo);
72441
+ const repoPath = path54.resolve(argv.repo);
71975
72442
  const onboarding = resolveOnboardingOptions(argv);
71976
72443
  header("har env maintain");
71977
72444
  info(`Repository: ${repoPath}`);
@@ -72102,7 +72569,7 @@ async function applyAgentIntegrations(options) {
72102
72569
  }
72103
72570
  }
72104
72571
  async function handleAddPlugin(argv) {
72105
- const repoPath = path51.resolve(argv.repo);
72572
+ const repoPath = path54.resolve(argv.repo);
72106
72573
  const available = listPluginIds();
72107
72574
  if (argv.list) {
72108
72575
  for (const id of available) {
@@ -72110,9 +72577,9 @@ async function handleAddPlugin(argv) {
72110
72577
  }
72111
72578
  return;
72112
72579
  }
72113
- if (!argv.plugin || !available.includes(argv.plugin)) {
72580
+ if (!argv.plugin) {
72114
72581
  error(
72115
- `Unknown plugin: ${argv.plugin ?? "(missing)"}. Available: ${available.join(", ")}. For a project-specific stage, use: har env add-stage <id> --custom`
72582
+ `Missing plugin. Bundled: ${available.join(", ") || "(none)"}. Or pass a path, npm package, or git URL. For a project-specific stage, use: har env add-stage <id> --custom`
72116
72583
  );
72117
72584
  return finishCommand(1);
72118
72585
  }
@@ -72122,10 +72589,12 @@ async function handleAddPlugin(argv) {
72122
72589
  try {
72123
72590
  const result = addPlugin(repoPath, argv.plugin, {
72124
72591
  force: argv.force,
72125
- skipCi: argv.skipCi
72592
+ skipCi: argv.skipCi,
72593
+ spec: argv.plugin
72126
72594
  });
72127
72595
  divider();
72128
- success(`Plugin applied \u2014 registered stage: ${result.stageId}`);
72596
+ const stageLabel = result.stageIds.length > 1 ? `stages: ${result.stageIds.join(", ")}` : `stage: ${result.stageId}`;
72597
+ success(`Plugin applied \u2014 registered ${stageLabel} (source: ${result.source})`);
72129
72598
  console.error("");
72130
72599
  console.error(" Next steps:");
72131
72600
  for (const step of result.nextSteps) {
@@ -72140,7 +72609,7 @@ async function handleAddPlugin(argv) {
72140
72609
  }
72141
72610
  }
72142
72611
  async function handleAddStage(argv) {
72143
- const repoPath = path51.resolve(argv.repo);
72612
+ const repoPath = path54.resolve(argv.repo);
72144
72613
  const available = listPluginIds();
72145
72614
  if (argv.list) {
72146
72615
  warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
@@ -72188,9 +72657,9 @@ async function handleAddStage(argv) {
72188
72657
  }
72189
72658
  return;
72190
72659
  }
72191
- if (!argv.template || !available.includes(argv.template)) {
72660
+ if (!argv.template) {
72192
72661
  error(
72193
- `Unknown plugin: ${argv.template ?? "(missing)"}. Available: ${available.join(", ")}. Prefer: har env add-plugin <id>. For a project-specific stage, use: har env add-stage <id> --custom`
72662
+ `Unknown plugin: (missing). Available: ${available.join(", ")}. Prefer: har env add-plugin <id>. For a project-specific stage, use: har env add-stage <id> --custom`
72194
72663
  );
72195
72664
  return finishCommand(1);
72196
72665
  }
@@ -72206,7 +72675,7 @@ async function handleAddStage(argv) {
72206
72675
  });
72207
72676
  }
72208
72677
  async function handlePreflight(argv) {
72209
- const repo = path51.resolve(argv.repo);
72678
+ const repo = path54.resolve(argv.repo);
72210
72679
  const agentId = validateAgentId(argv.id, repo);
72211
72680
  const result = await preflightEnvironment({
72212
72681
  repoPath: repo,
@@ -72222,7 +72691,7 @@ async function handlePreflight(argv) {
72222
72691
  return finishCommand(result.code);
72223
72692
  }
72224
72693
  async function handleLaunch(argv) {
72225
- const repo = path51.resolve(argv.repo);
72694
+ const repo = path54.resolve(argv.repo);
72226
72695
  const agentId = validateAgentId(argv.id, repo);
72227
72696
  if (!argv.resume) {
72228
72697
  const guard = checkLaunchGuard2(repo, agentId, { worktree: argv.worktree });
@@ -72280,7 +72749,7 @@ async function handleRecover(argv) {
72280
72749
  });
72281
72750
  }
72282
72751
  async function handleVerify(argv) {
72283
- const repo = path51.resolve(argv.repo);
72752
+ const repo = path54.resolve(argv.repo);
72284
72753
  const agentId = validateAgentId(argv.id, repo);
72285
72754
  const result = await runVerification({
72286
72755
  repoPath: repo,
@@ -72292,7 +72761,7 @@ async function handleVerify(argv) {
72292
72761
  return finishCommand(result.code);
72293
72762
  }
72294
72763
  async function handleTeardown(argv) {
72295
- const repo = path51.resolve(argv.repo);
72764
+ const repo = path54.resolve(argv.repo);
72296
72765
  const agentId = validateAgentId(argv.id, repo);
72297
72766
  const result = await teardownEnvironment({
72298
72767
  repoPath: repo,
@@ -72303,7 +72772,7 @@ async function handleTeardown(argv) {
72303
72772
  return finishCommand(result.code);
72304
72773
  }
72305
72774
  async function handleComplete(argv) {
72306
- const repo = path51.resolve(argv.repo);
72775
+ const repo = path54.resolve(argv.repo);
72307
72776
  const agentId = validateAgentId(argv.id, repo);
72308
72777
  const result = await completeEnvironment({
72309
72778
  repoPath: repo,
@@ -72324,7 +72793,7 @@ async function handleComplete(argv) {
72324
72793
  return finishCommand(result.code);
72325
72794
  }
72326
72795
  async function handleStatus(argv) {
72327
- const repoPath = path51.resolve(argv.repo);
72796
+ const repoPath = path54.resolve(argv.repo);
72328
72797
  if (argv.json) {
72329
72798
  const status = collectEnvironmentStatus(repoPath);
72330
72799
  const output = EnvironmentStatusSchema.parse(status);
@@ -72337,7 +72806,7 @@ async function handleStatus(argv) {
72337
72806
  });
72338
72807
  }
72339
72808
  async function handleRunsList(argv) {
72340
- const repoPath = path51.resolve(argv.repo);
72809
+ const repoPath = path54.resolve(argv.repo);
72341
72810
  const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
72342
72811
  if (argv.json) {
72343
72812
  process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
@@ -72354,7 +72823,7 @@ async function handleRunsList(argv) {
72354
72823
  }
72355
72824
  }
72356
72825
  async function handleRunsGet(argv) {
72357
- const run2 = getRun(path51.resolve(argv.repo), argv.runId);
72826
+ const run2 = getRun(path54.resolve(argv.repo), argv.runId);
72358
72827
  if (!run2) {
72359
72828
  error(`Run not found: ${argv.runId}`);
72360
72829
  return finishCommand(1);
@@ -72436,27 +72905,27 @@ function printNextSteps() {
72436
72905
  }
72437
72906
 
72438
72907
  // src/cli/commands/control.ts
72439
- var path55 = __toESM(require("path"));
72908
+ var path58 = __toESM(require("path"));
72440
72909
  init_control_config();
72441
72910
  init_control_port();
72442
72911
  init_control_sync();
72443
72912
 
72444
72913
  // src/core/control-sync-selection.ts
72445
- var fs44 = __toESM(require("fs"));
72446
- var os18 = __toESM(require("os"));
72447
- var path52 = __toESM(require("path"));
72914
+ var fs47 = __toESM(require("fs"));
72915
+ var os19 = __toESM(require("os"));
72916
+ var path55 = __toESM(require("path"));
72448
72917
  init_control_repo_path();
72449
72918
  function getSelectionPath() {
72450
72919
  if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
72451
- return path52.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
72920
+ return path55.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
72452
72921
  }
72453
- return path52.join(os18.homedir(), ".har", "sync-selection.json");
72922
+ return path55.join(os19.homedir(), ".har", "sync-selection.json");
72454
72923
  }
72455
72924
  function readSyncSelection() {
72456
72925
  const selectionPath = getSelectionPath();
72457
72926
  try {
72458
- if (!fs44.existsSync(selectionPath)) return null;
72459
- const parsed = JSON.parse(fs44.readFileSync(selectionPath, "utf8"));
72927
+ if (!fs47.existsSync(selectionPath)) return null;
72928
+ const parsed = JSON.parse(fs47.readFileSync(selectionPath, "utf8"));
72460
72929
  if (!Array.isArray(parsed.repos)) return null;
72461
72930
  return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
72462
72931
  } catch {
@@ -72466,8 +72935,8 @@ function readSyncSelection() {
72466
72935
  function writeSyncSelection(repos) {
72467
72936
  const selectionPath = getSelectionPath();
72468
72937
  const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
72469
- fs44.mkdirSync(path52.dirname(selectionPath), { recursive: true });
72470
- fs44.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
72938
+ fs47.mkdirSync(path55.dirname(selectionPath), { recursive: true });
72939
+ fs47.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
72471
72940
  }
72472
72941
  function resolveSyncSelection(input) {
72473
72942
  const { discovered, stored, forceSelect, isTTY } = input;
@@ -72499,13 +72968,13 @@ init_portal_credentials();
72499
72968
  // src/core/portal-login.ts
72500
72969
  var http = __toESM(require("http"));
72501
72970
  var import_crypto = require("crypto");
72502
- var import_child_process13 = require("child_process");
72971
+ var import_child_process14 = require("child_process");
72503
72972
  var CALLBACK_PATH = "/callback";
72504
72973
  var LOGIN_TIMEOUT_MS = 3 * 6e4;
72505
72974
  function openBrowser(url) {
72506
72975
  const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
72507
72976
  try {
72508
- const child = (0, import_child_process13.spawn)(cmd, args, { stdio: "ignore", detached: true });
72977
+ const child = (0, import_child_process14.spawn)(cmd, args, { stdio: "ignore", detached: true });
72509
72978
  child.on("error", () => {
72510
72979
  });
72511
72980
  child.unref();
@@ -72514,7 +72983,7 @@ function openBrowser(url) {
72514
72983
  }
72515
72984
  async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
72516
72985
  const state = (0, import_crypto.randomUUID)();
72517
- return new Promise((resolve47, reject) => {
72986
+ return new Promise((resolve49, reject) => {
72518
72987
  let timer;
72519
72988
  const server = http.createServer((req, res) => {
72520
72989
  const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
@@ -72539,7 +73008,7 @@ async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
72539
73008
  res.writeHead(200, { "Content-Type": "text/html" });
72540
73009
  res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
72541
73010
  cleanup();
72542
- resolve47({
73011
+ resolve49({
72543
73012
  portalUrl,
72544
73013
  token,
72545
73014
  workspace,
@@ -72574,8 +73043,8 @@ If your browser did not open, paste that URL.
72574
73043
  }
72575
73044
 
72576
73045
  // src/core/control-unregister.ts
72577
- var fs45 = __toESM(require("fs"));
72578
- var path53 = __toESM(require("path"));
73046
+ var fs48 = __toESM(require("fs"));
73047
+ var path56 = __toESM(require("path"));
72579
73048
  init_control_repo_path();
72580
73049
  init_control_registry();
72581
73050
  init_control_config();
@@ -72585,9 +73054,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
72585
73054
  const harnessRoot = canonicalizeControlRepoPath(repoPath);
72586
73055
  const byPath = /* @__PURE__ */ new Map();
72587
73056
  const add = (partial2) => {
72588
- const resolved = path53.resolve(partial2.worktreePath);
73057
+ const resolved = path56.resolve(partial2.worktreePath);
72589
73058
  if (!resolved || resolved === harnessRoot) return;
72590
- const exists = partial2.exists ?? fs45.existsSync(resolved);
73059
+ const exists = partial2.exists ?? fs48.existsSync(resolved);
72591
73060
  const prev = byPath.get(resolved);
72592
73061
  if (prev) {
72593
73062
  byPath.set(resolved, {
@@ -72638,8 +73107,8 @@ async function askYesNo5(question) {
72638
73107
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
72639
73108
  const readline8 = await import("readline");
72640
73109
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
72641
- const answer = await new Promise((resolve47) => {
72642
- rl.question(question, resolve47);
73110
+ const answer = await new Promise((resolve49) => {
73111
+ rl.question(question, resolve49);
72643
73112
  });
72644
73113
  rl.close();
72645
73114
  return /^[Yy]$/.test(answer.trim());
@@ -72701,28 +73170,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
72701
73170
  trigger: "cli"
72702
73171
  });
72703
73172
  if (result.code !== 0) {
72704
- if (fs45.existsSync(candidate.worktreePath)) {
72705
- fs45.rmSync(candidate.worktreePath, { recursive: true, force: true });
73173
+ if (fs48.existsSync(candidate.worktreePath)) {
73174
+ fs48.rmSync(candidate.worktreePath, { recursive: true, force: true });
72706
73175
  }
72707
73176
  }
72708
73177
  outcomes.push({
72709
73178
  path: candidate.worktreePath,
72710
73179
  agentId: candidate.agentId,
72711
- deleted: !fs45.existsSync(candidate.worktreePath),
72712
- error: result.code !== 0 && fs45.existsSync(candidate.worktreePath) ? result.stderr : void 0
73180
+ deleted: !fs48.existsSync(candidate.worktreePath),
73181
+ error: result.code !== 0 && fs48.existsSync(candidate.worktreePath) ? result.stderr : void 0
72713
73182
  });
72714
73183
  } catch (err) {
72715
73184
  const message = err instanceof Error ? err.message : String(err);
72716
73185
  try {
72717
- if (fs45.existsSync(candidate.worktreePath)) {
72718
- fs45.rmSync(candidate.worktreePath, { recursive: true, force: true });
73186
+ if (fs48.existsSync(candidate.worktreePath)) {
73187
+ fs48.rmSync(candidate.worktreePath, { recursive: true, force: true });
72719
73188
  }
72720
73189
  } catch {
72721
73190
  }
72722
73191
  outcomes.push({
72723
73192
  path: candidate.worktreePath,
72724
73193
  agentId: candidate.agentId,
72725
- deleted: !fs45.existsSync(candidate.worktreePath),
73194
+ deleted: !fs48.existsSync(candidate.worktreePath),
72726
73195
  error: message
72727
73196
  });
72728
73197
  }
@@ -72785,16 +73254,16 @@ init_control_config();
72785
73254
  init_control_registry();
72786
73255
 
72787
73256
  // src/core/harness-scrub.ts
72788
- var fs46 = __toESM(require("fs"));
72789
- var path54 = __toESM(require("path"));
73257
+ var fs49 = __toESM(require("fs"));
73258
+ var path57 = __toESM(require("path"));
72790
73259
  var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
72791
73260
  function scrubLocalHarnessDirs(repoPath) {
72792
73261
  const results = [];
72793
- const resolved = path54.resolve(repoPath);
72794
- if (!fs46.existsSync(resolved)) {
73262
+ const resolved = path57.resolve(repoPath);
73263
+ if (!fs49.existsSync(resolved)) {
72795
73264
  for (const directory of HARNESS_SCRUB_DIRS) {
72796
73265
  results.push({
72797
- path: path54.join(resolved, ".har", directory),
73266
+ path: path57.join(resolved, ".har", directory),
72798
73267
  directory,
72799
73268
  deleted: false,
72800
73269
  error: "repository path does not exist"
@@ -72803,24 +73272,24 @@ function scrubLocalHarnessDirs(repoPath) {
72803
73272
  return results;
72804
73273
  }
72805
73274
  for (const directory of HARNESS_SCRUB_DIRS) {
72806
- const target = path54.join(resolved, ".har", directory);
72807
- if (!fs46.existsSync(target)) {
73275
+ const target = path57.join(resolved, ".har", directory);
73276
+ if (!fs49.existsSync(target)) {
72808
73277
  results.push({ path: target, directory, deleted: true });
72809
73278
  continue;
72810
73279
  }
72811
73280
  try {
72812
- fs46.rmSync(target, { recursive: true, force: true });
73281
+ fs49.rmSync(target, { recursive: true, force: true });
72813
73282
  results.push({
72814
73283
  path: target,
72815
73284
  directory,
72816
- deleted: !fs46.existsSync(target),
72817
- error: fs46.existsSync(target) ? "failed to remove directory" : void 0
73285
+ deleted: !fs49.existsSync(target),
73286
+ error: fs49.existsSync(target) ? "failed to remove directory" : void 0
72818
73287
  });
72819
73288
  } catch (err) {
72820
73289
  results.push({
72821
73290
  path: target,
72822
73291
  directory,
72823
- deleted: !fs46.existsSync(target),
73292
+ deleted: !fs49.existsSync(target),
72824
73293
  error: err instanceof Error ? err.message : String(err)
72825
73294
  });
72826
73295
  }
@@ -72831,7 +73300,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
72831
73300
  const results = [];
72832
73301
  const seen = /* @__PURE__ */ new Set();
72833
73302
  for (const repoPath of repoPaths) {
72834
- const key = path54.resolve(repoPath);
73303
+ const key = path57.resolve(repoPath);
72835
73304
  if (seen.has(key)) continue;
72836
73305
  seen.add(key);
72837
73306
  results.push(...scrubLocalHarnessDirs(key));
@@ -72844,8 +73313,8 @@ async function askYesNo6(question) {
72844
73313
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
72845
73314
  const readline8 = await import("readline");
72846
73315
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
72847
- const answer = await new Promise((resolve47) => {
72848
- rl.question(question, resolve47);
73316
+ const answer = await new Promise((resolve49) => {
73317
+ rl.question(question, resolve49);
72849
73318
  });
72850
73319
  rl.close();
72851
73320
  return /^[Yy]$/.test(answer.trim());
@@ -73090,7 +73559,7 @@ async function handleDown() {
73090
73559
  return finishCommand(code);
73091
73560
  }
73092
73561
  async function handleRegister(argv) {
73093
- const repoPath = path55.resolve(argv.repo);
73562
+ const repoPath = path58.resolve(argv.repo);
73094
73563
  header("har control register");
73095
73564
  info(`Repository: ${repoPath}`);
73096
73565
  try {
@@ -73182,7 +73651,7 @@ async function handleReset(argv) {
73182
73651
  }
73183
73652
  }
73184
73653
  async function handleUnregister(argv) {
73185
- const repoPath = path55.resolve(argv.repo);
73654
+ const repoPath = path58.resolve(argv.repo);
73186
73655
  const worktrees = listUnregisterWorktreeCandidates(repoPath);
73187
73656
  try {
73188
73657
  let deleteWorktrees = argv.deleteWorktrees;
@@ -73364,12 +73833,12 @@ async function handleLogin(argv) {
73364
73833
  }
73365
73834
 
73366
73835
  // src/cli/commands/hooks.ts
73367
- var path57 = __toESM(require("path"));
73836
+ var path60 = __toESM(require("path"));
73368
73837
  init_hooks();
73369
73838
 
73370
73839
  // src/core/claude-hooks.ts
73371
- var fs47 = __toESM(require("fs"));
73372
- var path56 = __toESM(require("path"));
73840
+ var fs50 = __toESM(require("fs"));
73841
+ var path59 = __toESM(require("path"));
73373
73842
  var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
73374
73843
  var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
73375
73844
  var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
@@ -73380,8 +73849,8 @@ function isHarGuardEntry(entry) {
73380
73849
  );
73381
73850
  }
73382
73851
  function readSettings(settingsPath) {
73383
- if (!fs47.existsSync(settingsPath)) return {};
73384
- const raw = fs47.readFileSync(settingsPath, "utf8").trim();
73852
+ if (!fs50.existsSync(settingsPath)) return {};
73853
+ const raw = fs50.readFileSync(settingsPath, "utf8").trim();
73385
73854
  if (raw === "") return {};
73386
73855
  const parsed = JSON.parse(raw);
73387
73856
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -73390,19 +73859,19 @@ function readSettings(settingsPath) {
73390
73859
  return parsed;
73391
73860
  }
73392
73861
  function writeSettings(settingsPath, settings) {
73393
- fs47.mkdirSync(path56.dirname(settingsPath), { recursive: true });
73394
- fs47.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
73862
+ fs50.mkdirSync(path59.dirname(settingsPath), { recursive: true });
73863
+ fs50.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
73395
73864
  }
73396
73865
  function installClaudeGuard(repoPath) {
73397
73866
  const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
73398
73867
  if (!templatePath) {
73399
73868
  throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
73400
73869
  }
73401
- const guardScript = path56.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73402
- fs47.mkdirSync(path56.dirname(guardScript), { recursive: true });
73403
- fs47.copyFileSync(templatePath, guardScript);
73404
- fs47.chmodSync(guardScript, 493);
73405
- const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73870
+ const guardScript = path59.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73871
+ fs50.mkdirSync(path59.dirname(guardScript), { recursive: true });
73872
+ fs50.copyFileSync(templatePath, guardScript);
73873
+ fs50.chmodSync(guardScript, 493);
73874
+ const settingsPath = path59.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73406
73875
  const settings = readSettings(settingsPath);
73407
73876
  const hooks = settings.hooks ?? {};
73408
73877
  const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
@@ -73416,15 +73885,15 @@ function installClaudeGuard(repoPath) {
73416
73885
  }
73417
73886
  function uninstallClaudeGuard(repoPath) {
73418
73887
  let removed = false;
73419
- const guardScript = path56.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73420
- if (fs47.existsSync(guardScript)) {
73421
- fs47.rmSync(guardScript);
73888
+ const guardScript = path59.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73889
+ if (fs50.existsSync(guardScript)) {
73890
+ fs50.rmSync(guardScript);
73422
73891
  removed = true;
73423
- const parent = path56.dirname(guardScript);
73424
- if (fs47.existsSync(parent) && fs47.readdirSync(parent).length === 0) fs47.rmdirSync(parent);
73892
+ const parent = path59.dirname(guardScript);
73893
+ if (fs50.existsSync(parent) && fs50.readdirSync(parent).length === 0) fs50.rmdirSync(parent);
73425
73894
  }
73426
- const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73427
- if (fs47.existsSync(settingsPath)) {
73895
+ const settingsPath = path59.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73896
+ if (fs50.existsSync(settingsPath)) {
73428
73897
  const settings = readSettings(settingsPath);
73429
73898
  const preToolUse = settings.hooks?.PreToolUse;
73430
73899
  if (preToolUse) {
@@ -73449,8 +73918,8 @@ function uninstallClaudeGuard(repoPath) {
73449
73918
  return { removed };
73450
73919
  }
73451
73920
  function claudeGuardInstalled(repoPath) {
73452
- const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73453
- if (!fs47.existsSync(settingsPath)) return false;
73921
+ const settingsPath = path59.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73922
+ if (!fs50.existsSync(settingsPath)) return false;
73454
73923
  try {
73455
73924
  const settings = readSettings(settingsPath);
73456
73925
  return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
@@ -73467,7 +73936,7 @@ function repoOption(y) {
73467
73936
  function handleInstall2(argv) {
73468
73937
  try {
73469
73938
  if (argv.claude) {
73470
- const result2 = installClaudeGuard(path57.resolve(argv.repo));
73939
+ const result2 = installClaudeGuard(path60.resolve(argv.repo));
73471
73940
  success("Claude Code worktree guard installed.");
73472
73941
  info(`Guard script: ${result2.guardScript}`);
73473
73942
  info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
@@ -73475,7 +73944,7 @@ function handleInstall2(argv) {
73475
73944
  info("Commit both files so the guard travels with the repo.");
73476
73945
  return;
73477
73946
  }
73478
- const result = installHooks({ repoPath: path57.resolve(argv.repo), force: argv.force });
73947
+ const result = installHooks({ repoPath: path60.resolve(argv.repo), force: argv.force });
73479
73948
  success(`Commit gate installed in ${result.hooksDir}`);
73480
73949
  info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
73481
73950
  info("Commits of unverified change batches will be blocked in agent worktrees.");
@@ -73488,7 +73957,7 @@ function handleInstall2(argv) {
73488
73957
  function handleUninstall(argv) {
73489
73958
  try {
73490
73959
  if (argv.claude) {
73491
- const result2 = uninstallClaudeGuard(path57.resolve(argv.repo));
73960
+ const result2 = uninstallClaudeGuard(path60.resolve(argv.repo));
73492
73961
  if (result2.removed) {
73493
73962
  success("Claude Code worktree guard removed.");
73494
73963
  } else {
@@ -73496,7 +73965,7 @@ function handleUninstall(argv) {
73496
73965
  }
73497
73966
  return;
73498
73967
  }
73499
- const result = uninstallHooks(path57.resolve(argv.repo));
73968
+ const result = uninstallHooks(path60.resolve(argv.repo));
73500
73969
  if (result.removed) {
73501
73970
  success(`Commit gate removed from ${result.hooksDir}`);
73502
73971
  } else {
@@ -73509,7 +73978,7 @@ function handleUninstall(argv) {
73509
73978
  }
73510
73979
  function handleStatus2(argv) {
73511
73980
  try {
73512
- const status = getHooksStatus(path57.resolve(argv.repo));
73981
+ const status = getHooksStatus(path60.resolve(argv.repo));
73513
73982
  if (argv.json) {
73514
73983
  process.stdout.write(`${JSON.stringify(status, null, 2)}
73515
73984
  `);
@@ -73527,7 +73996,7 @@ function handleStatus2(argv) {
73527
73996
  );
73528
73997
  info(`Effective: ${status.effectiveMode} (in this checkout)`);
73529
73998
  info(
73530
- `Claude guard: ${claudeGuardInstalled(path57.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
73999
+ `Claude guard: ${claudeGuardInstalled(path60.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
73531
74000
  );
73532
74001
  } catch (err) {
73533
74002
  error(err instanceof Error ? err.message : String(err));
@@ -73788,10 +74257,10 @@ function assignProp(target, prop, value) {
73788
74257
  configurable: true
73789
74258
  });
73790
74259
  }
73791
- function getElementAtPath(obj, path62) {
73792
- if (!path62)
74260
+ function getElementAtPath(obj, path65) {
74261
+ if (!path65)
73793
74262
  return obj;
73794
- return path62.reduce((acc, key) => acc?.[key], obj);
74263
+ return path65.reduce((acc, key) => acc?.[key], obj);
73795
74264
  }
73796
74265
  function promiseAllObject(promisesObj) {
73797
74266
  const keys = Object.keys(promisesObj);
@@ -74111,11 +74580,11 @@ function aborted(x, startIndex = 0) {
74111
74580
  }
74112
74581
  return false;
74113
74582
  }
74114
- function prefixIssues(path62, issues) {
74583
+ function prefixIssues(path65, issues) {
74115
74584
  return issues.map((iss) => {
74116
74585
  var _a2;
74117
74586
  (_a2 = iss).path ?? (_a2.path = []);
74118
- iss.path.unshift(path62);
74587
+ iss.path.unshift(path65);
74119
74588
  return iss;
74120
74589
  });
74121
74590
  }
@@ -79438,7 +79907,7 @@ var Protocol = class {
79438
79907
  return;
79439
79908
  }
79440
79909
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
79441
- await new Promise((resolve47) => setTimeout(resolve47, pollInterval));
79910
+ await new Promise((resolve49) => setTimeout(resolve49, pollInterval));
79442
79911
  options?.signal?.throwIfAborted();
79443
79912
  }
79444
79913
  } catch (error3) {
@@ -79455,7 +79924,7 @@ var Protocol = class {
79455
79924
  */
79456
79925
  request(request, resultSchema, options) {
79457
79926
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
79458
- return new Promise((resolve47, reject) => {
79927
+ return new Promise((resolve49, reject) => {
79459
79928
  const earlyReject = (error3) => {
79460
79929
  reject(error3);
79461
79930
  };
@@ -79533,7 +80002,7 @@ var Protocol = class {
79533
80002
  if (!parseResult.success) {
79534
80003
  reject(parseResult.error);
79535
80004
  } else {
79536
- resolve47(parseResult.data);
80005
+ resolve49(parseResult.data);
79537
80006
  }
79538
80007
  } catch (error3) {
79539
80008
  reject(error3);
@@ -79794,12 +80263,12 @@ var Protocol = class {
79794
80263
  }
79795
80264
  } catch {
79796
80265
  }
79797
- return new Promise((resolve47, reject) => {
80266
+ return new Promise((resolve49, reject) => {
79798
80267
  if (signal.aborted) {
79799
80268
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
79800
80269
  return;
79801
80270
  }
79802
- const timeoutId = setTimeout(resolve47, interval);
80271
+ const timeoutId = setTimeout(resolve49, interval);
79803
80272
  signal.addEventListener("abort", () => {
79804
80273
  clearTimeout(timeoutId);
79805
80274
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -80589,7 +81058,7 @@ var Server = class extends Protocol {
80589
81058
  };
80590
81059
 
80591
81060
  // src/mcp/server.ts
80592
- var path58 = __toESM(require("path"));
81061
+ var path61 = __toESM(require("path"));
80593
81062
 
80594
81063
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
80595
81064
  var import_node_process3 = __toESM(require("node:process"), 1);
@@ -80672,12 +81141,12 @@ var StdioServerTransport = class {
80672
81141
  this.onclose?.();
80673
81142
  }
80674
81143
  send(message) {
80675
- return new Promise((resolve47) => {
81144
+ return new Promise((resolve49) => {
80676
81145
  const json = serializeMessage(message);
80677
81146
  if (this._stdout.write(json)) {
80678
- resolve47();
81147
+ resolve49();
80679
81148
  } else {
80680
- this._stdout.once("drain", resolve47);
81149
+ this._stdout.once("drain", resolve49);
80681
81150
  }
80682
81151
  });
80683
81152
  }
@@ -81232,7 +81701,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
81232
81701
  const input = ControlUpInputSchema.parse({ ...args, repo });
81233
81702
  const result = await startControlAndSync({
81234
81703
  detach: input.detach,
81235
- cwd: path58.resolve(input.repo)
81704
+ cwd: path61.resolve(input.repo)
81236
81705
  });
81237
81706
  if (result.code !== 0) {
81238
81707
  return {
@@ -81296,11 +81765,11 @@ var mcpCommand = {
81296
81765
  };
81297
81766
 
81298
81767
  // src/cli/commands/onboard.ts
81299
- var path60 = __toESM(require("path"));
81768
+ var path63 = __toESM(require("path"));
81300
81769
  init_stages();
81301
81770
 
81302
81771
  // src/core/onboarding.ts
81303
- var path59 = __toESM(require("path"));
81772
+ var path62 = __toESM(require("path"));
81304
81773
  init_control_config();
81305
81774
  init_control_sync();
81306
81775
  init_otel_hooks();
@@ -81345,7 +81814,8 @@ function listPluginChoices() {
81345
81814
  return listPluginIds().map((id) => {
81346
81815
  try {
81347
81816
  const manifest = readPluginManifest(id);
81348
- const description = typeof manifest.stage.description === "string" ? manifest.stage.description : `Adds stage ${manifest.stageId}`;
81817
+ const stages = normalizePluginStages(manifest);
81818
+ const description = typeof stages[0]?.description === "string" ? stages[0].description : `Adds stage ${primaryStageId(manifest)}`;
81349
81819
  return {
81350
81820
  id,
81351
81821
  label: `${id} \u2014 ${description}`,
@@ -81435,7 +81905,7 @@ async function defaultEnsureControl(options) {
81435
81905
  return { started: true, apiUrl: result.apiUrl };
81436
81906
  }
81437
81907
  async function runOnboarding(options, deps = {}) {
81438
- const repoPath = path59.resolve(options.repoPath);
81908
+ const repoPath = path62.resolve(options.repoPath);
81439
81909
  const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
81440
81910
  const ensureControl = deps.ensureControl ?? defaultEnsureControl;
81441
81911
  const init = deps.initHarness ?? initHarness;
@@ -81623,7 +82093,7 @@ async function promptChoices(args) {
81623
82093
  };
81624
82094
  }
81625
82095
  const pluginChoices = listPluginChoices();
81626
- const repoPath = path60.resolve(args.repo);
82096
+ const repoPath = path63.resolve(args.repo);
81627
82097
  const alreadyPresent = harnessExists(repoPath);
81628
82098
  const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
81629
82099
  const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
@@ -81740,7 +82210,7 @@ function printSummary(result) {
81740
82210
  console.error("");
81741
82211
  }
81742
82212
  async function handleOnboard(argv) {
81743
- const repoPath = path60.resolve(argv.repo);
82213
+ const repoPath = path63.resolve(argv.repo);
81744
82214
  header("har onboard");
81745
82215
  info(`Repository: ${repoPath}`);
81746
82216
  try {
@@ -81971,7 +82441,7 @@ var preferencesCommand = {
81971
82441
  };
81972
82442
 
81973
82443
  // src/cli/commands/telemetry.ts
81974
- var path61 = __toESM(require("path"));
82444
+ var path64 = __toESM(require("path"));
81975
82445
  init_control_config();
81976
82446
  init_control_sync();
81977
82447
  init_manifest();
@@ -82064,7 +82534,7 @@ async function handleOff() {
82064
82534
  info("Mission Control will not auto-start. Existing usage rows are kept.");
82065
82535
  }
82066
82536
  async function handleWriteEnv(argv) {
82067
- const repoPath = path61.resolve(argv.repo);
82537
+ const repoPath = path64.resolve(argv.repo);
82068
82538
  const harnessRoot = resolveHarnessRoot(repoPath);
82069
82539
  const session = readSlotRegistry(harnessRoot, argv.agentId);
82070
82540
  const workDir = argv.workDir ?? session?.workDir ?? repoPath;
@@ -82076,7 +82546,7 @@ async function handleWriteEnv(argv) {
82076
82546
  suffix,
82077
82547
  createdAt: session?.createdAt
82078
82548
  });
82079
- const envFile = argv.envFile ?? path61.join(workDir, `.env.agent.${argv.agentId}`);
82549
+ const envFile = argv.envFile ?? path64.join(workDir, `.env.agent.${argv.agentId}`);
82080
82550
  const attrs = {
82081
82551
  sessionKey,
82082
82552
  agentId: argv.agentId,
@@ -82092,7 +82562,7 @@ async function handleWriteEnv(argv) {
82092
82562
  success(`Wrote session attribution to ${envFile}`);
82093
82563
  }
82094
82564
  function handlePrintEnv(argv) {
82095
- const repoPath = path61.resolve(argv.repo);
82565
+ const repoPath = path64.resolve(argv.repo);
82096
82566
  const workDir = argv.workDir ?? repoPath;
82097
82567
  const sessionKey = buildSessionKey({
82098
82568
  branch: argv.branch,