@osfactory/har 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +887 -685
  2. package/package.json +1 -1
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: path61, errorMaps, issueData } = params;
557
- const fullPath = [...path61, ...issueData.path || []];
556
+ const { data, path: path62, errorMaps, issueData } = params;
557
+ const fullPath = [...path62, ...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, path61, key) {
865
+ constructor(parent, value, path62, key) {
866
866
  this._cachedPath = [];
867
867
  this.parent = parent;
868
868
  this.data = value;
869
- this._path = path61;
869
+ this._path = path62;
870
870
  this._key = key;
871
871
  }
872
872
  get path() {
@@ -32051,6 +32051,7 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false)
32051
32051
  const workUnits = listWorkUnits(harnessRoot);
32052
32052
  const attempts = listWorkAttempts(harnessRoot);
32053
32053
  const validationBindings = listValidationBindings(harnessRoot);
32054
+ const userEmail = resolvePortalUserEmail();
32054
32055
  const { usage: usage2, events, maxSyncedAt } = await collectPortalTelemetry(
32055
32056
  repoPath,
32056
32057
  status.slots,
@@ -32069,13 +32070,16 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false)
32069
32070
  ...stagesRegistry ? { stagesRegistry } : {},
32070
32071
  slots: status.slots,
32071
32072
  generatedAt: status.generatedAt,
32072
- ...validations.length > 0 ? { validations } : {},
32073
+ ...validations.length > 0 ? {
32074
+ validations: userEmail ? validations.map((v2) => ({ ...v2, userEmail })) : validations
32075
+ } : {},
32073
32076
  ...workUnits.length > 0 ? { workUnits } : {},
32074
32077
  ...attempts.length > 0 ? { attempts } : {},
32075
32078
  ...validationBindings.length > 0 ? { validationBindings } : {},
32076
32079
  ...usage2.length > 0 ? { usage: usage2 } : {}
32077
32080
  };
32078
- return { syncBody, runs, events, maxSyncedAt };
32081
+ const runsPayload = userEmail ? runs.map((run2) => ({ ...run2, userEmail })) : runs;
32082
+ return { syncBody, runs: runsPayload, events, maxSyncedAt };
32079
32083
  }
32080
32084
  async function isControlApiReachable(apiUrl = getControlApiUrl()) {
32081
32085
  try {
@@ -32518,32 +32522,32 @@ __export(otel_hooks_exports, {
32518
32522
  });
32519
32523
  function getOtelHooksHome() {
32520
32524
  if (process.env.HAR_OTEL_HOOKS_HOME) {
32521
- return path46.resolve(process.env.HAR_OTEL_HOOKS_HOME);
32525
+ return path47.resolve(process.env.HAR_OTEL_HOOKS_HOME);
32522
32526
  }
32523
- return path46.join(os15.homedir(), ".har", "otel-hooks");
32527
+ return path47.join(os15.homedir(), ".har", "otel-hooks");
32524
32528
  }
32525
32529
  function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
32526
- return path46.join(hooksHome, "otel_config.json");
32530
+ return path47.join(hooksHome, "otel_config.json");
32527
32531
  }
32528
32532
  function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
32529
- return path46.join(hooksHome, "run-otel-hook.sh");
32533
+ return path47.join(hooksHome, "run-otel-hook.sh");
32530
32534
  }
32531
32535
  function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
32532
- return path46.join(hooksHome, "state");
32536
+ return path47.join(hooksHome, "state");
32533
32537
  }
32534
32538
  function localOtelHookBin(hooksHome) {
32535
- return path46.join(hooksHome, "node_modules", ".bin", "otel-hook");
32539
+ return path47.join(hooksHome, "node_modules", ".bin", "otel-hook");
32536
32540
  }
32537
32541
  function installedPackageVersion(hooksHome) {
32538
32542
  try {
32539
- const pkgPath = path46.join(
32543
+ const pkgPath = path47.join(
32540
32544
  hooksHome,
32541
32545
  "node_modules",
32542
32546
  "@osfactory",
32543
32547
  "otel-hook",
32544
32548
  "package.json"
32545
32549
  );
32546
- const pkg = JSON.parse(fs40.readFileSync(pkgPath, "utf8"));
32550
+ const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf8"));
32547
32551
  return typeof pkg.version === "string" ? pkg.version : null;
32548
32552
  } catch {
32549
32553
  return null;
@@ -32594,15 +32598,15 @@ function buildOtelHooksConfig(options) {
32594
32598
  };
32595
32599
  }
32596
32600
  function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
32597
- fs40.mkdirSync(hooksHome, { recursive: true });
32601
+ fs41.mkdirSync(hooksHome, { recursive: true });
32598
32602
  const configPath = getOtelHooksConfigPath(hooksHome);
32599
- fs40.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
32603
+ fs41.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
32600
32604
  `);
32601
32605
  return configPath;
32602
32606
  }
32603
32607
  function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
32604
- fs40.mkdirSync(hooksHome, { recursive: true });
32605
- fs40.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
32608
+ fs41.mkdirSync(hooksHome, { recursive: true });
32609
+ fs41.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
32606
32610
  const wrapperPath = getOtelHooksWrapperPath(hooksHome);
32607
32611
  const configPath = getOtelHooksConfigPath(hooksHome);
32608
32612
  const stateDir = getOtelHooksStateDir(hooksHome);
@@ -32614,9 +32618,9 @@ exec "${otelHookCommand}" run \\
32614
32618
  --state-dir "${stateDir}" \\
32615
32619
  "$@"
32616
32620
  `;
32617
- fs40.writeFileSync(wrapperPath, script, { mode: 493 });
32621
+ fs41.writeFileSync(wrapperPath, script, { mode: 493 });
32618
32622
  try {
32619
- fs40.chmodSync(wrapperPath, 493);
32623
+ fs41.chmodSync(wrapperPath, 493);
32620
32624
  } catch {
32621
32625
  }
32622
32626
  return wrapperPath;
@@ -32629,11 +32633,11 @@ function commandExists2(command2) {
32629
32633
  }
32630
32634
  function resolveOtelHookCommand(hooksHome) {
32631
32635
  const local = localOtelHookBin(hooksHome);
32632
- if (fs40.existsSync(local)) return local;
32636
+ if (fs41.existsSync(local)) return local;
32633
32637
  return null;
32634
32638
  }
32635
32639
  function tryInstallPackage(hooksHome) {
32636
- fs40.mkdirSync(hooksHome, { recursive: true });
32640
+ fs41.mkdirSync(hooksHome, { recursive: true });
32637
32641
  if (!commandExists2("npm")) {
32638
32642
  return {
32639
32643
  ok: false,
@@ -32645,7 +32649,7 @@ function tryInstallPackage(hooksHome) {
32645
32649
  ["install", "--prefix", hooksHome, "--no-fund", "--no-audit", OTEL_HOOKS_PACKAGE],
32646
32650
  { encoding: "utf8", timeout: 18e4 }
32647
32651
  );
32648
- if (result.status === 0 && fs40.existsSync(localOtelHookBin(hooksHome))) {
32652
+ if (result.status === 0 && fs41.existsSync(localOtelHookBin(hooksHome))) {
32649
32653
  return { ok: true, detail: `npm install --prefix ${hooksHome} ${OTEL_HOOKS_PACKAGE}` };
32650
32654
  }
32651
32655
  return {
@@ -32671,14 +32675,14 @@ function uninstallLegacyPythonHooks(hooksHome) {
32671
32675
  }
32672
32676
  function removeLegacyPythonArtifacts(hooksHome) {
32673
32677
  const legacyPaths = [
32674
- path46.join(hooksHome, ".venv"),
32675
- path46.join(hooksHome, "otel_config.yaml"),
32676
- path46.join(hooksHome, "venv")
32678
+ path47.join(hooksHome, ".venv"),
32679
+ path47.join(hooksHome, "otel_config.yaml"),
32680
+ path47.join(hooksHome, "venv")
32677
32681
  ];
32678
32682
  for (const target of legacyPaths) {
32679
32683
  try {
32680
- if (fs40.existsSync(target)) {
32681
- fs40.rmSync(target, { recursive: true, force: true });
32684
+ if (fs41.existsSync(target)) {
32685
+ fs41.rmSync(target, { recursive: true, force: true });
32682
32686
  }
32683
32687
  } catch {
32684
32688
  }
@@ -32719,10 +32723,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
32719
32723
  };
32720
32724
  }
32721
32725
  function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
32722
- if (!fs40.existsSync(filePath)) return false;
32726
+ if (!fs41.existsSync(filePath)) return false;
32723
32727
  let raw;
32724
32728
  try {
32725
- raw = fs40.readFileSync(filePath, "utf8");
32729
+ raw = fs41.readFileSync(filePath, "utf8");
32726
32730
  } catch {
32727
32731
  return false;
32728
32732
  }
@@ -32769,15 +32773,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
32769
32773
  return changed;
32770
32774
  };
32771
32775
  if (!walk(parsed)) return false;
32772
- fs40.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32776
+ fs41.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32773
32777
  `);
32774
32778
  return true;
32775
32779
  }
32776
32780
  function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
32777
- if (!fs40.existsSync(filePath)) return false;
32781
+ if (!fs41.existsSync(filePath)) return false;
32778
32782
  let raw;
32779
32783
  try {
32780
- raw = fs40.readFileSync(filePath, "utf8");
32784
+ raw = fs41.readFileSync(filePath, "utf8");
32781
32785
  } catch {
32782
32786
  return false;
32783
32787
  }
@@ -32812,21 +32816,21 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
32812
32816
  }
32813
32817
  }
32814
32818
  if (!changed) return false;
32815
- fs40.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32819
+ fs41.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32816
32820
  `);
32817
32821
  return true;
32818
32822
  }
32819
32823
  function rewriteKnownHookRegistrations(wrapperPath) {
32820
32824
  const home = os15.homedir();
32821
32825
  const candidates = [
32822
- path46.join(home, ".cursor", "hooks.json"),
32823
- path46.join(home, ".claude", "settings.json"),
32824
- path46.join(home, ".codex", "hooks.json")
32826
+ path47.join(home, ".cursor", "hooks.json"),
32827
+ path47.join(home, ".claude", "settings.json"),
32828
+ path47.join(home, ".codex", "hooks.json")
32825
32829
  ];
32826
32830
  for (const filePath of candidates) {
32827
32831
  try {
32828
32832
  rewriteHookCommandsToWrapper(filePath, wrapperPath);
32829
- if (filePath.endsWith(`${path46.sep}.cursor${path46.sep}hooks.json`)) {
32833
+ if (filePath.endsWith(`${path47.sep}.cursor${path47.sep}hooks.json`)) {
32830
32834
  pruneLegacyCursorHookEvents(filePath, wrapperPath);
32831
32835
  }
32832
32836
  } catch {
@@ -32842,7 +32846,7 @@ function ensureOtelHooks(options) {
32842
32846
  const hooksHome = getOtelHooksHome();
32843
32847
  const errors = [];
32844
32848
  const providersSetup = [];
32845
- fs40.mkdirSync(hooksHome, { recursive: true });
32849
+ fs41.mkdirSync(hooksHome, { recursive: true });
32846
32850
  let otelHookCommand = resolveOtelHookCommand(hooksHome);
32847
32851
  const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
32848
32852
  if (needsInstall) {
@@ -32936,14 +32940,14 @@ function ensureOtelHooks(options) {
32936
32940
  function disableOtelHooksExport() {
32937
32941
  return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
32938
32942
  }
32939
- var import_child_process10, fs40, os15, path46, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
32943
+ var import_child_process10, fs41, os15, path47, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
32940
32944
  var init_otel_hooks = __esm({
32941
32945
  "src/core/otel-hooks.ts"() {
32942
32946
  "use strict";
32943
32947
  import_child_process10 = require("child_process");
32944
- fs40 = __toESM(require("fs"));
32948
+ fs41 = __toESM(require("fs"));
32945
32949
  os15 = __toESM(require("os"));
32946
- path46 = __toESM(require("path"));
32950
+ path47 = __toESM(require("path"));
32947
32951
  init_control_config();
32948
32952
  init_telemetry_config();
32949
32953
  OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.1.2";
@@ -34059,15 +34063,15 @@ var require_route = __commonJS({
34059
34063
  };
34060
34064
  }
34061
34065
  function wrapConversion(toModel, graph) {
34062
- const path61 = [graph[toModel].parent, toModel];
34066
+ const path62 = [graph[toModel].parent, toModel];
34063
34067
  let fn = conversions[graph[toModel].parent][toModel];
34064
34068
  let cur = graph[toModel].parent;
34065
34069
  while (graph[cur].parent) {
34066
- path61.unshift(graph[cur].parent);
34070
+ path62.unshift(graph[cur].parent);
34067
34071
  fn = link(conversions[graph[cur].parent][cur], fn);
34068
34072
  cur = graph[cur].parent;
34069
34073
  }
34070
- fn.conversion = path61;
34074
+ fn.conversion = path62;
34071
34075
  return fn;
34072
34076
  }
34073
34077
  module2.exports = function(fromModel) {
@@ -39997,7 +40001,7 @@ var require_iso2022 = __commonJS({
39997
40001
  // node_modules/chardet/index.js
39998
40002
  var require_chardet = __commonJS({
39999
40003
  "node_modules/chardet/index.js"(exports2, module2) {
40000
- var fs47 = require("fs");
40004
+ var fs48 = require("fs");
40001
40005
  var utf8 = require_utf8();
40002
40006
  var unicode = require_unicode();
40003
40007
  var mbcs = require_mbcs();
@@ -40071,28 +40075,28 @@ var require_chardet = __commonJS({
40071
40075
  var fd;
40072
40076
  var handler = function(err, buffer) {
40073
40077
  if (fd) {
40074
- fs47.closeSync(fd);
40078
+ fs48.closeSync(fd);
40075
40079
  }
40076
40080
  if (err) return cb(err, null);
40077
40081
  cb(null, self.detect(buffer, opts));
40078
40082
  };
40079
40083
  if (opts && opts.sampleSize) {
40080
- fd = fs47.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40081
- fs47.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40084
+ fd = fs48.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40085
+ fs48.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40082
40086
  handler(err, sample);
40083
40087
  });
40084
40088
  return;
40085
40089
  }
40086
- fs47.readFile(filepath, handler);
40090
+ fs48.readFile(filepath, handler);
40087
40091
  };
40088
40092
  module2.exports.detectFileSync = function(filepath, opts) {
40089
40093
  if (opts && opts.sampleSize) {
40090
- var fd = fs47.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40091
- fs47.readSync(fd, sample2, 0, opts.sampleSize);
40092
- fs47.closeSync(fd);
40094
+ var fd = fs48.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40095
+ fs48.readSync(fd, sample2, 0, opts.sampleSize);
40096
+ fs48.closeSync(fd);
40093
40097
  return self.detect(sample2, opts);
40094
40098
  }
40095
- return self.detect(fs47.readFileSync(filepath), opts);
40099
+ return self.detect(fs48.readFileSync(filepath), opts);
40096
40100
  };
40097
40101
  module2.exports.detectAll = function(buffer, opts) {
40098
40102
  if (typeof opts !== "object") {
@@ -43557,16 +43561,16 @@ var require_os_tmpdir = __commonJS({
43557
43561
  var isWindows = process.platform === "win32";
43558
43562
  var trailingSlashRe = isWindows ? /[^:]\\$/ : /.\/$/;
43559
43563
  module2.exports = function() {
43560
- var path61;
43564
+ var path62;
43561
43565
  if (isWindows) {
43562
- path61 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43566
+ path62 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43563
43567
  } else {
43564
- path61 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43568
+ path62 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43565
43569
  }
43566
- if (trailingSlashRe.test(path61)) {
43567
- path61 = path61.slice(0, -1);
43570
+ if (trailingSlashRe.test(path62)) {
43571
+ path62 = path62.slice(0, -1);
43568
43572
  }
43569
- return path61;
43573
+ return path62;
43570
43574
  };
43571
43575
  }
43572
43576
  });
@@ -43574,8 +43578,8 @@ var require_os_tmpdir = __commonJS({
43574
43578
  // node_modules/tmp/lib/tmp.js
43575
43579
  var require_tmp = __commonJS({
43576
43580
  "node_modules/tmp/lib/tmp.js"(exports2, module2) {
43577
- var fs47 = require("fs");
43578
- var path61 = require("path");
43581
+ var fs48 = require("fs");
43582
+ var path62 = require("path");
43579
43583
  var crypto6 = require("crypto");
43580
43584
  var osTmpDir = require_os_tmpdir();
43581
43585
  var _c2 = process.binding("constants");
@@ -43617,7 +43621,7 @@ var require_tmp = __commonJS({
43617
43621
  }
43618
43622
  function _generateTmpName(opts) {
43619
43623
  if (opts.name) {
43620
- return path61.join(opts.dir || tmpDir, opts.name);
43624
+ return path62.join(opts.dir || tmpDir, opts.name);
43621
43625
  }
43622
43626
  if (opts.template) {
43623
43627
  return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
@@ -43628,7 +43632,7 @@ var require_tmp = __commonJS({
43628
43632
  _randomChars(12),
43629
43633
  opts.postfix || ""
43630
43634
  ].join("");
43631
- return path61.join(opts.dir || tmpDir, name);
43635
+ return path62.join(opts.dir || tmpDir, name);
43632
43636
  }
43633
43637
  function tmpName(options, callback) {
43634
43638
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1], tries = opts.name ? 1 : opts.tries || DEFAULT_TRIES;
@@ -43638,7 +43642,7 @@ var require_tmp = __commonJS({
43638
43642
  return cb(new Error("Invalid template provided"));
43639
43643
  (function _getUniqueName() {
43640
43644
  const name = _generateTmpName(opts);
43641
- fs47.stat(name, function(err) {
43645
+ fs48.stat(name, function(err) {
43642
43646
  if (!err) {
43643
43647
  if (tries-- > 0) return _getUniqueName();
43644
43648
  return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
@@ -43656,7 +43660,7 @@ var require_tmp = __commonJS({
43656
43660
  do {
43657
43661
  const name = _generateTmpName(opts);
43658
43662
  try {
43659
- fs47.statSync(name);
43663
+ fs48.statSync(name);
43660
43664
  } catch (e) {
43661
43665
  return name;
43662
43666
  }
@@ -43668,13 +43672,13 @@ var require_tmp = __commonJS({
43668
43672
  opts.postfix = _isUndefined(opts.postfix) ? ".tmp" : opts.postfix;
43669
43673
  tmpName(opts, function _tmpNameCreated(err, name) {
43670
43674
  if (err) return cb(err);
43671
- fs47.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43675
+ fs48.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43672
43676
  if (err2) return cb(err2);
43673
43677
  if (opts.discardDescriptor) {
43674
- return fs47.close(fd, function _discardCallback(err3) {
43678
+ return fs48.close(fd, function _discardCallback(err3) {
43675
43679
  if (err3) {
43676
43680
  try {
43677
- fs47.unlinkSync(name);
43681
+ fs48.unlinkSync(name);
43678
43682
  } catch (e) {
43679
43683
  if (!isENOENT(e)) {
43680
43684
  err3 = e;
@@ -43697,9 +43701,9 @@ var require_tmp = __commonJS({
43697
43701
  opts.postfix = opts.postfix || ".tmp";
43698
43702
  const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
43699
43703
  const name = tmpNameSync(opts);
43700
- var fd = fs47.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43704
+ var fd = fs48.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43701
43705
  if (opts.discardDescriptor) {
43702
- fs47.closeSync(fd);
43706
+ fs48.closeSync(fd);
43703
43707
  fd = void 0;
43704
43708
  }
43705
43709
  return {
@@ -43711,9 +43715,9 @@ var require_tmp = __commonJS({
43711
43715
  function _rmdirRecursiveSync(root) {
43712
43716
  const dirs = [root];
43713
43717
  do {
43714
- var dir2 = dirs.pop(), deferred = false, files = fs47.readdirSync(dir2);
43718
+ var dir2 = dirs.pop(), deferred = false, files = fs48.readdirSync(dir2);
43715
43719
  for (var i = 0, length = files.length; i < length; i++) {
43716
- var file2 = path61.join(dir2, files[i]), stat = fs47.lstatSync(file2);
43720
+ var file2 = path62.join(dir2, files[i]), stat = fs48.lstatSync(file2);
43717
43721
  if (stat.isDirectory()) {
43718
43722
  if (!deferred) {
43719
43723
  deferred = true;
@@ -43721,11 +43725,11 @@ var require_tmp = __commonJS({
43721
43725
  }
43722
43726
  dirs.push(file2);
43723
43727
  } else {
43724
- fs47.unlinkSync(file2);
43728
+ fs48.unlinkSync(file2);
43725
43729
  }
43726
43730
  }
43727
43731
  if (!deferred) {
43728
- fs47.rmdirSync(dir2);
43732
+ fs48.rmdirSync(dir2);
43729
43733
  }
43730
43734
  } while (dirs.length !== 0);
43731
43735
  }
@@ -43733,7 +43737,7 @@ var require_tmp = __commonJS({
43733
43737
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1];
43734
43738
  tmpName(opts, function _tmpNameCreated(err, name) {
43735
43739
  if (err) return cb(err);
43736
- fs47.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43740
+ fs48.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43737
43741
  if (err2) return cb(err2);
43738
43742
  cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
43739
43743
  });
@@ -43742,7 +43746,7 @@ var require_tmp = __commonJS({
43742
43746
  function dirSync(options) {
43743
43747
  var args = _parseArguments(options), opts = args[0];
43744
43748
  const name = tmpNameSync(opts);
43745
- fs47.mkdirSync(name, opts.mode || DIR_MODE);
43749
+ fs48.mkdirSync(name, opts.mode || DIR_MODE);
43746
43750
  return {
43747
43751
  name,
43748
43752
  removeCallback: _prepareTmpDirRemoveCallback(name, opts)
@@ -43752,7 +43756,7 @@ var require_tmp = __commonJS({
43752
43756
  const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
43753
43757
  try {
43754
43758
  if (0 <= fdPath[0]) {
43755
- fs47.closeSync(fdPath[0]);
43759
+ fs48.closeSync(fdPath[0]);
43756
43760
  }
43757
43761
  } catch (e) {
43758
43762
  if (!isEBADF(e) && !isENOENT(e)) {
@@ -43760,7 +43764,7 @@ var require_tmp = __commonJS({
43760
43764
  }
43761
43765
  }
43762
43766
  try {
43763
- fs47.unlinkSync(fdPath[1]);
43767
+ fs48.unlinkSync(fdPath[1]);
43764
43768
  } catch (e) {
43765
43769
  if (!isENOENT(e)) {
43766
43770
  throw e;
@@ -43773,7 +43777,7 @@ var require_tmp = __commonJS({
43773
43777
  return removeCallback;
43774
43778
  }
43775
43779
  function _prepareTmpDirRemoveCallback(name, opts) {
43776
- const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs47.rmdirSync.bind(fs47);
43780
+ const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs48.rmdirSync.bind(fs48);
43777
43781
  const removeCallback = _prepareRemoveCallback(removeFunction, name);
43778
43782
  if (!opts.keep) {
43779
43783
  _removeObjects.unshift(removeCallback);
@@ -56906,8 +56910,8 @@ var require_utils = __commonJS({
56906
56910
  }
56907
56911
  return ind;
56908
56912
  }
56909
- function removeDotSegments(path61) {
56910
- let input = path61;
56913
+ function removeDotSegments(path62) {
56914
+ let input = path62;
56911
56915
  const output = [];
56912
56916
  let nextSlash = -1;
56913
56917
  let len = 0;
@@ -57159,8 +57163,8 @@ var require_schemes = __commonJS({
57159
57163
  wsComponent.secure = void 0;
57160
57164
  }
57161
57165
  if (wsComponent.resourceName) {
57162
- const [path61, query] = wsComponent.resourceName.split("?");
57163
- wsComponent.path = path61 && path61 !== "/" ? path61 : void 0;
57166
+ const [path62, query] = wsComponent.resourceName.split("?");
57167
+ wsComponent.path = path62 && path62 !== "/" ? path62 : void 0;
57164
57168
  wsComponent.query = query;
57165
57169
  wsComponent.resourceName = void 0;
57166
57170
  }
@@ -60553,12 +60557,12 @@ var require_dist = __commonJS({
60553
60557
  throw new Error(`Unknown format "${name}"`);
60554
60558
  return f;
60555
60559
  };
60556
- function addFormats(ajv, list, fs47, exportName) {
60560
+ function addFormats(ajv, list, fs48, exportName) {
60557
60561
  var _a2;
60558
60562
  var _b2;
60559
60563
  (_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
60560
60564
  for (const f of list)
60561
- ajv.addFormat(f, fs47[f]);
60565
+ ajv.addFormat(f, fs48[f]);
60562
60566
  }
60563
60567
  module2.exports = exports2 = formatsPlugin;
60564
60568
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -61842,11 +61846,11 @@ var parser = new YargsParser({
61842
61846
  resolve: import_path2.resolve,
61843
61847
  // TODO: figure out a way to combine ESM and CJS coverage, such that
61844
61848
  // we can exercise all the lines below:
61845
- require: (path61) => {
61849
+ require: (path62) => {
61846
61850
  if (typeof require !== "undefined") {
61847
- return require(path61);
61848
- } else if (path61.match(/\.json$/)) {
61849
- return JSON.parse((0, import_fs2.readFileSync)(path61, "utf8"));
61851
+ return require(path62);
61852
+ } else if (path62.match(/\.json$/)) {
61853
+ return JSON.parse((0, import_fs2.readFileSync)(path62, "utf8"));
61850
61854
  } else {
61851
61855
  throw Error("only .json config files are supported in ESM");
61852
61856
  }
@@ -65755,7 +65759,7 @@ function handleRemove(argv) {
65755
65759
  }
65756
65760
 
65757
65761
  // src/cli/commands/env.ts
65758
- var path50 = __toESM(require("path"));
65762
+ var path51 = __toESM(require("path"));
65759
65763
 
65760
65764
  // src/cli/finish-command.ts
65761
65765
  init_sync_context();
@@ -65765,8 +65769,8 @@ async function finishCommand(code) {
65765
65769
  }
65766
65770
 
65767
65771
  // src/core/harness.ts
65768
- var fs36 = __toESM(require("fs"));
65769
- var path41 = __toESM(require("path"));
65772
+ var fs37 = __toESM(require("fs"));
65773
+ var path42 = __toESM(require("path"));
65770
65774
 
65771
65775
  // src/harness/generator.ts
65772
65776
  var fs28 = __toESM(require("fs"));
@@ -65890,9 +65894,485 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
65890
65894
  success("Harness adaptation complete.");
65891
65895
  }
65892
65896
 
65893
- // src/harness/validator.ts
65897
+ // src/harness/agent-md.ts
65898
+ var fs30 = __toESM(require("fs"));
65899
+ var path36 = __toESM(require("path"));
65900
+ init_file_ops();
65901
+ init_logging();
65902
+ init_manifest();
65903
+
65904
+ // src/harness/instruction-files.ts
65894
65905
  var fs29 = __toESM(require("fs"));
65906
+ var os13 = __toESM(require("os"));
65895
65907
  var path35 = __toESM(require("path"));
65908
+ var readline2 = __toESM(require("readline"));
65909
+ init_file_ops();
65910
+ init_logging();
65911
+ var AGENTS_MD = "AGENTS.md";
65912
+ var LEGACY_AGENT_MD = "AGENT.md";
65913
+ var CLAUDE_MD = "CLAUDE.md";
65914
+ var HAR_SECTION_START = "<!-- har:agent-environment:start -->";
65915
+ var HAR_SECTION_END = "<!-- har:agent-environment:end -->";
65916
+ var CLAUDE_HAR_SECTION_START = "<!-- har:claude-pointer:start -->";
65917
+ var CLAUDE_HAR_SECTION_END = "<!-- har:claude-pointer:end -->";
65918
+ var AgentsMdShrinkError = class extends Error {
65919
+ constructor(message) {
65920
+ super(message);
65921
+ this.name = "AgentsMdShrinkError";
65922
+ }
65923
+ };
65924
+ function escapeRegExp(value) {
65925
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
65926
+ }
65927
+ function countNonEmptyLines(text) {
65928
+ return text.split("\n").filter((line) => line.trim().length > 0).length;
65929
+ }
65930
+ function stripClaudePointerFromAgentsMd(content) {
65931
+ if (!content.includes(CLAUDE_HAR_SECTION_START)) return content;
65932
+ const pattern = new RegExp(
65933
+ `${escapeRegExp(CLAUDE_HAR_SECTION_START)}[\\s\\S]*?${escapeRegExp(CLAUDE_HAR_SECTION_END)}\\n?`,
65934
+ "g"
65935
+ );
65936
+ return content.replace(pattern, "").replace(/\n{3,}/g, "\n\n");
65937
+ }
65938
+ function extractOutsideHarSection(content) {
65939
+ const sanitized = stripClaudePointerFromAgentsMd(content);
65940
+ return removeCompleteMarkedBlocks(sanitized, HAR_SECTION_START, HAR_SECTION_END).trim();
65941
+ }
65942
+ function findLastCompleteMarkedBlock(content, startMarker, endMarker) {
65943
+ let last = null;
65944
+ let searchFrom = 0;
65945
+ while (searchFrom < content.length) {
65946
+ const start = content.indexOf(startMarker, searchFrom);
65947
+ if (start === -1) break;
65948
+ const end = content.indexOf(endMarker, start + startMarker.length);
65949
+ if (end === -1) break;
65950
+ const nestedStart = content.indexOf(startMarker, start + startMarker.length);
65951
+ if (nestedStart !== -1 && nestedStart < end) {
65952
+ searchFrom = start + startMarker.length;
65953
+ continue;
65954
+ }
65955
+ last = { start, end: end + endMarker.length };
65956
+ searchFrom = end + endMarker.length;
65957
+ }
65958
+ return last;
65959
+ }
65960
+ function removeCompleteMarkedBlocks(content, startMarker, endMarker) {
65961
+ let result = content;
65962
+ let block = findLastCompleteMarkedBlock(result, startMarker, endMarker);
65963
+ while (block) {
65964
+ result = result.slice(0, block.start) + result.slice(block.end);
65965
+ block = findLastCompleteMarkedBlock(result, startMarker, endMarker);
65966
+ }
65967
+ return result;
65968
+ }
65969
+ function checkOutsideContentPreserved(before, after, options) {
65970
+ const outsideBefore = extractOutsideHarSection(before);
65971
+ const outsideAfter = extractOutsideHarSection(after);
65972
+ const beforeLines = countNonEmptyLines(outsideBefore);
65973
+ const afterLines = countNonEmptyLines(outsideAfter);
65974
+ const minRatio = options.minOutsidePreservationRatio ?? 0.9;
65975
+ if (beforeLines >= 5 && afterLines < beforeLines * minRatio) {
65976
+ return "shrink";
65977
+ }
65978
+ return "ok";
65979
+ }
65980
+ function outsideContentShrinkMessage(beforeLines, afterLines) {
65981
+ return `Refusing to update ${AGENTS_MD}: refresh would drop project-specific content outside har:agent-environment markers (${beforeLines} \u2192 ${afterLines} non-empty lines). Keep custom sections outside those markers, or merge manually before --finalize.`;
65982
+ }
65983
+ function detectInstructionFiles(repoPath) {
65984
+ return {
65985
+ agentsMd: fs29.existsSync(path35.join(repoPath, AGENTS_MD)),
65986
+ agentMd: fs29.existsSync(path35.join(repoPath, LEGACY_AGENT_MD)),
65987
+ claudeMd: fs29.existsSync(path35.join(repoPath, CLAUDE_MD)),
65988
+ cursorDir: fs29.existsSync(path35.join(repoPath, ".cursor")),
65989
+ claudeDir: fs29.existsSync(path35.join(repoPath, ".claude")),
65990
+ codexHome: fs29.existsSync(path35.join(os13.homedir(), ".codex"))
65991
+ };
65992
+ }
65993
+ function formatDetectionReport(detection) {
65994
+ const lines2 = ["Detected:"];
65995
+ lines2.push(` - ${AGENTS_MD} (${detection.agentsMd ? "exists" : "missing"})`);
65996
+ if (detection.agentMd) {
65997
+ lines2.push(` - ${LEGACY_AGENT_MD} (legacy \u2014 will migrate into ${AGENTS_MD})`);
65998
+ }
65999
+ lines2.push(` - ${CLAUDE_MD} (${detection.claudeMd ? "exists" : "missing"})`);
66000
+ lines2.push(` - .cursor/ (${detection.cursorDir ? "exists" : "missing"})`);
66001
+ lines2.push(` - .claude/ (${detection.claudeDir ? "exists" : "missing"})`);
66002
+ lines2.push(` - ~/.codex (${detection.codexHome ? "exists" : "missing"})`);
66003
+ return lines2.join("\n");
66004
+ }
66005
+ function buildInstallPlan(detection, targets, options = {}) {
66006
+ const writeAgentsMd = options.writeAgentsMd !== false;
66007
+ const skillsEnabled = options.skillsEnabled !== false;
66008
+ const cursorExplicit = options.cursorRule;
66009
+ const wantsCursor = cursorExplicit === true || cursorExplicit !== false && (targets.includes("cursor") || detection.cursorDir);
66010
+ return {
66011
+ agentsMd: writeAgentsMd,
66012
+ migrateLegacyAgentMd: writeAgentsMd && detection.agentMd,
66013
+ claudeMd: skillsEnabled && targets.includes("claude"),
66014
+ cursorRule: wantsCursor,
66015
+ skills: skillsEnabled ? targets : []
66016
+ };
66017
+ }
66018
+ function formatInstallPlan(plan, detection) {
66019
+ const mark = (on) => on ? "[x]" : "[ ]";
66020
+ const lines2 = ["After you confirm, HAR will:"];
66021
+ const agentsAction = detection.agentsMd ? `Update ${AGENTS_MD} \u2014 refresh HAR / agent environment section` : `Create ${AGENTS_MD} \u2014 shared HAR workflow (Codex + cross-tool)`;
66022
+ lines2.push(` ${mark(plan.agentsMd)} ${agentsAction}`);
66023
+ if (plan.migrateLegacyAgentMd) {
66024
+ lines2.push(` ${mark(true)} Migrate ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD}, then remove legacy file`);
66025
+ }
66026
+ lines2.push(
66027
+ ` ${mark(plan.claudeMd)} Claude \u2014 ensure ${CLAUDE_MD} points at ${AGENTS_MD}; install .claude/skills if confirmed`
66028
+ );
66029
+ lines2.push(
66030
+ ` ${mark(plan.cursorRule)} Cursor \u2014 install/refresh .cursor/rules/har-workflow.mdc + commands if confirmed`
66031
+ );
66032
+ lines2.push(
66033
+ ` ${mark(plan.skills.includes("codex"))} Codex \u2014 global ~/.codex/prompts (skills); project contract is ${AGENTS_MD}`
66034
+ );
66035
+ return lines2.join("\n");
66036
+ }
66037
+ function loadHarAgentsSectionFromTemplate() {
66038
+ const templatePath = resolveTemplateFile("AGENTS.md.template");
66039
+ if (!templatePath) {
66040
+ throw new Error("AGENTS.md.template not found. Run npm run build.");
66041
+ }
66042
+ const content = fs29.readFileSync(templatePath, "utf8");
66043
+ const start = content.indexOf(HAR_SECTION_START);
66044
+ const end = content.indexOf(HAR_SECTION_END);
66045
+ if (start === -1 || end === -1 || end < start) {
66046
+ throw new Error("AGENTS.md.template is missing har:agent-environment markers.");
66047
+ }
66048
+ return content.slice(start, end + HAR_SECTION_END.length);
66049
+ }
66050
+ function loadAgentsMdTemplate() {
66051
+ const templatePath = resolveTemplateFile("AGENTS.md.template");
66052
+ if (!templatePath) {
66053
+ throw new Error("AGENTS.md.template not found. Run npm run build.");
66054
+ }
66055
+ return fs29.readFileSync(templatePath, "utf8");
66056
+ }
66057
+ function upsertMarkedBlock(content, block, startMarker, endMarker) {
66058
+ const existingBlock = findLastCompleteMarkedBlock(content, startMarker, endMarker);
66059
+ if (existingBlock) {
66060
+ const newContent = content.slice(0, existingBlock.start) + block + content.slice(existingBlock.end);
66061
+ return { content: newContent, action: "updated" };
66062
+ }
66063
+ const suffix = content.endsWith("\n") ? "" : "\n";
66064
+ return { content: `${content}${suffix}
66065
+ ${block}
66066
+ `, action: "appended" };
66067
+ }
66068
+ function mergeAgentsMdContent(existing, incoming) {
66069
+ const sanitizedExisting = stripClaudePointerFromAgentsMd(existing);
66070
+ const sanitizedIncoming = stripClaudePointerFromAgentsMd(incoming);
66071
+ let harSection = loadHarAgentsSectionFromTemplate();
66072
+ if (sanitizedIncoming.includes(HAR_SECTION_START)) {
66073
+ const start = sanitizedIncoming.indexOf(HAR_SECTION_START);
66074
+ const end = sanitizedIncoming.indexOf(HAR_SECTION_END, start + HAR_SECTION_START.length);
66075
+ if (end !== -1) {
66076
+ harSection = sanitizedIncoming.slice(start, end + HAR_SECTION_END.length);
66077
+ }
66078
+ }
66079
+ const { content } = upsertMarkedBlock(
66080
+ sanitizedExisting,
66081
+ harSection,
66082
+ HAR_SECTION_START,
66083
+ HAR_SECTION_END
66084
+ );
66085
+ return content;
66086
+ }
66087
+ function upsertAgentsMdHarSection(repoPath, options = {}) {
66088
+ const dest = path35.join(repoPath, AGENTS_MD);
66089
+ const section = loadHarAgentsSectionFromTemplate();
66090
+ if (!fs29.existsSync(dest)) {
66091
+ writeFileSafe(dest, loadAgentsMdTemplate());
66092
+ return "created";
66093
+ }
66094
+ const existing = fs29.readFileSync(dest, "utf8");
66095
+ const sanitized = stripClaudePointerFromAgentsMd(existing);
66096
+ const { content, action } = upsertMarkedBlock(
66097
+ sanitized,
66098
+ section,
66099
+ HAR_SECTION_START,
66100
+ HAR_SECTION_END
66101
+ );
66102
+ if (checkOutsideContentPreserved(existing, content, options) === "shrink") {
66103
+ const beforeLines = countNonEmptyLines(extractOutsideHarSection(existing));
66104
+ const afterLines = countNonEmptyLines(extractOutsideHarSection(content));
66105
+ const message = outsideContentShrinkMessage(beforeLines, afterLines);
66106
+ if (options.rejectSignificantShrink) {
66107
+ throw new AgentsMdShrinkError(message);
66108
+ }
66109
+ warn(message);
66110
+ return "skipped";
66111
+ }
66112
+ if (content === existing) {
66113
+ return "skipped";
66114
+ }
66115
+ writeFileSafe(dest, content);
66116
+ return action;
66117
+ }
66118
+ function migrateLegacyAgentMd(repoPath) {
66119
+ const legacyPath = path35.join(repoPath, LEGACY_AGENT_MD);
66120
+ const agentsPath = path35.join(repoPath, AGENTS_MD);
66121
+ if (!fs29.existsSync(legacyPath)) return false;
66122
+ const legacy = fs29.readFileSync(legacyPath, "utf8");
66123
+ if (!fs29.existsSync(agentsPath)) {
66124
+ writeFileSafe(agentsPath, legacy);
66125
+ upsertAgentsMdHarSection(repoPath);
66126
+ } else {
66127
+ const agents = fs29.readFileSync(agentsPath, "utf8");
66128
+ const legacyTrimmed = legacy.trim();
66129
+ if (legacyTrimmed.length > 0 && !agents.includes(legacyTrimmed)) {
66130
+ const suffix = agents.endsWith("\n") ? "" : "\n";
66131
+ writeFileSafe(agentsPath, `${agents}${suffix}
66132
+ ${legacyTrimmed}
66133
+ `);
66134
+ }
66135
+ upsertAgentsMdHarSection(repoPath);
66136
+ }
66137
+ fs29.unlinkSync(legacyPath);
66138
+ info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
66139
+ return true;
66140
+ }
66141
+ function loadClaudeMdTemplate(projectName) {
66142
+ const templatePath = resolveTemplateFile("CLAUDE.md.template");
66143
+ if (!templatePath) {
66144
+ throw new Error("CLAUDE.md.template not found. Run npm run build.");
66145
+ }
66146
+ const displayName = projectName.replace(/_/g, " ");
66147
+ return fs29.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
66148
+ }
66149
+ function isThinClaudePointer(content) {
66150
+ const trimmed = content.trim();
66151
+ if (trimmed.length > 600) return false;
66152
+ return /AGENTS\.md|AGENT\.md/.test(trimmed) && (trimmed.includes(".har/README.md") || trimmed.includes("har-workflow"));
66153
+ }
66154
+ var CLAUDE_POINTER_BLOCK = `${CLAUDE_HAR_SECTION_START}
66155
+ ## HAR
66156
+
66157
+ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
66158
+ [\`.har/README.md\`](./.har/README.md) before making changes.
66159
+ ${CLAUDE_HAR_SECTION_END}`;
66160
+ function ensureClaudeMdPointer(repoPath, options = {}) {
66161
+ const dest = path35.join(repoPath, CLAUDE_MD);
66162
+ const projectName = path35.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66163
+ const thin = loadClaudeMdTemplate(projectName);
66164
+ if (!fs29.existsSync(dest)) {
66165
+ writeFileSafe(dest, thin);
66166
+ return "created";
66167
+ }
66168
+ const existing = fs29.readFileSync(dest, "utf8");
66169
+ if (isThinClaudePointer(existing) || options.force) {
66170
+ writeFileSafe(dest, thin);
66171
+ return "updated";
66172
+ }
66173
+ if (existing.includes(CLAUDE_HAR_SECTION_START) || /\[AGENTS\.md\]/.test(existing)) {
66174
+ if (existing.includes(CLAUDE_HAR_SECTION_START)) {
66175
+ const { content: content2, action: action2 } = upsertMarkedBlock(
66176
+ existing,
66177
+ CLAUDE_POINTER_BLOCK,
66178
+ CLAUDE_HAR_SECTION_START,
66179
+ CLAUDE_HAR_SECTION_END
66180
+ );
66181
+ writeFileSafe(dest, content2);
66182
+ return action2;
66183
+ }
66184
+ return "skipped";
66185
+ }
66186
+ const { content, action } = upsertMarkedBlock(
66187
+ existing,
66188
+ CLAUDE_POINTER_BLOCK,
66189
+ CLAUDE_HAR_SECTION_START,
66190
+ CLAUDE_HAR_SECTION_END
66191
+ );
66192
+ writeFileSafe(dest, content);
66193
+ return action;
66194
+ }
66195
+ async function askYesNo2(question, defaultYes = true) {
66196
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
66197
+ return new Promise((resolve47) => {
66198
+ process.stderr.write(`${question} `);
66199
+ rl.once("line", (answer) => {
66200
+ rl.close();
66201
+ const trimmed = answer.trim();
66202
+ if (trimmed === "") {
66203
+ resolve47(defaultYes);
66204
+ return;
66205
+ }
66206
+ resolve47(/^y(es)?$/i.test(trimmed));
66207
+ });
66208
+ });
66209
+ }
66210
+ async function handleInstructionFiles(options) {
66211
+ const { repoPath, mode } = options;
66212
+ const writeAgentsMd = options.writeAgentsMd !== false;
66213
+ const skillsEnabled = options.enabled !== false;
66214
+ const detection = detectInstructionFiles(repoPath);
66215
+ let targets;
66216
+ if (!skillsEnabled) {
66217
+ targets = [];
66218
+ } else if (typeof options.agents === "string") {
66219
+ targets = parseAgentTargets(options.agents);
66220
+ } else {
66221
+ targets = detectAgentTargets(repoPath);
66222
+ }
66223
+ if (skillsEnabled && targets.length === 0 && mode === "init" && typeof options.agents !== "string" && !options.autoYes) {
66224
+ targets = [...AGENT_SKILL_TARGETS];
66225
+ }
66226
+ let plan = buildInstallPlan(detection, targets, {
66227
+ writeAgentsMd,
66228
+ cursorRule: options.cursorRule,
66229
+ skillsEnabled
66230
+ });
66231
+ divider();
66232
+ process.stderr.write(`${formatDetectionReport(detection)}
66233
+
66234
+ `);
66235
+ process.stderr.write(`${formatInstallPlan(plan, detection)}
66236
+ `);
66237
+ divider();
66238
+ const shouldPrompt = !options.autoYes && skillsEnabled && typeof options.agents !== "string" && !(mode === "maintain" && targets.length > 0 && !detection.agentMd);
66239
+ if (shouldPrompt && targets.length > 0) {
66240
+ const accepted = await askYesNo2(
66241
+ `Install HAR agent instructions for: ${targets.join(", ")}? [Y/n]`
66242
+ );
66243
+ if (!accepted) {
66244
+ info("Skipped agent instruction adapters (AGENTS.md will still be updated)");
66245
+ targets = [];
66246
+ plan = buildInstallPlan(detection, targets, {
66247
+ writeAgentsMd,
66248
+ cursorRule: options.cursorRule === true ? true : false,
66249
+ skillsEnabled: false
66250
+ });
66251
+ }
66252
+ }
66253
+ let migratedLegacy = false;
66254
+ let agentsMdAction = null;
66255
+ let claudeMdAction = null;
66256
+ if (writeAgentsMd) {
66257
+ if (detection.agentMd) {
66258
+ migratedLegacy = migrateLegacyAgentMd(repoPath);
66259
+ }
66260
+ agentsMdAction = upsertAgentsMdHarSection(repoPath, {
66261
+ rejectSignificantShrink: options.finalize === true
66262
+ });
66263
+ if (agentsMdAction === "created") {
66264
+ success(`Wrote ${AGENTS_MD}`);
66265
+ } else if (agentsMdAction === "updated" || agentsMdAction === "appended") {
66266
+ info(
66267
+ `${agentsMdAction === "updated" ? "Refreshed" : "Appended"} HAR section in ${AGENTS_MD}`
66268
+ );
66269
+ } else if (agentsMdAction === "skipped" && options.finalize) {
66270
+ warn(
66271
+ `${AGENTS_MD} left unchanged \u2014 project-specific content outside har:agent-environment markers was preserved.`
66272
+ );
66273
+ }
66274
+ } else {
66275
+ agentsMdAction = "skipped";
66276
+ }
66277
+ if (plan.claudeMd) {
66278
+ claudeMdAction = ensureClaudeMdPointer(repoPath);
66279
+ if (claudeMdAction === "created") {
66280
+ success(`Wrote ${CLAUDE_MD} (pointer \u2192 ${AGENTS_MD})`);
66281
+ } else if (claudeMdAction === "updated" || claudeMdAction === "appended") {
66282
+ info(
66283
+ `${claudeMdAction === "updated" ? "Updated" : "Appended"} ${CLAUDE_MD} pointer \u2192 ${AGENTS_MD}`
66284
+ );
66285
+ }
66286
+ } else {
66287
+ claudeMdAction = "skipped";
66288
+ }
66289
+ return {
66290
+ detection,
66291
+ plan,
66292
+ targets,
66293
+ agentsMdAction,
66294
+ migratedLegacy,
66295
+ claudeMdAction
66296
+ };
66297
+ }
66298
+
66299
+ // src/harness/agent-md.ts
66300
+ var AGENTS_MD_PROPOSAL = "AGENTS.md.proposed";
66301
+ var AGENTS_MD_PROPOSAL_META = "AGENTS.md.proposed.meta.json";
66302
+ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
66303
+ var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
66304
+ function readAgentMdProposal(repoPath) {
66305
+ const harnessDir = getHarnessDir(repoPath);
66306
+ const proposalPath = path36.join(harnessDir, AGENTS_MD_PROPOSAL);
66307
+ const metaPath = path36.join(harnessDir, AGENTS_MD_PROPOSAL_META);
66308
+ const legacyProposalPath = path36.join(harnessDir, AGENT_MD_PROPOSAL);
66309
+ const legacyMetaPath = path36.join(harnessDir, AGENT_MD_PROPOSAL_META);
66310
+ const resolvedProposal = fs30.existsSync(proposalPath) ? proposalPath : fs30.existsSync(legacyProposalPath) ? legacyProposalPath : null;
66311
+ if (!resolvedProposal) return null;
66312
+ const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
66313
+ const content = fs30.readFileSync(resolvedProposal, "utf8");
66314
+ let rationale = "";
66315
+ let createdAt = (/* @__PURE__ */ new Date()).toISOString();
66316
+ if (fs30.existsSync(resolvedMeta)) {
66317
+ try {
66318
+ const meta = JSON.parse(fs30.readFileSync(resolvedMeta, "utf8"));
66319
+ rationale = meta.rationale ?? "";
66320
+ createdAt = meta.createdAt ?? createdAt;
66321
+ } catch {
66322
+ rationale = "";
66323
+ }
66324
+ }
66325
+ return { content, rationale, createdAt };
66326
+ }
66327
+ function clearAgentMdProposal(repoPath) {
66328
+ const harnessDir = getHarnessDir(repoPath);
66329
+ for (const file of [
66330
+ AGENTS_MD_PROPOSAL,
66331
+ AGENTS_MD_PROPOSAL_META,
66332
+ AGENT_MD_PROPOSAL,
66333
+ AGENT_MD_PROPOSAL_META
66334
+ ]) {
66335
+ const p = path36.join(harnessDir, file);
66336
+ if (fs30.existsSync(p)) fs30.unlinkSync(p);
66337
+ }
66338
+ }
66339
+ function wouldProposalShrinkExisting(existing, proposal) {
66340
+ const outsideExisting = extractOutsideHarSection(existing);
66341
+ const outsideMerged = extractOutsideHarSection(mergeAgentsMdContent(existing, proposal));
66342
+ const existingLines = outsideExisting.split("\n").filter((l) => l.trim()).length;
66343
+ const mergedLines = outsideMerged.split("\n").filter((l) => l.trim()).length;
66344
+ return existingLines >= 5 && mergedLines < existingLines * 0.9;
66345
+ }
66346
+ function applyAgentMdProposalMerge(repoPath, options = {}) {
66347
+ const proposal = readAgentMdProposal(repoPath);
66348
+ if (!proposal) return false;
66349
+ const agentsMdPath = path36.join(repoPath, AGENTS_MD);
66350
+ if (fs30.existsSync(agentsMdPath)) {
66351
+ const existing = fs30.readFileSync(agentsMdPath, "utf8");
66352
+ if (wouldProposalShrinkExisting(existing, proposal.content)) {
66353
+ 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.`;
66354
+ if (options.rejectSignificantShrink) {
66355
+ throw new AgentsMdShrinkError(message);
66356
+ }
66357
+ warn(message);
66358
+ return false;
66359
+ }
66360
+ writeFileSafe(agentsMdPath, mergeAgentsMdContent(existing, proposal.content));
66361
+ } else {
66362
+ writeFileSafe(agentsMdPath, proposal.content);
66363
+ }
66364
+ clearAgentMdProposal(repoPath);
66365
+ info(`Merged ${AGENTS_MD} proposal into repo root (preserved content outside managed markers)`);
66366
+ return true;
66367
+ }
66368
+ function finalizeAgentsMdInstructionFiles(repoPath) {
66369
+ applyAgentMdProposalMerge(repoPath, { rejectSignificantShrink: true });
66370
+ upsertAgentsMdHarSection(repoPath, { rejectSignificantShrink: true });
66371
+ }
66372
+
66373
+ // src/harness/validator.ts
66374
+ var fs31 = __toESM(require("fs"));
66375
+ var path37 = __toESM(require("path"));
65896
66376
  init_shell();
65897
66377
  init_manifest();
65898
66378
  init_stages();
@@ -65947,22 +66427,22 @@ var SHELL_SCRIPTS = [
65947
66427
  function validateHarness(repoPath) {
65948
66428
  const harnessDir = getHarnessDir(repoPath);
65949
66429
  const issues = [];
65950
- if (!fs29.existsSync(harnessDir)) {
66430
+ if (!fs31.existsSync(harnessDir)) {
65951
66431
  return {
65952
66432
  pass: false,
65953
66433
  issues: [{ file: ".har", message: "Harness directory not found", severity: "error" }]
65954
66434
  };
65955
66435
  }
65956
66436
  for (const file of getRequiredFiles(repoPath)) {
65957
- const filePath = path35.join(harnessDir, file);
65958
- if (!fs29.existsSync(filePath)) {
66437
+ const filePath = path37.join(harnessDir, file);
66438
+ if (!fs31.existsSync(filePath)) {
65959
66439
  issues.push({ file, message: "Required file missing", severity: "error" });
65960
66440
  }
65961
66441
  }
65962
66442
  for (const script of SHELL_SCRIPTS) {
65963
- const scriptPath = path35.join(harnessDir, script);
65964
- if (!fs29.existsSync(scriptPath)) continue;
65965
- const stat = fs29.statSync(scriptPath);
66443
+ const scriptPath = path37.join(harnessDir, script);
66444
+ if (!fs31.existsSync(scriptPath)) continue;
66445
+ const stat = fs31.statSync(scriptPath);
65966
66446
  if (!(stat.mode & 73)) {
65967
66447
  issues.push({ file: script, message: "Script is not executable", severity: "warning" });
65968
66448
  }
@@ -65977,9 +66457,9 @@ function validateHarness(repoPath) {
65977
66457
  }
65978
66458
  const manifest = readManifest(repoPath);
65979
66459
  const profile = manifest?.profile ?? "default";
65980
- const ecosystemPath = path35.join(harnessDir, "ecosystem.agent.template.cjs");
65981
- if (profile !== "cli" && fs29.existsSync(ecosystemPath)) {
65982
- const content = fs29.readFileSync(ecosystemPath, "utf8");
66460
+ const ecosystemPath = path37.join(harnessDir, "ecosystem.agent.template.cjs");
66461
+ if (profile !== "cli" && fs31.existsSync(ecosystemPath)) {
66462
+ const content = fs31.readFileSync(ecosystemPath, "utf8");
65983
66463
  if (!content.includes("module.exports")) {
65984
66464
  issues.push({
65985
66465
  file: "ecosystem.agent.template.cjs",
@@ -65988,9 +66468,9 @@ function validateHarness(repoPath) {
65988
66468
  });
65989
66469
  }
65990
66470
  }
65991
- const harnessEnvPath = path35.join(harnessDir, "harness.env");
65992
- if (fs29.existsSync(harnessEnvPath)) {
65993
- const content = fs29.readFileSync(harnessEnvPath, "utf8");
66471
+ const harnessEnvPath = path37.join(harnessDir, "harness.env");
66472
+ if (fs31.existsSync(harnessEnvPath)) {
66473
+ const content = fs31.readFileSync(harnessEnvPath, "utf8");
65994
66474
  if (content.includes("TODO: set migrate command")) {
65995
66475
  issues.push({ file: "harness.env", message: "Migrate command still has TODO", severity: "warning" });
65996
66476
  }
@@ -65998,17 +66478,17 @@ function validateHarness(repoPath) {
65998
66478
  issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
65999
66479
  }
66000
66480
  }
66001
- const verifyPath = path35.join(harnessDir, "verify.sh");
66002
- if (fs29.existsSync(verifyPath)) {
66003
- const content = fs29.readFileSync(verifyPath, "utf8");
66481
+ const verifyPath = path37.join(harnessDir, "verify.sh");
66482
+ if (fs31.existsSync(verifyPath)) {
66483
+ const content = fs31.readFileSync(verifyPath, "utf8");
66004
66484
  if (content.includes("echo 'TODO:")) {
66005
66485
  issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
66006
66486
  }
66007
66487
  }
66008
- const stagesPath = path35.join(harnessDir, "stages.json");
66009
- if (fs29.existsSync(stagesPath)) {
66488
+ const stagesPath = path37.join(harnessDir, "stages.json");
66489
+ if (fs31.existsSync(stagesPath)) {
66010
66490
  try {
66011
- JSON.parse(fs29.readFileSync(stagesPath, "utf8"));
66491
+ JSON.parse(fs31.readFileSync(stagesPath, "utf8"));
66012
66492
  const registry2 = readStageRegistry(repoPath);
66013
66493
  if (registry2.stages.length === 0) {
66014
66494
  issues.push({ file: "stages.json", message: "No harness stages declared", severity: "warning" });
@@ -66023,9 +66503,9 @@ function validateHarness(repoPath) {
66023
66503
  } else {
66024
66504
  issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
66025
66505
  }
66026
- const readmePath = path35.join(harnessDir, "README.md");
66027
- if (fs29.existsSync(readmePath)) {
66028
- const content = fs29.readFileSync(readmePath, "utf8");
66506
+ const readmePath = path37.join(harnessDir, "README.md");
66507
+ if (fs31.existsSync(readmePath)) {
66508
+ const content = fs31.readFileSync(readmePath, "utf8");
66029
66509
  if (!content.includes(".har")) {
66030
66510
  issues.push({ file: "README.md", message: "README should document .har/ paths", severity: "warning" });
66031
66511
  }
@@ -66039,8 +66519,8 @@ function validateHarness(repoPath) {
66039
66519
  async function smokeTestHarness(repoPath) {
66040
66520
  const harnessDir = getHarnessDir(repoPath);
66041
66521
  const issues = [];
66042
- const setupScript = path35.join(harnessDir, "setup-infra.sh");
66043
- if (fs29.existsSync(setupScript)) {
66522
+ const setupScript = path37.join(harnessDir, "setup-infra.sh");
66523
+ if (fs31.existsSync(setupScript)) {
66044
66524
  const result = run(`bash "${setupScript}"`, { cwd: repoPath });
66045
66525
  if (result.code !== 0) {
66046
66526
  issues.push({
@@ -66055,8 +66535,8 @@ async function smokeTestHarness(repoPath) {
66055
66535
  }
66056
66536
 
66057
66537
  // src/harness/drift.ts
66058
- var fs30 = __toESM(require("fs"));
66059
- var path36 = __toESM(require("path"));
66538
+ var fs32 = __toESM(require("fs"));
66539
+ var path38 = __toESM(require("path"));
66060
66540
  init_env();
66061
66541
  init_manifest();
66062
66542
  init_stages();
@@ -66127,16 +66607,16 @@ function substituteProjectName(content, projectName) {
66127
66607
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
66128
66608
  }
66129
66609
  function listBoilerplateFiles(boilerplateDir) {
66130
- if (!fs30.existsSync(boilerplateDir)) return [];
66131
- return fs30.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
66610
+ if (!fs32.existsSync(boilerplateDir)) return [];
66611
+ return fs32.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
66132
66612
  }
66133
66613
  function compareHarnessToTemplate(repoPath) {
66134
- const resolved = path36.resolve(repoPath);
66614
+ const resolved = path38.resolve(repoPath);
66135
66615
  const manifest = readManifest(resolved);
66136
66616
  const profile = manifest?.profile ?? "default";
66137
66617
  const harnessDir = getHarnessDir(resolved);
66138
- const projectName = path36.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
66139
- const boilerplateDir = path36.join(resolveTemplatesDir(), PROFILE_DIRS2[profile]);
66618
+ const projectName = path38.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
66619
+ const boilerplateDir = path38.join(resolveTemplatesDir(), PROFILE_DIRS2[profile]);
66140
66620
  const templateFiles = listBoilerplateFiles(boilerplateDir);
66141
66621
  const missing = [];
66142
66622
  const checksumMismatch = [];
@@ -66144,17 +66624,17 @@ function compareHarnessToTemplate(repoPath) {
66144
66624
  const unchanged = [];
66145
66625
  for (const file of templateFiles) {
66146
66626
  const harnessFile = harnessFileForTemplate(file);
66147
- const templatePath = path36.join(boilerplateDir, file);
66148
- const harnessPath = path36.join(harnessDir, harnessFile);
66149
- let templateContent = fs30.readFileSync(templatePath, "utf8");
66627
+ const templatePath = path38.join(boilerplateDir, file);
66628
+ const harnessPath = path38.join(harnessDir, harnessFile);
66629
+ let templateContent = fs32.readFileSync(templatePath, "utf8");
66150
66630
  if (file === "harness.env") {
66151
66631
  templateContent = substituteProjectName(templateContent, projectName);
66152
66632
  }
66153
- if (!fs30.existsSync(harnessPath)) {
66633
+ if (!fs32.existsSync(harnessPath)) {
66154
66634
  missing.push(harnessFile);
66155
66635
  continue;
66156
66636
  }
66157
- const harnessChecksum = computeFileChecksum(fs30.readFileSync(harnessPath, "utf8"));
66637
+ const harnessChecksum = computeFileChecksum(fs32.readFileSync(harnessPath, "utf8"));
66158
66638
  const templateChecksum = computeFileChecksum(templateContent);
66159
66639
  if (harnessChecksum === templateChecksum) {
66160
66640
  unchanged.push(harnessFile);
@@ -66162,10 +66642,10 @@ function compareHarnessToTemplate(repoPath) {
66162
66642
  checksumMismatch.push(harnessFile);
66163
66643
  }
66164
66644
  }
66165
- if (fs30.existsSync(harnessDir)) {
66166
- for (const file of fs30.readdirSync(harnessDir)) {
66167
- const full = path36.join(harnessDir, file);
66168
- if (!fs30.statSync(full).isFile()) continue;
66645
+ if (fs32.existsSync(harnessDir)) {
66646
+ for (const file of fs32.readdirSync(harnessDir)) {
66647
+ const full = path38.join(harnessDir, file);
66648
+ if (!fs32.statSync(full).isFile()) continue;
66169
66649
  if (file === "manifest.json" || file.startsWith("ADAPT-PROMPT")) continue;
66170
66650
  if (profile === "cli" && CLI_EXPECTED_ABSENT.has(file)) {
66171
66651
  extra.push(file);
@@ -66196,29 +66676,29 @@ function compareHarnessToTemplate(repoPath) {
66196
66676
  }
66197
66677
 
66198
66678
  // src/harness/maintain-bundle.ts
66199
- var fs35 = __toESM(require("fs"));
66679
+ var fs36 = __toESM(require("fs"));
66200
66680
  var os14 = __toESM(require("os"));
66201
- var path40 = __toESM(require("path"));
66681
+ var path41 = __toESM(require("path"));
66202
66682
  init_file_ops();
66203
66683
  init_shell();
66204
66684
  init_manifest();
66205
66685
 
66206
66686
  // src/harness/plugin-drift.ts
66207
- var fs33 = __toESM(require("fs"));
66208
- var path38 = __toESM(require("path"));
66687
+ var fs35 = __toESM(require("fs"));
66688
+ var path40 = __toESM(require("path"));
66209
66689
  init_manifest();
66210
66690
 
66211
66691
  // src/harness/plugins.ts
66212
- var fs32 = __toESM(require("fs"));
66213
- var path37 = __toESM(require("path"));
66692
+ var fs34 = __toESM(require("fs"));
66693
+ var path39 = __toESM(require("path"));
66214
66694
  init_zod();
66215
66695
  init_logging();
66216
66696
 
66217
66697
  // src/harness/parser.ts
66218
- var fs31 = __toESM(require("fs"));
66698
+ var fs33 = __toESM(require("fs"));
66219
66699
  init_manifest();
66220
66700
  function harnessExists(repoPath) {
66221
- return fs31.existsSync(`${repoPath}/.har/setup-infra.sh`);
66701
+ return fs33.existsSync(`${repoPath}/.har/setup-infra.sh`);
66222
66702
  }
66223
66703
 
66224
66704
  // src/harness/plugins.ts
@@ -66243,16 +66723,16 @@ var PluginManifestSchema = external_exports.object({
66243
66723
  docsPath: external_exports.string().min(1)
66244
66724
  });
66245
66725
  function resolvePluginDir(pluginId) {
66246
- const dir = path37.join(resolveTemplatesDir(), "plugins", pluginId);
66247
- if (!fs32.existsSync(dir)) {
66726
+ const dir = path39.join(resolveTemplatesDir(), "plugins", pluginId);
66727
+ if (!fs34.existsSync(dir)) {
66248
66728
  throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
66249
66729
  }
66250
66730
  return dir;
66251
66731
  }
66252
66732
  function readPluginManifest(pluginId) {
66253
- const manifestPath = path37.join(resolvePluginDir(pluginId), "template.manifest.json");
66733
+ const manifestPath = path39.join(resolvePluginDir(pluginId), "template.manifest.json");
66254
66734
  const parsed = PluginManifestSchema.safeParse(
66255
- JSON.parse(fs32.readFileSync(manifestPath, "utf8"))
66735
+ JSON.parse(fs34.readFileSync(manifestPath, "utf8"))
66256
66736
  );
66257
66737
  if (!parsed.success) {
66258
66738
  throw new Error(`Invalid plugin manifest for ${pluginId}: ${parsed.error.message}`);
@@ -66263,40 +66743,40 @@ function readPluginManifest(pluginId) {
66263
66743
  return parsed.data;
66264
66744
  }
66265
66745
  function ensureParentDir(filePath) {
66266
- const parent = path37.dirname(filePath);
66267
- if (!fs32.existsSync(parent)) {
66268
- fs32.mkdirSync(parent, { recursive: true });
66746
+ const parent = path39.dirname(filePath);
66747
+ if (!fs34.existsSync(parent)) {
66748
+ fs34.mkdirSync(parent, { recursive: true });
66269
66749
  }
66270
66750
  }
66271
66751
  function copyPluginFile(pluginDir, file, repoPath, force) {
66272
- const srcPath = path37.join(pluginDir, file.src);
66273
- const destPath = path37.join(repoPath, file.dest);
66274
- if (!fs32.existsSync(srcPath)) {
66752
+ const srcPath = path39.join(pluginDir, file.src);
66753
+ const destPath = path39.join(repoPath, file.dest);
66754
+ if (!fs34.existsSync(srcPath)) {
66275
66755
  throw new Error(`Plugin file missing: ${file.src}`);
66276
66756
  }
66277
- if (fs32.existsSync(destPath) && !force) {
66757
+ if (fs34.existsSync(destPath) && !force) {
66278
66758
  throw new Error(
66279
66759
  `File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
66280
66760
  );
66281
66761
  }
66282
66762
  ensureParentDir(destPath);
66283
- fs32.copyFileSync(srcPath, destPath);
66763
+ fs34.copyFileSync(srcPath, destPath);
66284
66764
  if (file.executable) {
66285
- fs32.chmodSync(destPath, 493);
66765
+ fs34.chmodSync(destPath, 493);
66286
66766
  }
66287
66767
  return { written: true, path: file.dest };
66288
66768
  }
66289
66769
  function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
66290
- const packagePath = path37.join(repoPath, "package.json");
66291
- if (!fs32.existsSync(packagePath)) {
66770
+ const packagePath = path39.join(repoPath, "package.json");
66771
+ if (!fs34.existsSync(packagePath)) {
66292
66772
  throw new Error("No package.json in repo root. Add one before applying this plugin.");
66293
66773
  }
66294
- const fragmentPath = path37.join(pluginDir, fragmentRelPath);
66295
- if (!fs32.existsSync(fragmentPath)) {
66774
+ const fragmentPath = path39.join(pluginDir, fragmentRelPath);
66775
+ if (!fs34.existsSync(fragmentPath)) {
66296
66776
  throw new Error(`Package fragment missing: ${fragmentRelPath}`);
66297
66777
  }
66298
- const pkg = JSON.parse(fs32.readFileSync(packagePath, "utf8"));
66299
- const fragment = JSON.parse(fs32.readFileSync(fragmentPath, "utf8"));
66778
+ const pkg = JSON.parse(fs34.readFileSync(packagePath, "utf8"));
66779
+ const fragment = JSON.parse(fs34.readFileSync(fragmentPath, "utf8"));
66300
66780
  for (const section of ["scripts", "devDependencies"]) {
66301
66781
  const existing = pkg[section] ?? {};
66302
66782
  const incoming = fragment[section] ?? {};
@@ -66309,7 +66789,7 @@ function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
66309
66789
  }
66310
66790
  pkg[section] = existing;
66311
66791
  }
66312
- fs32.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
66792
+ fs34.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
66313
66793
  }
66314
66794
  function patchStageRegistry(repoPath, manifest, force) {
66315
66795
  const registry2 = readStageRegistry(repoPath);
@@ -66349,8 +66829,8 @@ function assertHarnessPresent(repoPath) {
66349
66829
  }
66350
66830
  function assertStageNotPresent(repoPath, stageId, force) {
66351
66831
  if (force) return;
66352
- const scriptPath = path37.join(repoPath, ".har", "stages", `${stageId}.sh`);
66353
- if (fs32.existsSync(scriptPath)) {
66832
+ const scriptPath = path39.join(repoPath, ".har", "stages", `${stageId}.sh`);
66833
+ if (fs34.existsSync(scriptPath)) {
66354
66834
  throw new Error(
66355
66835
  `Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
66356
66836
  );
@@ -66363,7 +66843,7 @@ function assertStageNotPresent(repoPath, stageId, force) {
66363
66843
  }
66364
66844
  }
66365
66845
  function applyPlugin(repoPath, pluginId, options = {}) {
66366
- const resolved = path37.resolve(repoPath);
66846
+ const resolved = path39.resolve(repoPath);
66367
66847
  const force = options.force ?? false;
66368
66848
  const warnings = [];
66369
66849
  const filesWritten = [];
@@ -66382,7 +66862,7 @@ function applyPlugin(repoPath, pluginId, options = {}) {
66382
66862
  if (file.skipFlag === "skipCi" && options.skipCi) {
66383
66863
  continue;
66384
66864
  }
66385
- if (fs32.existsSync(path37.join(resolved, file.dest)) && !force) {
66865
+ if (fs34.existsSync(path39.join(resolved, file.dest)) && !force) {
66386
66866
  warnings.push(`Skipped optional file (exists): ${file.dest}`);
66387
66867
  continue;
66388
66868
  }
@@ -66417,18 +66897,18 @@ function applyPlugin(repoPath, pluginId, options = {}) {
66417
66897
  };
66418
66898
  }
66419
66899
  function listPluginIds() {
66420
- const root = path37.join(resolveTemplatesDir(), "plugins");
66421
- if (!fs32.existsSync(root)) return [...PLUGIN_IDS];
66422
- return fs32.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
66900
+ const root = path39.join(resolveTemplatesDir(), "plugins");
66901
+ if (!fs34.existsSync(root)) return [...PLUGIN_IDS];
66902
+ return fs34.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
66423
66903
  }
66424
66904
 
66425
66905
  // src/harness/plugin-drift.ts
66426
66906
  init_stages();
66427
66907
  var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
66428
66908
  function detectInstalledPlugins(repoPath) {
66429
- const resolved = path38.resolve(repoPath);
66430
- const registryPath = path38.join(resolved, ".har", "stages.json");
66431
- if (!fs33.existsSync(registryPath)) return [];
66909
+ const resolved = path40.resolve(repoPath);
66910
+ const registryPath = path40.join(resolved, ".har", "stages.json");
66911
+ if (!fs35.existsSync(registryPath)) return [];
66432
66912
  const registry2 = readStageRegistry(resolved);
66433
66913
  const stageIds = new Set(registry2.stages.map((stage) => stage.id));
66434
66914
  const installed = [];
@@ -66441,17 +66921,17 @@ function detectInstalledPlugins(repoPath) {
66441
66921
  return installed;
66442
66922
  }
66443
66923
  function pluginTemplatePath(pluginId, srcRel) {
66444
- return path38.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
66924
+ return path40.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
66445
66925
  }
66446
66926
  function readBundledPluginFile(pluginId, srcRel) {
66447
- return fs33.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
66927
+ return fs35.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
66448
66928
  }
66449
66929
  function listPluginDestPaths(pluginId, repoPath) {
66450
66930
  const manifest = readPluginManifest(pluginId);
66451
66931
  const paths = manifest.files.map((file) => file.dest);
66452
66932
  if (manifest.optionalFiles) {
66453
66933
  for (const file of manifest.optionalFiles) {
66454
- if (fs33.existsSync(path38.join(repoPath, file.dest))) {
66934
+ if (fs35.existsSync(path40.join(repoPath, file.dest))) {
66455
66935
  paths.push(file.dest);
66456
66936
  }
66457
66937
  }
@@ -66510,9 +66990,9 @@ function readTemplatePluginFile(pluginId, dest) {
66510
66990
  return null;
66511
66991
  }
66512
66992
  function readInstalledPluginFile(repoPath, pluginId, dest) {
66513
- const installedPath = path38.join(path38.resolve(repoPath), dest);
66514
- if (!fs33.existsSync(installedPath)) return null;
66515
- const content = fs33.readFileSync(installedPath, "utf8");
66993
+ const installedPath = path40.join(path40.resolve(repoPath), dest);
66994
+ if (!fs35.existsSync(installedPath)) return null;
66995
+ const content = fs35.readFileSync(installedPath, "utf8");
66516
66996
  const manifest = readPluginManifest(pluginId);
66517
66997
  const fragmentRel = manifest.merge?.[dest];
66518
66998
  if (fragmentRel) {
@@ -66531,7 +67011,7 @@ function pluginActionHint(pluginId, dest, kind) {
66531
67011
  }
66532
67012
  function comparePluginToTemplate(repoPath, pluginId) {
66533
67013
  const manifest = readPluginManifest(pluginId);
66534
- const resolved = path38.resolve(repoPath);
67014
+ const resolved = path40.resolve(repoPath);
66535
67015
  const destPaths = listPluginDestPaths(pluginId, resolved);
66536
67016
  const missing = [];
66537
67017
  const checksumMismatch = [];
@@ -66546,8 +67026,8 @@ function comparePluginToTemplate(repoPath, pluginId) {
66546
67026
  }
66547
67027
  if (dest === "package.json") {
66548
67028
  const fragmentRel = manifest.merge?.[dest];
66549
- const installedPath = path38.join(resolved, dest);
66550
- const installedRaw = fs33.readFileSync(installedPath, "utf8");
67029
+ const installedPath = path40.join(resolved, dest);
67030
+ const installedRaw = fs35.readFileSync(installedPath, "utf8");
66551
67031
  if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
66552
67032
  unchanged.push(dest);
66553
67033
  } else if (computeFileChecksum(installedContent) === computeFileChecksum(templateContent)) {
@@ -66605,293 +67085,6 @@ function buildPluginDriftActions(repoPath, pluginDrift) {
66605
67085
  );
66606
67086
  }
66607
67087
 
66608
- // src/harness/instruction-files.ts
66609
- var fs34 = __toESM(require("fs"));
66610
- var os13 = __toESM(require("os"));
66611
- var path39 = __toESM(require("path"));
66612
- var readline2 = __toESM(require("readline"));
66613
- init_file_ops();
66614
- init_logging();
66615
- var AGENTS_MD = "AGENTS.md";
66616
- var LEGACY_AGENT_MD = "AGENT.md";
66617
- var CLAUDE_MD = "CLAUDE.md";
66618
- var HAR_SECTION_START = "<!-- har:agent-environment:start -->";
66619
- var HAR_SECTION_END = "<!-- har:agent-environment:end -->";
66620
- var CLAUDE_HAR_SECTION_START = "<!-- har:claude-pointer:start -->";
66621
- var CLAUDE_HAR_SECTION_END = "<!-- har:claude-pointer:end -->";
66622
- function escapeRegExp(value) {
66623
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
66624
- }
66625
- function detectInstructionFiles(repoPath) {
66626
- return {
66627
- agentsMd: fs34.existsSync(path39.join(repoPath, AGENTS_MD)),
66628
- agentMd: fs34.existsSync(path39.join(repoPath, LEGACY_AGENT_MD)),
66629
- claudeMd: fs34.existsSync(path39.join(repoPath, CLAUDE_MD)),
66630
- cursorDir: fs34.existsSync(path39.join(repoPath, ".cursor")),
66631
- claudeDir: fs34.existsSync(path39.join(repoPath, ".claude")),
66632
- codexHome: fs34.existsSync(path39.join(os13.homedir(), ".codex"))
66633
- };
66634
- }
66635
- function formatDetectionReport(detection) {
66636
- const lines2 = ["Detected:"];
66637
- lines2.push(` - ${AGENTS_MD} (${detection.agentsMd ? "exists" : "missing"})`);
66638
- if (detection.agentMd) {
66639
- lines2.push(` - ${LEGACY_AGENT_MD} (legacy \u2014 will migrate into ${AGENTS_MD})`);
66640
- }
66641
- lines2.push(` - ${CLAUDE_MD} (${detection.claudeMd ? "exists" : "missing"})`);
66642
- lines2.push(` - .cursor/ (${detection.cursorDir ? "exists" : "missing"})`);
66643
- lines2.push(` - .claude/ (${detection.claudeDir ? "exists" : "missing"})`);
66644
- lines2.push(` - ~/.codex (${detection.codexHome ? "exists" : "missing"})`);
66645
- return lines2.join("\n");
66646
- }
66647
- function buildInstallPlan(detection, targets, options = {}) {
66648
- const writeAgentsMd = options.writeAgentsMd !== false;
66649
- const skillsEnabled = options.skillsEnabled !== false;
66650
- const cursorExplicit = options.cursorRule;
66651
- const wantsCursor = cursorExplicit === true || cursorExplicit !== false && (targets.includes("cursor") || detection.cursorDir);
66652
- return {
66653
- agentsMd: writeAgentsMd,
66654
- migrateLegacyAgentMd: writeAgentsMd && detection.agentMd,
66655
- claudeMd: skillsEnabled && targets.includes("claude"),
66656
- cursorRule: wantsCursor,
66657
- skills: skillsEnabled ? targets : []
66658
- };
66659
- }
66660
- function formatInstallPlan(plan, detection) {
66661
- const mark = (on) => on ? "[x]" : "[ ]";
66662
- const lines2 = ["After you confirm, HAR will:"];
66663
- const agentsAction = detection.agentsMd ? `Update ${AGENTS_MD} \u2014 refresh HAR / agent environment section` : `Create ${AGENTS_MD} \u2014 shared HAR workflow (Codex + cross-tool)`;
66664
- lines2.push(` ${mark(plan.agentsMd)} ${agentsAction}`);
66665
- if (plan.migrateLegacyAgentMd) {
66666
- lines2.push(` ${mark(true)} Migrate ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD}, then remove legacy file`);
66667
- }
66668
- lines2.push(
66669
- ` ${mark(plan.claudeMd)} Claude \u2014 ensure ${CLAUDE_MD} points at ${AGENTS_MD}; install .claude/skills if confirmed`
66670
- );
66671
- lines2.push(
66672
- ` ${mark(plan.cursorRule)} Cursor \u2014 install/refresh .cursor/rules/har-workflow.mdc + commands if confirmed`
66673
- );
66674
- lines2.push(
66675
- ` ${mark(plan.skills.includes("codex"))} Codex \u2014 global ~/.codex/prompts (skills); project contract is ${AGENTS_MD}`
66676
- );
66677
- return lines2.join("\n");
66678
- }
66679
- function loadHarAgentsSectionFromTemplate() {
66680
- const templatePath = resolveTemplateFile("AGENTS.md.template");
66681
- if (!templatePath) {
66682
- throw new Error("AGENTS.md.template not found. Run npm run build.");
66683
- }
66684
- const content = fs34.readFileSync(templatePath, "utf8");
66685
- const start = content.indexOf(HAR_SECTION_START);
66686
- const end = content.indexOf(HAR_SECTION_END);
66687
- if (start === -1 || end === -1 || end < start) {
66688
- throw new Error("AGENTS.md.template is missing har:agent-environment markers.");
66689
- }
66690
- return content.slice(start, end + HAR_SECTION_END.length);
66691
- }
66692
- function loadAgentsMdTemplate() {
66693
- const templatePath = resolveTemplateFile("AGENTS.md.template");
66694
- if (!templatePath) {
66695
- throw new Error("AGENTS.md.template not found. Run npm run build.");
66696
- }
66697
- return fs34.readFileSync(templatePath, "utf8");
66698
- }
66699
- function upsertMarkedBlock(content, block, startMarker, endMarker) {
66700
- if (content.includes(startMarker)) {
66701
- const pattern = new RegExp(
66702
- `${escapeRegExp(startMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`
66703
- );
66704
- return { content: content.replace(pattern, block), action: "updated" };
66705
- }
66706
- const suffix = content.endsWith("\n") ? "" : "\n";
66707
- return { content: `${content}${suffix}
66708
- ${block}
66709
- `, action: "appended" };
66710
- }
66711
- function upsertAgentsMdHarSection(repoPath) {
66712
- const dest = path39.join(repoPath, AGENTS_MD);
66713
- const section = loadHarAgentsSectionFromTemplate();
66714
- if (!fs34.existsSync(dest)) {
66715
- writeFileSafe(dest, loadAgentsMdTemplate());
66716
- return "created";
66717
- }
66718
- const existing = fs34.readFileSync(dest, "utf8");
66719
- const { content, action } = upsertMarkedBlock(
66720
- existing,
66721
- section,
66722
- HAR_SECTION_START,
66723
- HAR_SECTION_END
66724
- );
66725
- writeFileSafe(dest, content);
66726
- return action;
66727
- }
66728
- function migrateLegacyAgentMd(repoPath) {
66729
- const legacyPath = path39.join(repoPath, LEGACY_AGENT_MD);
66730
- const agentsPath = path39.join(repoPath, AGENTS_MD);
66731
- if (!fs34.existsSync(legacyPath)) return false;
66732
- const legacy = fs34.readFileSync(legacyPath, "utf8");
66733
- if (!fs34.existsSync(agentsPath)) {
66734
- writeFileSafe(agentsPath, legacy);
66735
- upsertAgentsMdHarSection(repoPath);
66736
- } else {
66737
- upsertAgentsMdHarSection(repoPath);
66738
- }
66739
- fs34.unlinkSync(legacyPath);
66740
- info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
66741
- return true;
66742
- }
66743
- function loadClaudeMdTemplate(projectName) {
66744
- const templatePath = resolveTemplateFile("CLAUDE.md.template");
66745
- if (!templatePath) {
66746
- throw new Error("CLAUDE.md.template not found. Run npm run build.");
66747
- }
66748
- const displayName = projectName.replace(/_/g, " ");
66749
- return fs34.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
66750
- }
66751
- function isThinClaudePointer(content) {
66752
- const trimmed = content.trim();
66753
- if (trimmed.length > 600) return false;
66754
- return /AGENTS\.md|AGENT\.md/.test(trimmed) && (trimmed.includes(".har/README.md") || trimmed.includes("har-workflow"));
66755
- }
66756
- var CLAUDE_POINTER_BLOCK = `${CLAUDE_HAR_SECTION_START}
66757
- ## HAR
66758
-
66759
- This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
66760
- [\`.har/README.md\`](./.har/README.md) before making changes.
66761
- ${CLAUDE_HAR_SECTION_END}`;
66762
- function ensureClaudeMdPointer(repoPath, options = {}) {
66763
- const dest = path39.join(repoPath, CLAUDE_MD);
66764
- const projectName = path39.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66765
- const thin = loadClaudeMdTemplate(projectName);
66766
- if (!fs34.existsSync(dest)) {
66767
- writeFileSafe(dest, thin);
66768
- return "created";
66769
- }
66770
- const existing = fs34.readFileSync(dest, "utf8");
66771
- if (isThinClaudePointer(existing) || options.force) {
66772
- writeFileSafe(dest, thin);
66773
- return "updated";
66774
- }
66775
- if (existing.includes(CLAUDE_HAR_SECTION_START) || /\[AGENTS\.md\]/.test(existing)) {
66776
- if (existing.includes(CLAUDE_HAR_SECTION_START)) {
66777
- const { content: content2, action: action2 } = upsertMarkedBlock(
66778
- existing,
66779
- CLAUDE_POINTER_BLOCK,
66780
- CLAUDE_HAR_SECTION_START,
66781
- CLAUDE_HAR_SECTION_END
66782
- );
66783
- writeFileSafe(dest, content2);
66784
- return action2;
66785
- }
66786
- return "skipped";
66787
- }
66788
- const { content, action } = upsertMarkedBlock(
66789
- existing,
66790
- CLAUDE_POINTER_BLOCK,
66791
- CLAUDE_HAR_SECTION_START,
66792
- CLAUDE_HAR_SECTION_END
66793
- );
66794
- writeFileSafe(dest, content);
66795
- return action;
66796
- }
66797
- async function askYesNo2(question, defaultYes = true) {
66798
- const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
66799
- return new Promise((resolve47) => {
66800
- process.stderr.write(`${question} `);
66801
- rl.once("line", (answer) => {
66802
- rl.close();
66803
- const trimmed = answer.trim();
66804
- if (trimmed === "") {
66805
- resolve47(defaultYes);
66806
- return;
66807
- }
66808
- resolve47(/^y(es)?$/i.test(trimmed));
66809
- });
66810
- });
66811
- }
66812
- async function handleInstructionFiles(options) {
66813
- const { repoPath, mode } = options;
66814
- const writeAgentsMd = options.writeAgentsMd !== false;
66815
- const skillsEnabled = options.enabled !== false;
66816
- const detection = detectInstructionFiles(repoPath);
66817
- let targets;
66818
- if (!skillsEnabled) {
66819
- targets = [];
66820
- } else if (typeof options.agents === "string") {
66821
- targets = parseAgentTargets(options.agents);
66822
- } else {
66823
- targets = detectAgentTargets(repoPath);
66824
- }
66825
- if (skillsEnabled && targets.length === 0 && mode === "init" && typeof options.agents !== "string" && !options.autoYes) {
66826
- targets = [...AGENT_SKILL_TARGETS];
66827
- }
66828
- let plan = buildInstallPlan(detection, targets, {
66829
- writeAgentsMd,
66830
- cursorRule: options.cursorRule,
66831
- skillsEnabled
66832
- });
66833
- divider();
66834
- process.stderr.write(`${formatDetectionReport(detection)}
66835
-
66836
- `);
66837
- process.stderr.write(`${formatInstallPlan(plan, detection)}
66838
- `);
66839
- divider();
66840
- const shouldPrompt = !options.autoYes && skillsEnabled && typeof options.agents !== "string" && !(mode === "maintain" && targets.length > 0 && !detection.agentMd);
66841
- if (shouldPrompt && targets.length > 0) {
66842
- const accepted = await askYesNo2(
66843
- `Install HAR agent instructions for: ${targets.join(", ")}? [Y/n]`
66844
- );
66845
- if (!accepted) {
66846
- info("Skipped agent instruction adapters (AGENTS.md will still be updated)");
66847
- targets = [];
66848
- plan = buildInstallPlan(detection, targets, {
66849
- writeAgentsMd,
66850
- cursorRule: options.cursorRule === true ? true : false,
66851
- skillsEnabled: false
66852
- });
66853
- }
66854
- }
66855
- let migratedLegacy = false;
66856
- let agentsMdAction = null;
66857
- let claudeMdAction = null;
66858
- if (writeAgentsMd) {
66859
- if (detection.agentMd) {
66860
- migratedLegacy = migrateLegacyAgentMd(repoPath);
66861
- }
66862
- agentsMdAction = upsertAgentsMdHarSection(repoPath);
66863
- if (agentsMdAction === "created") {
66864
- success(`Wrote ${AGENTS_MD}`);
66865
- } else if (agentsMdAction === "updated" || agentsMdAction === "appended") {
66866
- info(
66867
- `${agentsMdAction === "updated" ? "Refreshed" : "Appended"} HAR section in ${AGENTS_MD}`
66868
- );
66869
- }
66870
- } else {
66871
- agentsMdAction = "skipped";
66872
- }
66873
- if (plan.claudeMd) {
66874
- claudeMdAction = ensureClaudeMdPointer(repoPath);
66875
- if (claudeMdAction === "created") {
66876
- success(`Wrote ${CLAUDE_MD} (pointer \u2192 ${AGENTS_MD})`);
66877
- } else if (claudeMdAction === "updated" || claudeMdAction === "appended") {
66878
- info(
66879
- `${claudeMdAction === "updated" ? "Updated" : "Appended"} ${CLAUDE_MD} pointer \u2192 ${AGENTS_MD}`
66880
- );
66881
- }
66882
- } else {
66883
- claudeMdAction = "skipped";
66884
- }
66885
- return {
66886
- detection,
66887
- plan,
66888
- targets,
66889
- agentsMdAction,
66890
- migratedLegacy,
66891
- claudeMdAction
66892
- };
66893
- }
66894
-
66895
67088
  // src/harness/maintain-bundle.ts
66896
67089
  var MAINTAIN_DIR = "maintain";
66897
67090
  var PROFILE_DIRS3 = {
@@ -66903,14 +67096,14 @@ function substituteProjectName2(content, projectName) {
66903
67096
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
66904
67097
  }
66905
67098
  function projectNameFromRepo(repoPath) {
66906
- return path40.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
67099
+ return path41.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66907
67100
  }
66908
67101
  function boilerplateDirForProfile(profile) {
66909
- return path40.join(resolveTemplatesDir(), PROFILE_DIRS3[profile]);
67102
+ return path41.join(resolveTemplatesDir(), PROFILE_DIRS3[profile]);
66910
67103
  }
66911
67104
  function readBundledTemplateContent(repoPath, profile, file) {
66912
- const templatePath = path40.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
66913
- let content = fs35.readFileSync(templatePath, "utf8");
67105
+ const templatePath = path41.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
67106
+ let content = fs36.readFileSync(templatePath, "utf8");
66914
67107
  if (file === "harness.env") {
66915
67108
  content = substituteProjectName2(content, projectNameFromRepo(repoPath));
66916
67109
  }
@@ -66941,12 +67134,12 @@ function actionHint(file, kind) {
66941
67134
  return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
66942
67135
  }
66943
67136
  function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
66944
- const tmpDir = fs35.mkdtempSync(path40.join(os14.tmpdir(), "har-maintain-diff-"));
67137
+ const tmpDir = fs36.mkdtempSync(path41.join(os14.tmpdir(), "har-maintain-diff-"));
66945
67138
  try {
66946
- const installedPath = path40.join(tmpDir, "installed");
66947
- const templatePath = path40.join(tmpDir, "template");
66948
- fs35.writeFileSync(installedPath, installedContent);
66949
- fs35.writeFileSync(templatePath, templateContent);
67139
+ const installedPath = path41.join(tmpDir, "installed");
67140
+ const templatePath = path41.join(tmpDir, "template");
67141
+ fs36.writeFileSync(installedPath, installedContent);
67142
+ fs36.writeFileSync(templatePath, templateContent);
66950
67143
  const result = run(`diff -u "${installedPath}" "${templatePath}"`);
66951
67144
  const body = result.stdout.trim();
66952
67145
  if (!body) return "";
@@ -66955,7 +67148,7 @@ function createUnifiedDiff(installedContent, templateContent, installedLabel, te
66955
67148
  ${body.split("\n").slice(2).join("\n")}
66956
67149
  `;
66957
67150
  } finally {
66958
- fs35.rmSync(tmpDir, { recursive: true, force: true });
67151
+ fs36.rmSync(tmpDir, { recursive: true, force: true });
66959
67152
  }
66960
67153
  }
66961
67154
  function buildActions(repoPath, profile, drift) {
@@ -66970,7 +67163,7 @@ function buildActions(repoPath, profile, drift) {
66970
67163
  });
66971
67164
  }
66972
67165
  for (const file of drift.checksumMismatch) {
66973
- const installedPath = path40.join(harnessDir, file);
67166
+ const installedPath = path41.join(harnessDir, file);
66974
67167
  const installedRel = `maintain/installed/${file}`;
66975
67168
  const templateRel = `maintain/templates/${file}`;
66976
67169
  const diffRel = `maintain/diffs/${file}.diff`;
@@ -66978,7 +67171,7 @@ function buildActions(repoPath, profile, drift) {
66978
67171
  file,
66979
67172
  kind: "drift",
66980
67173
  template: templateRel,
66981
- installed: fs35.existsSync(installedPath) ? installedRel : void 0,
67174
+ installed: fs36.existsSync(installedPath) ? installedRel : void 0,
66982
67175
  diff: diffRel,
66983
67176
  hint: actionHint(file, "drift")
66984
67177
  });
@@ -67097,6 +67290,10 @@ function buildReadme(report) {
67097
67290
  lines2.push("", "## Agent instruction files (generator 0.5.0)", "");
67098
67291
  lines2.push(
67099
67292
  "Repo-root agent docs are **outside** `.har/` checksum drift. Apply while adapting:",
67293
+ "",
67294
+ "**Merge contract:** `har env maintain --finalize` refreshes only the content between",
67295
+ "`<!-- har:agent-environment:start/end -->` in `AGENTS.md`. Custom `## Project` sections and",
67296
+ "other guidance **outside** those markers must survive finalize \u2014 relocate them if needed.",
67100
67297
  ""
67101
67298
  );
67102
67299
  for (const note of report.instructionFiles) {
@@ -67126,28 +67323,28 @@ function buildReadme(report) {
67126
67323
  }
67127
67324
  function writeBundleArtifacts(repoPath, profile, drift, report) {
67128
67325
  const harnessDir = getHarnessDir(repoPath);
67129
- const bundleDir = path40.join(harnessDir, MAINTAIN_DIR);
67130
- if (fs35.existsSync(bundleDir)) {
67131
- fs35.rmSync(bundleDir, { recursive: true, force: true });
67326
+ const bundleDir = path41.join(harnessDir, MAINTAIN_DIR);
67327
+ if (fs36.existsSync(bundleDir)) {
67328
+ fs36.rmSync(bundleDir, { recursive: true, force: true });
67132
67329
  }
67133
67330
  const dirs = [
67134
67331
  bundleDir,
67135
- path40.join(bundleDir, "templates"),
67136
- path40.join(bundleDir, "installed"),
67137
- path40.join(bundleDir, "diffs"),
67138
- path40.join(bundleDir, "stale")
67332
+ path41.join(bundleDir, "templates"),
67333
+ path41.join(bundleDir, "installed"),
67334
+ path41.join(bundleDir, "diffs"),
67335
+ path41.join(bundleDir, "stale")
67139
67336
  ];
67140
67337
  for (const dir of dirs) {
67141
- fs35.mkdirSync(dir, { recursive: true });
67338
+ fs36.mkdirSync(dir, { recursive: true });
67142
67339
  }
67143
67340
  const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
67144
67341
  for (const file of affectedFiles) {
67145
67342
  const templateContent = readBundledTemplateContent(repoPath, profile, file);
67146
- writeFileSafe(path40.join(bundleDir, "templates", file), templateContent);
67147
- const harnessPath = path40.join(harnessDir, file);
67148
- if (fs35.existsSync(harnessPath)) {
67149
- const installedContent = fs35.readFileSync(harnessPath, "utf8");
67150
- writeFileSafe(path40.join(bundleDir, "installed", file), installedContent);
67343
+ writeFileSafe(path41.join(bundleDir, "templates", file), templateContent);
67344
+ const harnessPath = path41.join(harnessDir, file);
67345
+ if (fs36.existsSync(harnessPath)) {
67346
+ const installedContent = fs36.readFileSync(harnessPath, "utf8");
67347
+ writeFileSafe(path41.join(bundleDir, "installed", file), installedContent);
67151
67348
  const diff = createUnifiedDiff(
67152
67349
  installedContent,
67153
67350
  templateContent,
@@ -67155,14 +67352,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
67155
67352
  `templates/${file}`
67156
67353
  );
67157
67354
  if (diff) {
67158
- writeFileSafe(path40.join(bundleDir, "diffs", `${file}.diff`), diff);
67355
+ writeFileSafe(path41.join(bundleDir, "diffs", `${file}.diff`), diff);
67159
67356
  }
67160
67357
  }
67161
67358
  }
67162
- writeFileSafe(path40.join(bundleDir, "README.md"), buildReadme(report));
67163
- writeFileSafe(path40.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
67359
+ writeFileSafe(path41.join(bundleDir, "README.md"), buildReadme(report));
67360
+ writeFileSafe(path41.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
67164
67361
  writeFileSafe(
67165
- path40.join(bundleDir, "validation.json"),
67362
+ path41.join(bundleDir, "validation.json"),
67166
67363
  JSON.stringify(report.validation, null, 2) + "\n"
67167
67364
  );
67168
67365
  if (report.stale.length > 0) {
@@ -67174,34 +67371,34 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
67174
67371
  ...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
67175
67372
  ""
67176
67373
  ];
67177
- writeFileSafe(path40.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
67374
+ writeFileSafe(path41.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
67178
67375
  }
67179
67376
  return bundleDir;
67180
67377
  }
67181
67378
  function ensureParentDir2(filePath) {
67182
- const parent = path40.dirname(filePath);
67183
- if (!fs35.existsSync(parent)) {
67184
- fs35.mkdirSync(parent, { recursive: true });
67379
+ const parent = path41.dirname(filePath);
67380
+ if (!fs36.existsSync(parent)) {
67381
+ fs36.mkdirSync(parent, { recursive: true });
67185
67382
  }
67186
67383
  }
67187
67384
  function writePluginBundleArtifacts(repoPath, bundleDir, report) {
67188
67385
  if (report.pluginActions.length === 0) return;
67189
67386
  for (const action of report.pluginActions) {
67190
- const pluginRoot = path40.join(bundleDir, "plugins", action.pluginId);
67191
- const templatesDir = path40.join(pluginRoot, "templates");
67192
- const installedDir = path40.join(pluginRoot, "installed");
67193
- const diffsDir = path40.join(pluginRoot, "diffs");
67387
+ const pluginRoot = path41.join(bundleDir, "plugins", action.pluginId);
67388
+ const templatesDir = path41.join(pluginRoot, "templates");
67389
+ const installedDir = path41.join(pluginRoot, "installed");
67390
+ const diffsDir = path41.join(pluginRoot, "diffs");
67194
67391
  for (const dir of [templatesDir, installedDir, diffsDir]) {
67195
- fs35.mkdirSync(dir, { recursive: true });
67392
+ fs36.mkdirSync(dir, { recursive: true });
67196
67393
  }
67197
67394
  const templateContent = readTemplatePluginFile(action.pluginId, action.file);
67198
67395
  if (templateContent === null) continue;
67199
- const templatePath = path40.join(templatesDir, action.file);
67396
+ const templatePath = path41.join(templatesDir, action.file);
67200
67397
  ensureParentDir2(templatePath);
67201
67398
  writeFileSafe(templatePath, templateContent);
67202
67399
  const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
67203
67400
  if (installedContent !== null) {
67204
- const installedPath = path40.join(installedDir, action.file);
67401
+ const installedPath = path41.join(installedDir, action.file);
67205
67402
  ensureParentDir2(installedPath);
67206
67403
  writeFileSafe(installedPath, installedContent);
67207
67404
  const diff = createUnifiedDiff(
@@ -67211,7 +67408,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
67211
67408
  `templates/${action.file}`
67212
67409
  );
67213
67410
  if (diff) {
67214
- const diffPath = path40.join(diffsDir, `${action.file}.diff`);
67411
+ const diffPath = path41.join(diffsDir, `${action.file}.diff`);
67215
67412
  ensureParentDir2(diffPath);
67216
67413
  writeFileSafe(diffPath, diff);
67217
67414
  }
@@ -67247,9 +67444,9 @@ function buildMaintainBundle(repoPath, validation2, drift) {
67247
67444
  return { bundleDir, report };
67248
67445
  }
67249
67446
  function removeMaintainBundle(repoPath) {
67250
- const bundleDir = path40.join(getHarnessDir(repoPath), MAINTAIN_DIR);
67251
- if (fs35.existsSync(bundleDir)) {
67252
- fs35.rmSync(bundleDir, { recursive: true, force: true });
67447
+ const bundleDir = path41.join(getHarnessDir(repoPath), MAINTAIN_DIR);
67448
+ if (fs36.existsSync(bundleDir)) {
67449
+ fs36.rmSync(bundleDir, { recursive: true, force: true });
67253
67450
  }
67254
67451
  }
67255
67452
  function formatMaintainBundlePromptSection(report) {
@@ -67338,11 +67535,11 @@ init_manifest();
67338
67535
  init_stages();
67339
67536
  function listHarnessScripts(repoPath) {
67340
67537
  const harnessDir = getHarnessDir(repoPath);
67341
- if (!fs36.existsSync(harnessDir)) return [];
67342
- return fs36.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
67538
+ if (!fs37.existsSync(harnessDir)) return [];
67539
+ return fs37.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
67343
67540
  }
67344
67541
  function describeProject(repoPath) {
67345
- const resolved = path41.resolve(repoPath);
67542
+ const resolved = path42.resolve(repoPath);
67346
67543
  const manifest = readManifest(resolved);
67347
67544
  const present = harnessExists(resolved);
67348
67545
  return {
@@ -67362,8 +67559,8 @@ function describeProject(repoPath) {
67362
67559
  };
67363
67560
  }
67364
67561
  async function initHarness(options) {
67365
- const repoPath = path41.resolve(options.repoPath);
67366
- if (!fs36.existsSync(repoPath)) {
67562
+ const repoPath = path42.resolve(options.repoPath);
67563
+ if (!fs37.existsSync(repoPath)) {
67367
67564
  throw new Error(`Path not found: ${repoPath}`);
67368
67565
  }
67369
67566
  const scaffold = scaffoldHarnessBoilerplate(repoPath, {
@@ -67383,9 +67580,9 @@ async function initHarness(options) {
67383
67580
  };
67384
67581
  }
67385
67582
  async function maintainHarness(options) {
67386
- const repoPath = path41.resolve(options.repoPath);
67583
+ const repoPath = path42.resolve(options.repoPath);
67387
67584
  const harnessDir = getHarnessDir(repoPath);
67388
- if (!fs36.existsSync(harnessDir)) {
67585
+ if (!fs37.existsSync(harnessDir)) {
67389
67586
  throw new Error('No .har/ found. Run "har env init" first.');
67390
67587
  }
67391
67588
  const drift = compareHarnessToTemplate(repoPath);
@@ -67395,6 +67592,7 @@ async function maintainHarness(options) {
67395
67592
  throw new Error("Cannot finalize: harness validation has errors. Fix them first.");
67396
67593
  }
67397
67594
  syncAgentSlotsToHarnessEnv(repoPath);
67595
+ finalizeAgentsMdInstructionFiles(repoPath);
67398
67596
  const existing = readManifest(repoPath);
67399
67597
  finalizeHarness(
67400
67598
  repoPath,
@@ -67419,13 +67617,13 @@ function addPlugin(repoPath, pluginId, options = {}) {
67419
67617
  }
67420
67618
 
67421
67619
  // src/harness/custom-stage.ts
67422
- var fs37 = __toESM(require("fs"));
67423
- var path42 = __toESM(require("path"));
67620
+ var fs38 = __toESM(require("fs"));
67621
+ var path43 = __toESM(require("path"));
67424
67622
  init_schema2();
67425
67623
  init_stages();
67426
67624
  var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
67427
67625
  function addCustomStage(repoPath, options) {
67428
- const resolved = path42.resolve(repoPath);
67626
+ const resolved = path43.resolve(repoPath);
67429
67627
  if (!harnessExists(resolved)) {
67430
67628
  throw new Error('No .har/ harness found. Run "har env init" first.');
67431
67629
  }
@@ -67462,20 +67660,20 @@ function addCustomStage(repoPath, options) {
67462
67660
  if (options.command) {
67463
67661
  stage.command = options.command;
67464
67662
  } else {
67465
- const scriptRel = path42.join("stages", `${id}.sh`);
67466
- const scriptAbs = path42.join(resolved, ".har", scriptRel);
67467
- if (fs37.existsSync(scriptAbs) && !options.force) {
67663
+ const scriptRel = path43.join("stages", `${id}.sh`);
67664
+ const scriptAbs = path43.join(resolved, ".har", scriptRel);
67665
+ if (fs38.existsSync(scriptAbs) && !options.force) {
67468
67666
  throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
67469
67667
  }
67470
- const skeletonPath = path42.join(
67668
+ const skeletonPath = path43.join(
67471
67669
  resolveTemplatesDir(),
67472
67670
  "plugins",
67473
67671
  "custom-stage-skeleton.sh"
67474
67672
  );
67475
- const skeleton = fs37.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
67476
- fs37.mkdirSync(path42.dirname(scriptAbs), { recursive: true });
67477
- fs37.writeFileSync(scriptAbs, skeleton);
67478
- fs37.chmodSync(scriptAbs, 493);
67673
+ const skeleton = fs38.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
67674
+ fs38.mkdirSync(path43.dirname(scriptAbs), { recursive: true });
67675
+ fs38.writeFileSync(scriptAbs, skeleton);
67676
+ fs38.chmodSync(scriptAbs, 493);
67479
67677
  filesWritten.push(`.har/${scriptRel}`);
67480
67678
  stage.script = scriptRel;
67481
67679
  stage.artifacts = [
@@ -67523,8 +67721,8 @@ function addCustomStage(repoPath, options) {
67523
67721
  }
67524
67722
 
67525
67723
  // src/harness/adaptation-prompt.ts
67526
- var fs38 = __toESM(require("fs"));
67527
- var path43 = __toESM(require("path"));
67724
+ var fs39 = __toESM(require("fs"));
67725
+ var path44 = __toESM(require("path"));
67528
67726
  var readline3 = __toESM(require("readline"));
67529
67727
 
67530
67728
  // src/utils/clipboard.ts
@@ -67614,7 +67812,7 @@ function loadTemplate(name) {
67614
67812
  if (!filePath) {
67615
67813
  throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
67616
67814
  }
67617
- return fs38.readFileSync(filePath, "utf8");
67815
+ return fs39.readFileSync(filePath, "utf8");
67618
67816
  }
67619
67817
  function applyProfilePlaceholders(content, profile) {
67620
67818
  return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
@@ -67636,7 +67834,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
67636
67834
  }
67637
67835
  function writeAdaptationPrompt(repoPath, content) {
67638
67836
  const harnessDir = getHarnessDir(repoPath);
67639
- const filePath = path43.join(harnessDir, ADAPTATION_PROMPT_FILE);
67837
+ const filePath = path44.join(harnessDir, ADAPTATION_PROMPT_FILE);
67640
67838
  writeFileSafe(filePath, content);
67641
67839
  return filePath;
67642
67840
  }
@@ -67691,27 +67889,27 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
67691
67889
  }
67692
67890
 
67693
67891
  // src/harness/cursor-rule.ts
67694
- var fs39 = __toESM(require("fs"));
67695
- var path44 = __toESM(require("path"));
67892
+ var fs40 = __toESM(require("fs"));
67893
+ var path45 = __toESM(require("path"));
67696
67894
  var readline4 = __toESM(require("readline"));
67697
67895
  init_file_ops();
67698
67896
  init_logging();
67699
67897
  var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
67700
67898
  function getCursorRulePath(repoPath) {
67701
- return path44.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
67899
+ return path45.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
67702
67900
  }
67703
67901
  function isCursorWorkspace(repoPath) {
67704
- return fs39.existsSync(path44.join(repoPath, ".cursor"));
67902
+ return fs40.existsSync(path45.join(repoPath, ".cursor"));
67705
67903
  }
67706
67904
  function cursorRuleExists(repoPath) {
67707
- return fs39.existsSync(getCursorRulePath(repoPath));
67905
+ return fs40.existsSync(getCursorRulePath(repoPath));
67708
67906
  }
67709
67907
  function scaffoldCursorRule(repoPath) {
67710
67908
  const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
67711
67909
  if (!templatePath) {
67712
67910
  throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
67713
67911
  }
67714
- const content = fs39.readFileSync(templatePath, "utf8");
67912
+ const content = fs40.readFileSync(templatePath, "utf8");
67715
67913
  writeFileSafe(getCursorRulePath(repoPath), content);
67716
67914
  }
67717
67915
  async function handleCursorRule(options) {
@@ -67801,7 +67999,7 @@ init_control_config();
67801
67999
 
67802
68000
  // src/core/control-lifecycle.ts
67803
68001
  var import_child_process9 = require("child_process");
67804
- var path45 = __toESM(require("path"));
68002
+ var path46 = __toESM(require("path"));
67805
68003
 
67806
68004
  // src/core/control-image.ts
67807
68005
  var DEFAULT_CONTROL_IMAGE = "theosfactory/har-control";
@@ -67827,10 +68025,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
67827
68025
  var CONTROL_CONTAINER_PORT = 3847;
67828
68026
  var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
67829
68027
  function resolveControlDir() {
67830
- return path45.resolve(__dirname, "..", "control");
68028
+ return path46.resolve(__dirname, "..", "control");
67831
68029
  }
67832
68030
  function resolveControlBuildContext() {
67833
- return path45.resolve(resolveControlDir(), "..");
68031
+ return path46.resolve(resolveControlDir(), "..");
67834
68032
  }
67835
68033
  function buildDockerRunArgs(options) {
67836
68034
  const name = options.containerName ?? CONTROL_CONTAINER_NAME;
@@ -67886,7 +68084,7 @@ async function startMissionControl(options) {
67886
68084
  "-t",
67887
68085
  imageRef,
67888
68086
  "-f",
67889
- path45.join(resolveControlDir(), "Dockerfile"),
68087
+ path46.join(resolveControlDir(), "Dockerfile"),
67890
68088
  resolveControlBuildContext()
67891
68089
  ]);
67892
68090
  if (buildCode !== 0) {
@@ -68033,7 +68231,7 @@ async function ensureTelemetryInfrastructure(options) {
68033
68231
  // src/core/run-service.ts
68034
68232
  init_telemetry_config();
68035
68233
  init_telemetry_env();
68036
- var path47 = __toESM(require("path"));
68234
+ var path48 = __toESM(require("path"));
68037
68235
  init_local_executor();
68038
68236
  function extractShellOutput(result) {
68039
68237
  const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
@@ -68236,12 +68434,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
68236
68434
  suffix: session.suffix,
68237
68435
  createdAt: session.createdAt
68238
68436
  });
68239
- const envFile = path47.join(session.workDir, `.env.agent.${options.agentId}`);
68437
+ const envFile = path48.join(session.workDir, `.env.agent.${options.agentId}`);
68240
68438
  try {
68241
68439
  appendTelemetryEnvToFile(envFile, {
68242
68440
  sessionKey,
68243
68441
  agentId: options.agentId,
68244
- repoPath: path47.resolve(options.repoPath),
68442
+ repoPath: path48.resolve(options.repoPath),
68245
68443
  workDir: session.workDir,
68246
68444
  branch: session.branch,
68247
68445
  suffix: session.suffix,
@@ -68479,9 +68677,9 @@ init_slot_status();
68479
68677
  var readline5 = __toESM(require("readline"));
68480
68678
 
68481
68679
  // src/core/hooks.ts
68482
- var fs41 = __toESM(require("fs"));
68680
+ var fs42 = __toESM(require("fs"));
68483
68681
  var os16 = __toESM(require("os"));
68484
- var path48 = __toESM(require("path"));
68682
+ var path49 = __toESM(require("path"));
68485
68683
  init_shell();
68486
68684
  init_schema2();
68487
68685
  init_stages();
@@ -68512,7 +68710,7 @@ function resolveCheckoutRoot(cwd) {
68512
68710
  function resolveHooksDir(checkoutDir) {
68513
68711
  const hooksPath = tryGit3(checkoutDir, "rev-parse --git-path hooks");
68514
68712
  if (!hooksPath) throw new Error(`Not a git checkout: ${checkoutDir}`);
68515
- return path48.resolve(checkoutDir, hooksPath);
68713
+ return path49.resolve(checkoutDir, hooksPath);
68516
68714
  }
68517
68715
  function getConfiguredHooksPath(checkoutDir) {
68518
68716
  return tryGit3(checkoutDir, "config core.hooksPath") || void 0;
@@ -68520,9 +68718,9 @@ function getConfiguredHooksPath(checkoutDir) {
68520
68718
  function defaultHarInvocation() {
68521
68719
  const entry = process.argv[1];
68522
68720
  if (entry && entry.endsWith(".js")) {
68523
- return `"${process.execPath}" "${path48.resolve(entry)}"`;
68721
+ return `"${process.execPath}" "${path49.resolve(entry)}"`;
68524
68722
  }
68525
- if (entry) return `"${path48.resolve(entry)}"`;
68723
+ if (entry) return `"${path49.resolve(entry)}"`;
68526
68724
  return "har";
68527
68725
  }
68528
68726
  function buildHookScript(harInvocation, subcommand, failOpenNotice) {
@@ -68543,40 +68741,40 @@ exit 0
68543
68741
  `;
68544
68742
  }
68545
68743
  function upsertMarkedBlock2(filePath, block) {
68546
- if (!fs41.existsSync(filePath)) {
68547
- fs41.writeFileSync(filePath, `#!/bin/sh
68744
+ if (!fs42.existsSync(filePath)) {
68745
+ fs42.writeFileSync(filePath, `#!/bin/sh
68548
68746
  ${block}
68549
68747
  `, { mode: 493 });
68550
68748
  return "created";
68551
68749
  }
68552
- const content = fs41.readFileSync(filePath, "utf8");
68750
+ const content = fs42.readFileSync(filePath, "utf8");
68553
68751
  if (content.includes(MARKER_START)) {
68554
68752
  const pattern = new RegExp(
68555
68753
  `${escapeRegExp2(MARKER_START)}[\\s\\S]*?${escapeRegExp2(MARKER_END)}`
68556
68754
  );
68557
- fs41.writeFileSync(filePath, content.replace(pattern, block));
68558
- fs41.chmodSync(filePath, 493);
68755
+ fs42.writeFileSync(filePath, content.replace(pattern, block));
68756
+ fs42.chmodSync(filePath, 493);
68559
68757
  return "updated";
68560
68758
  }
68561
68759
  const suffix = content.endsWith("\n") ? "" : "\n";
68562
- fs41.writeFileSync(filePath, `${content}${suffix}
68760
+ fs42.writeFileSync(filePath, `${content}${suffix}
68563
68761
  ${block}
68564
68762
  `);
68565
- fs41.chmodSync(filePath, 493);
68763
+ fs42.chmodSync(filePath, 493);
68566
68764
  return "appended";
68567
68765
  }
68568
68766
  function removeMarkedBlock(filePath) {
68569
- if (!fs41.existsSync(filePath)) return false;
68570
- const content = fs41.readFileSync(filePath, "utf8");
68767
+ if (!fs42.existsSync(filePath)) return false;
68768
+ const content = fs42.readFileSync(filePath, "utf8");
68571
68769
  if (!content.includes(MARKER_START)) return false;
68572
68770
  const pattern = new RegExp(
68573
68771
  `\\n?${escapeRegExp2(MARKER_START)}[\\s\\S]*?${escapeRegExp2(MARKER_END)}\\n?`
68574
68772
  );
68575
68773
  const stripped = content.replace(pattern, "\n");
68576
68774
  if (stripped.replace(/^#!\/bin\/sh\n?/, "").trim() === "") {
68577
- fs41.rmSync(filePath);
68775
+ fs42.rmSync(filePath);
68578
68776
  } else {
68579
- fs41.writeFileSync(filePath, stripped);
68777
+ fs42.writeFileSync(filePath, stripped);
68580
68778
  }
68581
68779
  return true;
68582
68780
  }
@@ -68598,20 +68796,20 @@ Or re-run with --force to write into that directory anyway.`
68598
68796
  );
68599
68797
  }
68600
68798
  const hooksDir = resolveHooksDir(checkout);
68601
- fs41.mkdirSync(hooksDir, { recursive: true });
68799
+ fs42.mkdirSync(hooksDir, { recursive: true });
68602
68800
  const invocation = options.harInvocation ?? defaultHarInvocation();
68603
- fs41.writeFileSync(
68604
- path48.join(hooksDir, "har-pre-commit"),
68801
+ fs42.writeFileSync(
68802
+ path49.join(hooksDir, "har-pre-commit"),
68605
68803
  buildHookScript(invocation, "check", "har: binary not found; skipping commit gate (reinstall with har hooks install)"),
68606
68804
  { mode: 493 }
68607
68805
  );
68608
- fs41.writeFileSync(
68609
- path48.join(hooksDir, "har-post-commit"),
68806
+ fs42.writeFileSync(
68807
+ path49.join(hooksDir, "har-post-commit"),
68610
68808
  buildHookScript(invocation, "record-commit", "har: binary not found; skipping commit association"),
68611
68809
  { mode: 493 }
68612
68810
  );
68613
- const preCommit = upsertMarkedBlock2(path48.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
68614
- const postCommit = upsertMarkedBlock2(path48.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
68811
+ const preCommit = upsertMarkedBlock2(path49.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
68812
+ const postCommit = upsertMarkedBlock2(path49.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
68615
68813
  ensureValidationsIgnored(checkout);
68616
68814
  return { hooksDir, preCommit, postCommit };
68617
68815
  }
@@ -68620,12 +68818,12 @@ function uninstallHooks(repoPath) {
68620
68818
  if (!checkout) throw new Error(`Not a git repository: ${repoPath}`);
68621
68819
  const hooksDir = resolveHooksDir(checkout);
68622
68820
  let removed = false;
68623
- removed = removeMarkedBlock(path48.join(hooksDir, "pre-commit")) || removed;
68624
- removed = removeMarkedBlock(path48.join(hooksDir, "post-commit")) || removed;
68821
+ removed = removeMarkedBlock(path49.join(hooksDir, "pre-commit")) || removed;
68822
+ removed = removeMarkedBlock(path49.join(hooksDir, "post-commit")) || removed;
68625
68823
  for (const file of ["har-pre-commit", "har-post-commit"]) {
68626
- const full = path48.join(hooksDir, file);
68627
- if (fs41.existsSync(full)) {
68628
- fs41.rmSync(full);
68824
+ const full = path49.join(hooksDir, file);
68825
+ if (fs42.existsSync(full)) {
68826
+ fs42.rmSync(full);
68629
68827
  removed = true;
68630
68828
  }
68631
68829
  }
@@ -68644,10 +68842,10 @@ function isAgentWorktree(checkoutDir) {
68644
68842
  if (branch && (/^har-agent-\d+$/.test(branch) || /-har-agent-\d+-[a-z0-9]+$/.test(branch))) {
68645
68843
  return true;
68646
68844
  }
68647
- const worktreesRoot = path48.join(os16.homedir(), "worktrees");
68648
- const resolved = path48.resolve(checkoutDir);
68649
- const name = path48.basename(resolved);
68650
- return resolved.startsWith(`${worktreesRoot}${path48.sep}`) && (/-agent-\d+$/.test(name) || /-har-agent-\d+-[a-z0-9]+$/.test(name));
68845
+ const worktreesRoot = path49.join(os16.homedir(), "worktrees");
68846
+ const resolved = path49.resolve(checkoutDir);
68847
+ const name = path49.basename(resolved);
68848
+ return resolved.startsWith(`${worktreesRoot}${path49.sep}`) && (/-agent-\d+$/.test(name) || /-har-agent-\d+-[a-z0-9]+$/.test(name));
68651
68849
  }
68652
68850
  function resolveEffectiveMode(checkoutDir, gate) {
68653
68851
  if (!gate.enabled) return "off";
@@ -68660,15 +68858,15 @@ function getHooksStatus(repoPath) {
68660
68858
  const hooksDir = resolveHooksDir(checkout);
68661
68859
  const gate = getCommitGateConfig(checkout);
68662
68860
  const hasBlock = (name) => {
68663
- const file = path48.join(hooksDir, name);
68664
- return fs41.existsSync(file) && fs41.readFileSync(file, "utf8").includes(MARKER_START);
68861
+ const file = path49.join(hooksDir, name);
68862
+ return fs42.existsSync(file) && fs42.readFileSync(file, "utf8").includes(MARKER_START);
68665
68863
  };
68666
68864
  return {
68667
68865
  checkout,
68668
68866
  hooksDir,
68669
68867
  configuredHooksPath: getConfiguredHooksPath(checkout),
68670
- preCommitInstalled: hasBlock("pre-commit") && fs41.existsSync(path48.join(hooksDir, "har-pre-commit")),
68671
- postCommitInstalled: hasBlock("post-commit") && fs41.existsSync(path48.join(hooksDir, "har-post-commit")),
68868
+ preCommitInstalled: hasBlock("pre-commit") && fs42.existsSync(path49.join(hooksDir, "har-pre-commit")),
68869
+ postCommitInstalled: hasBlock("post-commit") && fs42.existsSync(path49.join(hooksDir, "har-post-commit")),
68672
68870
  gate,
68673
68871
  effectiveMode: resolveEffectiveMode(checkout, gate)
68674
68872
  };
@@ -68679,7 +68877,7 @@ function checkCommitGate(cwd) {
68679
68877
  }
68680
68878
  const checkout = resolveCheckoutRoot(cwd);
68681
68879
  if (!checkout) return { exitCode: 0, messages: [] };
68682
- if (!fs41.existsSync(path48.join(checkout, ".har", "stages.json"))) {
68880
+ if (!fs42.existsSync(path49.join(checkout, ".har", "stages.json"))) {
68683
68881
  return { exitCode: 0, messages: [] };
68684
68882
  }
68685
68883
  const gate = getCommitGateConfig(checkout);
@@ -68801,21 +68999,21 @@ async function handleCommitGateOnboarding(options) {
68801
68999
  }
68802
69000
 
68803
69001
  // src/core/onboarding-preferences.ts
68804
- var fs42 = __toESM(require("fs"));
69002
+ var fs43 = __toESM(require("fs"));
68805
69003
  var os17 = __toESM(require("os"));
68806
- var path49 = __toESM(require("path"));
69004
+ var path50 = __toESM(require("path"));
68807
69005
  init_schema2();
68808
69006
  function getOnboardingPreferencesPath() {
68809
69007
  if (process.env.HAR_PREFERENCES_PATH) {
68810
- return path49.resolve(process.env.HAR_PREFERENCES_PATH);
69008
+ return path50.resolve(process.env.HAR_PREFERENCES_PATH);
68811
69009
  }
68812
- return path49.join(os17.homedir(), ".har", "preferences.json");
69010
+ return path50.join(os17.homedir(), ".har", "preferences.json");
68813
69011
  }
68814
69012
  function readOnboardingPreferences() {
68815
69013
  const preferencePath = getOnboardingPreferencesPath();
68816
69014
  try {
68817
- if (!fs42.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
68818
- return OnboardingPreferencesSchema.parse(JSON.parse(fs42.readFileSync(preferencePath, "utf8")));
69015
+ if (!fs43.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
69016
+ return OnboardingPreferencesSchema.parse(JSON.parse(fs43.readFileSync(preferencePath, "utf8")));
68819
69017
  } catch {
68820
69018
  return OnboardingPreferencesSchema.parse({});
68821
69019
  }
@@ -68840,8 +69038,8 @@ function writeOnboardingPreferences(overrides) {
68840
69038
  };
68841
69039
  const parsed = OnboardingPreferencesSchema.parse(preference);
68842
69040
  const preferencePath = getOnboardingPreferencesPath();
68843
- fs42.mkdirSync(path49.dirname(preferencePath), { recursive: true });
68844
- fs42.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
69041
+ fs43.mkdirSync(path50.dirname(preferencePath), { recursive: true });
69042
+ fs43.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
68845
69043
  `);
68846
69044
  return parsed;
68847
69045
  }
@@ -69132,7 +69330,7 @@ var envCommand = {
69132
69330
  }
69133
69331
  };
69134
69332
  async function handleInit(argv) {
69135
- const repoPath = path50.resolve(argv.repo);
69333
+ const repoPath = path51.resolve(argv.repo);
69136
69334
  const onboarding = resolveOnboardingOptions(argv);
69137
69335
  header("har env init");
69138
69336
  info(`Repository: ${repoPath}`);
@@ -69178,7 +69376,7 @@ async function handleInit(argv) {
69178
69376
  }
69179
69377
  }
69180
69378
  async function handleMaintain(argv) {
69181
- const repoPath = path50.resolve(argv.repo);
69379
+ const repoPath = path51.resolve(argv.repo);
69182
69380
  const onboarding = resolveOnboardingOptions(argv);
69183
69381
  header("har env maintain");
69184
69382
  info(`Repository: ${repoPath}`);
@@ -69233,6 +69431,8 @@ async function handleMaintain(argv) {
69233
69431
  mode: "maintain",
69234
69432
  autoYes: argv.yes,
69235
69433
  cursorRule: onboarding.cursorRule,
69434
+ writeAgentsMd: !argv.finalize,
69435
+ finalize: argv.finalize,
69236
69436
  ...onboarding.agentSkills
69237
69437
  });
69238
69438
  } catch (err) {
@@ -69284,7 +69484,9 @@ async function applyAgentIntegrations(options) {
69284
69484
  enabled: options.enabled,
69285
69485
  cursorRule: options.cursorRule,
69286
69486
  autoYes: options.autoYes,
69287
- mode: options.mode
69487
+ mode: options.mode,
69488
+ writeAgentsMd: options.writeAgentsMd,
69489
+ finalize: options.finalize
69288
69490
  });
69289
69491
  const cursorRuleFlag = options.cursorRule === false ? false : options.cursorRule === true || instruction.plan.cursorRule ? true : false;
69290
69492
  await handleCursorRule({
@@ -69305,7 +69507,7 @@ async function applyAgentIntegrations(options) {
69305
69507
  }
69306
69508
  }
69307
69509
  async function handleAddPlugin(argv) {
69308
- const repoPath = path50.resolve(argv.repo);
69510
+ const repoPath = path51.resolve(argv.repo);
69309
69511
  const available = listPluginIds();
69310
69512
  if (argv.list) {
69311
69513
  for (const id of available) {
@@ -69343,7 +69545,7 @@ async function handleAddPlugin(argv) {
69343
69545
  }
69344
69546
  }
69345
69547
  async function handleAddStage(argv) {
69346
- const repoPath = path50.resolve(argv.repo);
69548
+ const repoPath = path51.resolve(argv.repo);
69347
69549
  const available = listPluginIds();
69348
69550
  if (argv.list) {
69349
69551
  warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
@@ -69409,7 +69611,7 @@ async function handleAddStage(argv) {
69409
69611
  });
69410
69612
  }
69411
69613
  async function handlePreflight(argv) {
69412
- const repo = path50.resolve(argv.repo);
69614
+ const repo = path51.resolve(argv.repo);
69413
69615
  const agentId = validateAgentId(argv.id, repo);
69414
69616
  const result = await preflightEnvironment({
69415
69617
  repoPath: repo,
@@ -69425,7 +69627,7 @@ async function handlePreflight(argv) {
69425
69627
  return finishCommand(result.code);
69426
69628
  }
69427
69629
  async function handleLaunch(argv) {
69428
- const repo = path50.resolve(argv.repo);
69630
+ const repo = path51.resolve(argv.repo);
69429
69631
  const agentId = validateAgentId(argv.id, repo);
69430
69632
  if (!argv.resume) {
69431
69633
  const guard = checkLaunchGuard2(repo, agentId, {});
@@ -69480,7 +69682,7 @@ async function handleRecover(argv) {
69480
69682
  });
69481
69683
  }
69482
69684
  async function handleVerify(argv) {
69483
- const repo = path50.resolve(argv.repo);
69685
+ const repo = path51.resolve(argv.repo);
69484
69686
  const agentId = validateAgentId(argv.id, repo);
69485
69687
  const result = await runVerification({
69486
69688
  repoPath: repo,
@@ -69492,7 +69694,7 @@ async function handleVerify(argv) {
69492
69694
  return finishCommand(result.code);
69493
69695
  }
69494
69696
  async function handleTeardown(argv) {
69495
- const repo = path50.resolve(argv.repo);
69697
+ const repo = path51.resolve(argv.repo);
69496
69698
  const agentId = validateAgentId(argv.id, repo);
69497
69699
  const result = await teardownEnvironment({
69498
69700
  repoPath: repo,
@@ -69503,7 +69705,7 @@ async function handleTeardown(argv) {
69503
69705
  return finishCommand(result.code);
69504
69706
  }
69505
69707
  async function handleComplete(argv) {
69506
- const repo = path50.resolve(argv.repo);
69708
+ const repo = path51.resolve(argv.repo);
69507
69709
  const agentId = validateAgentId(argv.id, repo);
69508
69710
  const result = await completeEnvironment({
69509
69711
  repoPath: repo,
@@ -69524,7 +69726,7 @@ async function handleComplete(argv) {
69524
69726
  return finishCommand(result.code);
69525
69727
  }
69526
69728
  async function handleStatus(argv) {
69527
- const repoPath = path50.resolve(argv.repo);
69729
+ const repoPath = path51.resolve(argv.repo);
69528
69730
  if (argv.json) {
69529
69731
  const status = collectEnvironmentStatus(repoPath);
69530
69732
  const output = EnvironmentStatusSchema.parse(status);
@@ -69537,7 +69739,7 @@ async function handleStatus(argv) {
69537
69739
  });
69538
69740
  }
69539
69741
  async function handleRunsList(argv) {
69540
- const repoPath = path50.resolve(argv.repo);
69742
+ const repoPath = path51.resolve(argv.repo);
69541
69743
  const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
69542
69744
  if (argv.json) {
69543
69745
  process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
@@ -69554,7 +69756,7 @@ async function handleRunsList(argv) {
69554
69756
  }
69555
69757
  }
69556
69758
  async function handleRunsGet(argv) {
69557
- const run2 = getRun(path50.resolve(argv.repo), argv.runId);
69759
+ const run2 = getRun(path51.resolve(argv.repo), argv.runId);
69558
69760
  if (!run2) {
69559
69761
  error(`Run not found: ${argv.runId}`);
69560
69762
  return finishCommand(1);
@@ -69636,7 +69838,7 @@ function printNextSteps() {
69636
69838
  }
69637
69839
 
69638
69840
  // src/cli/commands/control.ts
69639
- var path54 = __toESM(require("path"));
69841
+ var path55 = __toESM(require("path"));
69640
69842
 
69641
69843
  // node_modules/@inquirer/core/dist/esm/lib/key.mjs
69642
69844
  var isUpKey = (key) => (
@@ -71690,9 +71892,9 @@ var import_run_async = __toESM(require_run_async(), 1);
71690
71892
  var import_mute_stream2 = __toESM(require_lib(), 1);
71691
71893
  var import_ansi_escapes5 = __toESM(require_ansi_escapes(), 1);
71692
71894
  var _ = {
71693
- set: (obj, path61 = "", value) => {
71895
+ set: (obj, path62 = "", value) => {
71694
71896
  let pointer = obj;
71695
- path61.split(".").forEach((key, index, arr) => {
71897
+ path62.split(".").forEach((key, index, arr) => {
71696
71898
  if (key === "__proto__" || key === "constructor")
71697
71899
  return;
71698
71900
  if (index === arr.length - 1) {
@@ -71703,8 +71905,8 @@ var _ = {
71703
71905
  pointer = pointer[key];
71704
71906
  });
71705
71907
  },
71706
- get: (obj, path61 = "", defaultValue) => {
71707
- const travel = (regexp) => String.prototype.split.call(path61, regexp).filter(Boolean).reduce(
71908
+ get: (obj, path62 = "", defaultValue) => {
71909
+ const travel = (regexp) => String.prototype.split.call(path62, regexp).filter(Boolean).reduce(
71708
71910
  // @ts-expect-error implicit any on res[key]
71709
71911
  (res, key) => res !== null && res !== void 0 ? res[key] : res,
71710
71912
  obj
@@ -71958,21 +72160,21 @@ init_control_port();
71958
72160
  init_control_sync();
71959
72161
 
71960
72162
  // src/core/control-sync-selection.ts
71961
- var fs43 = __toESM(require("fs"));
72163
+ var fs44 = __toESM(require("fs"));
71962
72164
  var os18 = __toESM(require("os"));
71963
- var path51 = __toESM(require("path"));
72165
+ var path52 = __toESM(require("path"));
71964
72166
  init_control_repo_path();
71965
72167
  function getSelectionPath() {
71966
72168
  if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
71967
- return path51.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
72169
+ return path52.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
71968
72170
  }
71969
- return path51.join(os18.homedir(), ".har", "sync-selection.json");
72171
+ return path52.join(os18.homedir(), ".har", "sync-selection.json");
71970
72172
  }
71971
72173
  function readSyncSelection() {
71972
72174
  const selectionPath = getSelectionPath();
71973
72175
  try {
71974
- if (!fs43.existsSync(selectionPath)) return null;
71975
- const parsed = JSON.parse(fs43.readFileSync(selectionPath, "utf8"));
72176
+ if (!fs44.existsSync(selectionPath)) return null;
72177
+ const parsed = JSON.parse(fs44.readFileSync(selectionPath, "utf8"));
71976
72178
  if (!Array.isArray(parsed.repos)) return null;
71977
72179
  return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
71978
72180
  } catch {
@@ -71982,8 +72184,8 @@ function readSyncSelection() {
71982
72184
  function writeSyncSelection(repos) {
71983
72185
  const selectionPath = getSelectionPath();
71984
72186
  const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
71985
- fs43.mkdirSync(path51.dirname(selectionPath), { recursive: true });
71986
- fs43.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
72187
+ fs44.mkdirSync(path52.dirname(selectionPath), { recursive: true });
72188
+ fs44.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
71987
72189
  }
71988
72190
  function resolveSyncSelection(input) {
71989
72191
  const { discovered, stored, forceSelect, isTTY } = input;
@@ -72090,8 +72292,8 @@ If your browser did not open, paste that URL.
72090
72292
  }
72091
72293
 
72092
72294
  // src/core/control-unregister.ts
72093
- var fs44 = __toESM(require("fs"));
72094
- var path52 = __toESM(require("path"));
72295
+ var fs45 = __toESM(require("fs"));
72296
+ var path53 = __toESM(require("path"));
72095
72297
  init_control_repo_path();
72096
72298
  init_control_registry();
72097
72299
  init_control_config();
@@ -72101,9 +72303,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
72101
72303
  const harnessRoot = canonicalizeControlRepoPath(repoPath);
72102
72304
  const byPath = /* @__PURE__ */ new Map();
72103
72305
  const add = (partial2) => {
72104
- const resolved = path52.resolve(partial2.worktreePath);
72306
+ const resolved = path53.resolve(partial2.worktreePath);
72105
72307
  if (!resolved || resolved === harnessRoot) return;
72106
- const exists = partial2.exists ?? fs44.existsSync(resolved);
72308
+ const exists = partial2.exists ?? fs45.existsSync(resolved);
72107
72309
  const prev = byPath.get(resolved);
72108
72310
  if (prev) {
72109
72311
  byPath.set(resolved, {
@@ -72217,28 +72419,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
72217
72419
  trigger: "cli"
72218
72420
  });
72219
72421
  if (result.code !== 0) {
72220
- if (fs44.existsSync(candidate.worktreePath)) {
72221
- fs44.rmSync(candidate.worktreePath, { recursive: true, force: true });
72422
+ if (fs45.existsSync(candidate.worktreePath)) {
72423
+ fs45.rmSync(candidate.worktreePath, { recursive: true, force: true });
72222
72424
  }
72223
72425
  }
72224
72426
  outcomes.push({
72225
72427
  path: candidate.worktreePath,
72226
72428
  agentId: candidate.agentId,
72227
- deleted: !fs44.existsSync(candidate.worktreePath),
72228
- error: result.code !== 0 && fs44.existsSync(candidate.worktreePath) ? result.stderr : void 0
72429
+ deleted: !fs45.existsSync(candidate.worktreePath),
72430
+ error: result.code !== 0 && fs45.existsSync(candidate.worktreePath) ? result.stderr : void 0
72229
72431
  });
72230
72432
  } catch (err) {
72231
72433
  const message = err instanceof Error ? err.message : String(err);
72232
72434
  try {
72233
- if (fs44.existsSync(candidate.worktreePath)) {
72234
- fs44.rmSync(candidate.worktreePath, { recursive: true, force: true });
72435
+ if (fs45.existsSync(candidate.worktreePath)) {
72436
+ fs45.rmSync(candidate.worktreePath, { recursive: true, force: true });
72235
72437
  }
72236
72438
  } catch {
72237
72439
  }
72238
72440
  outcomes.push({
72239
72441
  path: candidate.worktreePath,
72240
72442
  agentId: candidate.agentId,
72241
- deleted: !fs44.existsSync(candidate.worktreePath),
72443
+ deleted: !fs45.existsSync(candidate.worktreePath),
72242
72444
  error: message
72243
72445
  });
72244
72446
  }
@@ -72301,16 +72503,16 @@ init_control_config();
72301
72503
  init_control_registry();
72302
72504
 
72303
72505
  // src/core/harness-scrub.ts
72304
- var fs45 = __toESM(require("fs"));
72305
- var path53 = __toESM(require("path"));
72506
+ var fs46 = __toESM(require("fs"));
72507
+ var path54 = __toESM(require("path"));
72306
72508
  var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
72307
72509
  function scrubLocalHarnessDirs(repoPath) {
72308
72510
  const results = [];
72309
- const resolved = path53.resolve(repoPath);
72310
- if (!fs45.existsSync(resolved)) {
72511
+ const resolved = path54.resolve(repoPath);
72512
+ if (!fs46.existsSync(resolved)) {
72311
72513
  for (const directory of HARNESS_SCRUB_DIRS) {
72312
72514
  results.push({
72313
- path: path53.join(resolved, ".har", directory),
72515
+ path: path54.join(resolved, ".har", directory),
72314
72516
  directory,
72315
72517
  deleted: false,
72316
72518
  error: "repository path does not exist"
@@ -72319,24 +72521,24 @@ function scrubLocalHarnessDirs(repoPath) {
72319
72521
  return results;
72320
72522
  }
72321
72523
  for (const directory of HARNESS_SCRUB_DIRS) {
72322
- const target = path53.join(resolved, ".har", directory);
72323
- if (!fs45.existsSync(target)) {
72524
+ const target = path54.join(resolved, ".har", directory);
72525
+ if (!fs46.existsSync(target)) {
72324
72526
  results.push({ path: target, directory, deleted: true });
72325
72527
  continue;
72326
72528
  }
72327
72529
  try {
72328
- fs45.rmSync(target, { recursive: true, force: true });
72530
+ fs46.rmSync(target, { recursive: true, force: true });
72329
72531
  results.push({
72330
72532
  path: target,
72331
72533
  directory,
72332
- deleted: !fs45.existsSync(target),
72333
- error: fs45.existsSync(target) ? "failed to remove directory" : void 0
72534
+ deleted: !fs46.existsSync(target),
72535
+ error: fs46.existsSync(target) ? "failed to remove directory" : void 0
72334
72536
  });
72335
72537
  } catch (err) {
72336
72538
  results.push({
72337
72539
  path: target,
72338
72540
  directory,
72339
- deleted: !fs45.existsSync(target),
72541
+ deleted: !fs46.existsSync(target),
72340
72542
  error: err instanceof Error ? err.message : String(err)
72341
72543
  });
72342
72544
  }
@@ -72347,7 +72549,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
72347
72549
  const results = [];
72348
72550
  const seen = /* @__PURE__ */ new Set();
72349
72551
  for (const repoPath of repoPaths) {
72350
- const key = path53.resolve(repoPath);
72552
+ const key = path54.resolve(repoPath);
72351
72553
  if (seen.has(key)) continue;
72352
72554
  seen.add(key);
72353
72555
  results.push(...scrubLocalHarnessDirs(key));
@@ -72603,7 +72805,7 @@ async function handleDown() {
72603
72805
  return finishCommand(code);
72604
72806
  }
72605
72807
  async function handleRegister(argv) {
72606
- const repoPath = path54.resolve(argv.repo);
72808
+ const repoPath = path55.resolve(argv.repo);
72607
72809
  header("har control register");
72608
72810
  info(`Repository: ${repoPath}`);
72609
72811
  try {
@@ -72695,7 +72897,7 @@ async function handleReset(argv) {
72695
72897
  }
72696
72898
  }
72697
72899
  async function handleUnregister(argv) {
72698
- const repoPath = path54.resolve(argv.repo);
72900
+ const repoPath = path55.resolve(argv.repo);
72699
72901
  const worktrees = listUnregisterWorktreeCandidates(repoPath);
72700
72902
  try {
72701
72903
  let deleteWorktrees = argv.deleteWorktrees;
@@ -72874,11 +73076,11 @@ async function handleLogin(argv) {
72874
73076
  }
72875
73077
 
72876
73078
  // src/cli/commands/hooks.ts
72877
- var path56 = __toESM(require("path"));
73079
+ var path57 = __toESM(require("path"));
72878
73080
 
72879
73081
  // src/core/claude-hooks.ts
72880
- var fs46 = __toESM(require("fs"));
72881
- var path55 = __toESM(require("path"));
73082
+ var fs47 = __toESM(require("fs"));
73083
+ var path56 = __toESM(require("path"));
72882
73084
  var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
72883
73085
  var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
72884
73086
  var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
@@ -72889,8 +73091,8 @@ function isHarGuardEntry(entry) {
72889
73091
  );
72890
73092
  }
72891
73093
  function readSettings(settingsPath) {
72892
- if (!fs46.existsSync(settingsPath)) return {};
72893
- const raw = fs46.readFileSync(settingsPath, "utf8").trim();
73094
+ if (!fs47.existsSync(settingsPath)) return {};
73095
+ const raw = fs47.readFileSync(settingsPath, "utf8").trim();
72894
73096
  if (raw === "") return {};
72895
73097
  const parsed = JSON.parse(raw);
72896
73098
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -72899,19 +73101,19 @@ function readSettings(settingsPath) {
72899
73101
  return parsed;
72900
73102
  }
72901
73103
  function writeSettings(settingsPath, settings) {
72902
- fs46.mkdirSync(path55.dirname(settingsPath), { recursive: true });
72903
- fs46.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
73104
+ fs47.mkdirSync(path56.dirname(settingsPath), { recursive: true });
73105
+ fs47.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
72904
73106
  }
72905
73107
  function installClaudeGuard(repoPath) {
72906
73108
  const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
72907
73109
  if (!templatePath) {
72908
73110
  throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
72909
73111
  }
72910
- const guardScript = path55.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
72911
- fs46.mkdirSync(path55.dirname(guardScript), { recursive: true });
72912
- fs46.copyFileSync(templatePath, guardScript);
72913
- fs46.chmodSync(guardScript, 493);
72914
- const settingsPath = path55.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73112
+ const guardScript = path56.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73113
+ fs47.mkdirSync(path56.dirname(guardScript), { recursive: true });
73114
+ fs47.copyFileSync(templatePath, guardScript);
73115
+ fs47.chmodSync(guardScript, 493);
73116
+ const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
72915
73117
  const settings = readSettings(settingsPath);
72916
73118
  const hooks = settings.hooks ?? {};
72917
73119
  const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
@@ -72925,15 +73127,15 @@ function installClaudeGuard(repoPath) {
72925
73127
  }
72926
73128
  function uninstallClaudeGuard(repoPath) {
72927
73129
  let removed = false;
72928
- const guardScript = path55.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
72929
- if (fs46.existsSync(guardScript)) {
72930
- fs46.rmSync(guardScript);
73130
+ const guardScript = path56.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73131
+ if (fs47.existsSync(guardScript)) {
73132
+ fs47.rmSync(guardScript);
72931
73133
  removed = true;
72932
- const parent = path55.dirname(guardScript);
72933
- if (fs46.existsSync(parent) && fs46.readdirSync(parent).length === 0) fs46.rmdirSync(parent);
73134
+ const parent = path56.dirname(guardScript);
73135
+ if (fs47.existsSync(parent) && fs47.readdirSync(parent).length === 0) fs47.rmdirSync(parent);
72934
73136
  }
72935
- const settingsPath = path55.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
72936
- if (fs46.existsSync(settingsPath)) {
73137
+ const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73138
+ if (fs47.existsSync(settingsPath)) {
72937
73139
  const settings = readSettings(settingsPath);
72938
73140
  const preToolUse = settings.hooks?.PreToolUse;
72939
73141
  if (preToolUse) {
@@ -72958,8 +73160,8 @@ function uninstallClaudeGuard(repoPath) {
72958
73160
  return { removed };
72959
73161
  }
72960
73162
  function claudeGuardInstalled(repoPath) {
72961
- const settingsPath = path55.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
72962
- if (!fs46.existsSync(settingsPath)) return false;
73163
+ const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73164
+ if (!fs47.existsSync(settingsPath)) return false;
72963
73165
  try {
72964
73166
  const settings = readSettings(settingsPath);
72965
73167
  return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
@@ -72976,7 +73178,7 @@ function repoOption(y) {
72976
73178
  function handleInstall2(argv) {
72977
73179
  try {
72978
73180
  if (argv.claude) {
72979
- const result2 = installClaudeGuard(path56.resolve(argv.repo));
73181
+ const result2 = installClaudeGuard(path57.resolve(argv.repo));
72980
73182
  success("Claude Code worktree guard installed.");
72981
73183
  info(`Guard script: ${result2.guardScript}`);
72982
73184
  info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
@@ -72984,7 +73186,7 @@ function handleInstall2(argv) {
72984
73186
  info("Commit both files so the guard travels with the repo.");
72985
73187
  return;
72986
73188
  }
72987
- const result = installHooks({ repoPath: path56.resolve(argv.repo), force: argv.force });
73189
+ const result = installHooks({ repoPath: path57.resolve(argv.repo), force: argv.force });
72988
73190
  success(`Commit gate installed in ${result.hooksDir}`);
72989
73191
  info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
72990
73192
  info("Commits of unverified change batches will be blocked in agent worktrees.");
@@ -72997,7 +73199,7 @@ function handleInstall2(argv) {
72997
73199
  function handleUninstall(argv) {
72998
73200
  try {
72999
73201
  if (argv.claude) {
73000
- const result2 = uninstallClaudeGuard(path56.resolve(argv.repo));
73202
+ const result2 = uninstallClaudeGuard(path57.resolve(argv.repo));
73001
73203
  if (result2.removed) {
73002
73204
  success("Claude Code worktree guard removed.");
73003
73205
  } else {
@@ -73005,7 +73207,7 @@ function handleUninstall(argv) {
73005
73207
  }
73006
73208
  return;
73007
73209
  }
73008
- const result = uninstallHooks(path56.resolve(argv.repo));
73210
+ const result = uninstallHooks(path57.resolve(argv.repo));
73009
73211
  if (result.removed) {
73010
73212
  success(`Commit gate removed from ${result.hooksDir}`);
73011
73213
  } else {
@@ -73018,7 +73220,7 @@ function handleUninstall(argv) {
73018
73220
  }
73019
73221
  function handleStatus2(argv) {
73020
73222
  try {
73021
- const status = getHooksStatus(path56.resolve(argv.repo));
73223
+ const status = getHooksStatus(path57.resolve(argv.repo));
73022
73224
  if (argv.json) {
73023
73225
  process.stdout.write(`${JSON.stringify(status, null, 2)}
73024
73226
  `);
@@ -73036,7 +73238,7 @@ function handleStatus2(argv) {
73036
73238
  );
73037
73239
  info(`Effective: ${status.effectiveMode} (in this checkout)`);
73038
73240
  info(
73039
- `Claude guard: ${claudeGuardInstalled(path56.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
73241
+ `Claude guard: ${claudeGuardInstalled(path57.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
73040
73242
  );
73041
73243
  } catch (err) {
73042
73244
  error(err instanceof Error ? err.message : String(err));
@@ -73297,10 +73499,10 @@ function assignProp(target, prop, value) {
73297
73499
  configurable: true
73298
73500
  });
73299
73501
  }
73300
- function getElementAtPath(obj, path61) {
73301
- if (!path61)
73502
+ function getElementAtPath(obj, path62) {
73503
+ if (!path62)
73302
73504
  return obj;
73303
- return path61.reduce((acc, key) => acc?.[key], obj);
73505
+ return path62.reduce((acc, key) => acc?.[key], obj);
73304
73506
  }
73305
73507
  function promiseAllObject(promisesObj) {
73306
73508
  const keys = Object.keys(promisesObj);
@@ -73620,11 +73822,11 @@ function aborted(x, startIndex = 0) {
73620
73822
  }
73621
73823
  return false;
73622
73824
  }
73623
- function prefixIssues(path61, issues) {
73825
+ function prefixIssues(path62, issues) {
73624
73826
  return issues.map((iss) => {
73625
73827
  var _a2;
73626
73828
  (_a2 = iss).path ?? (_a2.path = []);
73627
- iss.path.unshift(path61);
73829
+ iss.path.unshift(path62);
73628
73830
  return iss;
73629
73831
  });
73630
73832
  }
@@ -80098,7 +80300,7 @@ var Server = class extends Protocol {
80098
80300
  };
80099
80301
 
80100
80302
  // src/mcp/server.ts
80101
- var path57 = __toESM(require("path"));
80303
+ var path58 = __toESM(require("path"));
80102
80304
 
80103
80305
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
80104
80306
  var import_node_process3 = __toESM(require("node:process"), 1);
@@ -80741,7 +80943,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
80741
80943
  const input = ControlUpInputSchema.parse({ ...args, repo });
80742
80944
  const result = await startControlAndSync({
80743
80945
  detach: input.detach,
80744
- cwd: path57.resolve(input.repo)
80946
+ cwd: path58.resolve(input.repo)
80745
80947
  });
80746
80948
  if (result.code !== 0) {
80747
80949
  return {
@@ -80805,11 +81007,11 @@ var mcpCommand = {
80805
81007
  };
80806
81008
 
80807
81009
  // src/cli/commands/onboard.ts
80808
- var path59 = __toESM(require("path"));
81010
+ var path60 = __toESM(require("path"));
80809
81011
  init_stages();
80810
81012
 
80811
81013
  // src/core/onboarding.ts
80812
- var path58 = __toESM(require("path"));
81014
+ var path59 = __toESM(require("path"));
80813
81015
  init_control_config();
80814
81016
  init_control_sync();
80815
81017
  init_otel_hooks();
@@ -80944,7 +81146,7 @@ async function defaultEnsureControl(options) {
80944
81146
  return { started: true, apiUrl: result.apiUrl };
80945
81147
  }
80946
81148
  async function runOnboarding(options, deps = {}) {
80947
- const repoPath = path58.resolve(options.repoPath);
81149
+ const repoPath = path59.resolve(options.repoPath);
80948
81150
  const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
80949
81151
  const ensureControl = deps.ensureControl ?? defaultEnsureControl;
80950
81152
  const init = deps.initHarness ?? initHarness;
@@ -81132,7 +81334,7 @@ async function promptChoices(args) {
81132
81334
  };
81133
81335
  }
81134
81336
  const pluginChoices = listPluginChoices();
81135
- const repoPath = path59.resolve(args.repo);
81337
+ const repoPath = path60.resolve(args.repo);
81136
81338
  const alreadyPresent = harnessExists(repoPath);
81137
81339
  const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
81138
81340
  const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
@@ -81249,7 +81451,7 @@ function printSummary(result) {
81249
81451
  console.error("");
81250
81452
  }
81251
81453
  async function handleOnboard(argv) {
81252
- const repoPath = path59.resolve(argv.repo);
81454
+ const repoPath = path60.resolve(argv.repo);
81253
81455
  header("har onboard");
81254
81456
  info(`Repository: ${repoPath}`);
81255
81457
  try {
@@ -81480,7 +81682,7 @@ var preferencesCommand = {
81480
81682
  };
81481
81683
 
81482
81684
  // src/cli/commands/telemetry.ts
81483
- var path60 = __toESM(require("path"));
81685
+ var path61 = __toESM(require("path"));
81484
81686
  init_control_config();
81485
81687
  init_control_sync();
81486
81688
  init_manifest();
@@ -81573,7 +81775,7 @@ async function handleOff() {
81573
81775
  info("Mission Control will not auto-start. Existing usage rows are kept.");
81574
81776
  }
81575
81777
  async function handleWriteEnv(argv) {
81576
- const repoPath = path60.resolve(argv.repo);
81778
+ const repoPath = path61.resolve(argv.repo);
81577
81779
  const harnessRoot = resolveHarnessRoot(repoPath);
81578
81780
  const session = readSlotRegistry(harnessRoot, argv.agentId);
81579
81781
  const workDir = argv.workDir ?? session?.workDir ?? repoPath;
@@ -81585,7 +81787,7 @@ async function handleWriteEnv(argv) {
81585
81787
  suffix,
81586
81788
  createdAt: session?.createdAt
81587
81789
  });
81588
- const envFile = argv.envFile ?? path60.join(workDir, `.env.agent.${argv.agentId}`);
81790
+ const envFile = argv.envFile ?? path61.join(workDir, `.env.agent.${argv.agentId}`);
81589
81791
  const attrs = {
81590
81792
  sessionKey,
81591
81793
  agentId: argv.agentId,
@@ -81601,7 +81803,7 @@ async function handleWriteEnv(argv) {
81601
81803
  success(`Wrote session attribution to ${envFile}`);
81602
81804
  }
81603
81805
  function handlePrintEnv(argv) {
81604
- const repoPath = path60.resolve(argv.repo);
81806
+ const repoPath = path61.resolve(argv.repo);
81605
81807
  const workDir = argv.workDir ?? repoPath;
81606
81808
  const sessionKey = buildSessionKey({
81607
81809
  branch: argv.branch,