@osfactory/har 0.46.0 → 0.46.2

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 +989 -683
  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() {
@@ -28010,6 +28010,109 @@ Compared to other leading proprietary and open-weights models Command A delivers
28010
28010
  }
28011
28011
  });
28012
28012
 
28013
+ // packages/schemas/src/cursor-pricing-overlay.ts
28014
+ function isCursorNativeModel(modelId) {
28015
+ const id = modelId.toLowerCase();
28016
+ const normalized = id.startsWith("cursor-") ? id.slice("cursor-".length) : id;
28017
+ return normalized.startsWith("composer") || normalized.includes("grok-4.5");
28018
+ }
28019
+ function estimateCursorNativeCostUsd(usage2, modelId) {
28020
+ if (!isCursorNativeModel(modelId)) return null;
28021
+ try {
28022
+ const result = ve(usage2, modelId, { provider: CURSOR_PRICING_PROVIDER });
28023
+ return result?.total_price ?? null;
28024
+ } catch {
28025
+ return null;
28026
+ }
28027
+ }
28028
+ var CURSOR_PRICING_PROVIDER;
28029
+ var init_cursor_pricing_overlay = __esm({
28030
+ "packages/schemas/src/cursor-pricing-overlay.ts"() {
28031
+ "use strict";
28032
+ init_dist();
28033
+ CURSOR_PRICING_PROVIDER = {
28034
+ id: "cursor",
28035
+ name: "Cursor",
28036
+ pricing_urls: ["https://cursor.com/docs/models-and-pricing"],
28037
+ api_pattern: String.raw`https://(.*\.)?cursor\.(com|sh)`,
28038
+ model_match: {
28039
+ or: [{ starts_with: "composer" }, { contains: "grok-4.5" }]
28040
+ },
28041
+ provider_match: { contains: "cursor" },
28042
+ models: [
28043
+ {
28044
+ id: "composer-2.5-fast",
28045
+ name: "Composer 2.5 (Fast)",
28046
+ description: "Fast-mode variant of Composer 2.5.",
28047
+ match: {
28048
+ or: [
28049
+ { equals: "composer-2.5-fast" },
28050
+ { equals: "cursor-composer-2.5-fast" }
28051
+ ]
28052
+ },
28053
+ prices: {
28054
+ input_mtok: 3,
28055
+ cache_read_mtok: 0.5,
28056
+ output_mtok: 15
28057
+ }
28058
+ },
28059
+ {
28060
+ id: "composer-2.5",
28061
+ name: "Composer 2.5",
28062
+ description: "Cursor's own agentic coding model.",
28063
+ match: {
28064
+ or: [
28065
+ { equals: "composer-2.5" },
28066
+ { equals: "cursor-composer-2.5" }
28067
+ ]
28068
+ },
28069
+ prices: {
28070
+ input_mtok: 0.5,
28071
+ cache_read_mtok: 0.2,
28072
+ output_mtok: 2.5
28073
+ }
28074
+ },
28075
+ {
28076
+ id: "grok-4.5-fast",
28077
+ name: "Grok 4.5 (Fast)",
28078
+ description: "Fast-mode variant of Grok 4.5.",
28079
+ match: {
28080
+ or: [
28081
+ { equals: "grok-4.5-fast" },
28082
+ { equals: "grok-4.5-high-fast" },
28083
+ { equals: "cursor-grok-4.5-high-fast" },
28084
+ { equals: "cursor-grok-4.5-fast" }
28085
+ ]
28086
+ },
28087
+ prices: {
28088
+ input_mtok: 4,
28089
+ cache_read_mtok: 1,
28090
+ output_mtok: 18
28091
+ }
28092
+ },
28093
+ {
28094
+ id: "grok-4.5",
28095
+ name: "Grok 4.5",
28096
+ description: "Jointly trained by Cursor and SpaceXAI for long-running coding and knowledge work.",
28097
+ match: {
28098
+ or: [
28099
+ { equals: "grok-4.5" },
28100
+ { equals: "grok-4.5-high" },
28101
+ { equals: "cursor-grok-4.5-high" },
28102
+ { equals: "cursor-grok-4.5" }
28103
+ ]
28104
+ },
28105
+ prices: {
28106
+ input_mtok: 2,
28107
+ cache_read_mtok: 0.5,
28108
+ output_mtok: 6
28109
+ }
28110
+ }
28111
+ ]
28112
+ };
28113
+ }
28114
+ });
28115
+
28013
28116
  // packages/schemas/src/usage-pricing.ts
28014
28117
  function num(value) {
28015
28118
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
@@ -28056,6 +28159,10 @@ function estimateModelCostUsd(modelId, totals, agentTool) {
28056
28159
  continue;
28057
28160
  }
28058
28161
  }
28162
+ for (const candidate of pricingModelCandidates(modelId)) {
28163
+ const overlay = estimateCursorNativeCostUsd(usage2, candidate);
28164
+ if (overlay != null) return overlay;
28165
+ }
28059
28166
  return null;
28060
28167
  }
28061
28168
  function enrichUsageWithPricing(usage2) {
@@ -28095,6 +28202,7 @@ var init_usage_pricing = __esm({
28095
28202
  "packages/schemas/src/usage-pricing.ts"() {
28096
28203
  "use strict";
28097
28204
  init_dist();
28205
+ init_cursor_pricing_overlay();
28098
28206
  }
28099
28207
  });
28100
28208
 
@@ -32522,32 +32630,32 @@ __export(otel_hooks_exports, {
32522
32630
  });
32523
32631
  function getOtelHooksHome() {
32524
32632
  if (process.env.HAR_OTEL_HOOKS_HOME) {
32525
- return path46.resolve(process.env.HAR_OTEL_HOOKS_HOME);
32633
+ return path47.resolve(process.env.HAR_OTEL_HOOKS_HOME);
32526
32634
  }
32527
- return path46.join(os15.homedir(), ".har", "otel-hooks");
32635
+ return path47.join(os15.homedir(), ".har", "otel-hooks");
32528
32636
  }
32529
32637
  function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
32530
- return path46.join(hooksHome, "otel_config.json");
32638
+ return path47.join(hooksHome, "otel_config.json");
32531
32639
  }
32532
32640
  function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
32533
- return path46.join(hooksHome, "run-otel-hook.sh");
32641
+ return path47.join(hooksHome, "run-otel-hook.sh");
32534
32642
  }
32535
32643
  function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
32536
- return path46.join(hooksHome, "state");
32644
+ return path47.join(hooksHome, "state");
32537
32645
  }
32538
32646
  function localOtelHookBin(hooksHome) {
32539
- return path46.join(hooksHome, "node_modules", ".bin", "otel-hook");
32647
+ return path47.join(hooksHome, "node_modules", ".bin", "otel-hook");
32540
32648
  }
32541
32649
  function installedPackageVersion(hooksHome) {
32542
32650
  try {
32543
- const pkgPath = path46.join(
32651
+ const pkgPath = path47.join(
32544
32652
  hooksHome,
32545
32653
  "node_modules",
32546
32654
  "@osfactory",
32547
32655
  "otel-hook",
32548
32656
  "package.json"
32549
32657
  );
32550
- const pkg = JSON.parse(fs40.readFileSync(pkgPath, "utf8"));
32658
+ const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf8"));
32551
32659
  return typeof pkg.version === "string" ? pkg.version : null;
32552
32660
  } catch {
32553
32661
  return null;
@@ -32598,15 +32706,15 @@ function buildOtelHooksConfig(options) {
32598
32706
  };
32599
32707
  }
32600
32708
  function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
32601
- fs40.mkdirSync(hooksHome, { recursive: true });
32709
+ fs41.mkdirSync(hooksHome, { recursive: true });
32602
32710
  const configPath = getOtelHooksConfigPath(hooksHome);
32603
- fs40.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
32711
+ fs41.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
32604
32712
  `);
32605
32713
  return configPath;
32606
32714
  }
32607
32715
  function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
32608
- fs40.mkdirSync(hooksHome, { recursive: true });
32609
- fs40.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
32716
+ fs41.mkdirSync(hooksHome, { recursive: true });
32717
+ fs41.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
32610
32718
  const wrapperPath = getOtelHooksWrapperPath(hooksHome);
32611
32719
  const configPath = getOtelHooksConfigPath(hooksHome);
32612
32720
  const stateDir = getOtelHooksStateDir(hooksHome);
@@ -32618,9 +32726,9 @@ exec "${otelHookCommand}" run \\
32618
32726
  --state-dir "${stateDir}" \\
32619
32727
  "$@"
32620
32728
  `;
32621
- fs40.writeFileSync(wrapperPath, script, { mode: 493 });
32729
+ fs41.writeFileSync(wrapperPath, script, { mode: 493 });
32622
32730
  try {
32623
- fs40.chmodSync(wrapperPath, 493);
32731
+ fs41.chmodSync(wrapperPath, 493);
32624
32732
  } catch {
32625
32733
  }
32626
32734
  return wrapperPath;
@@ -32633,11 +32741,11 @@ function commandExists2(command2) {
32633
32741
  }
32634
32742
  function resolveOtelHookCommand(hooksHome) {
32635
32743
  const local = localOtelHookBin(hooksHome);
32636
- if (fs40.existsSync(local)) return local;
32744
+ if (fs41.existsSync(local)) return local;
32637
32745
  return null;
32638
32746
  }
32639
32747
  function tryInstallPackage(hooksHome) {
32640
- fs40.mkdirSync(hooksHome, { recursive: true });
32748
+ fs41.mkdirSync(hooksHome, { recursive: true });
32641
32749
  if (!commandExists2("npm")) {
32642
32750
  return {
32643
32751
  ok: false,
@@ -32649,7 +32757,7 @@ function tryInstallPackage(hooksHome) {
32649
32757
  ["install", "--prefix", hooksHome, "--no-fund", "--no-audit", OTEL_HOOKS_PACKAGE],
32650
32758
  { encoding: "utf8", timeout: 18e4 }
32651
32759
  );
32652
- if (result.status === 0 && fs40.existsSync(localOtelHookBin(hooksHome))) {
32760
+ if (result.status === 0 && fs41.existsSync(localOtelHookBin(hooksHome))) {
32653
32761
  return { ok: true, detail: `npm install --prefix ${hooksHome} ${OTEL_HOOKS_PACKAGE}` };
32654
32762
  }
32655
32763
  return {
@@ -32675,14 +32783,14 @@ function uninstallLegacyPythonHooks(hooksHome) {
32675
32783
  }
32676
32784
  function removeLegacyPythonArtifacts(hooksHome) {
32677
32785
  const legacyPaths = [
32678
- path46.join(hooksHome, ".venv"),
32679
- path46.join(hooksHome, "otel_config.yaml"),
32680
- path46.join(hooksHome, "venv")
32786
+ path47.join(hooksHome, ".venv"),
32787
+ path47.join(hooksHome, "otel_config.yaml"),
32788
+ path47.join(hooksHome, "venv")
32681
32789
  ];
32682
32790
  for (const target of legacyPaths) {
32683
32791
  try {
32684
- if (fs40.existsSync(target)) {
32685
- fs40.rmSync(target, { recursive: true, force: true });
32792
+ if (fs41.existsSync(target)) {
32793
+ fs41.rmSync(target, { recursive: true, force: true });
32686
32794
  }
32687
32795
  } catch {
32688
32796
  }
@@ -32723,10 +32831,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
32723
32831
  };
32724
32832
  }
32725
32833
  function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
32726
- if (!fs40.existsSync(filePath)) return false;
32834
+ if (!fs41.existsSync(filePath)) return false;
32727
32835
  let raw;
32728
32836
  try {
32729
- raw = fs40.readFileSync(filePath, "utf8");
32837
+ raw = fs41.readFileSync(filePath, "utf8");
32730
32838
  } catch {
32731
32839
  return false;
32732
32840
  }
@@ -32773,15 +32881,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
32773
32881
  return changed;
32774
32882
  };
32775
32883
  if (!walk(parsed)) return false;
32776
- fs40.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32884
+ fs41.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32777
32885
  `);
32778
32886
  return true;
32779
32887
  }
32780
32888
  function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
32781
- if (!fs40.existsSync(filePath)) return false;
32889
+ if (!fs41.existsSync(filePath)) return false;
32782
32890
  let raw;
32783
32891
  try {
32784
- raw = fs40.readFileSync(filePath, "utf8");
32892
+ raw = fs41.readFileSync(filePath, "utf8");
32785
32893
  } catch {
32786
32894
  return false;
32787
32895
  }
@@ -32816,21 +32924,21 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
32816
32924
  }
32817
32925
  }
32818
32926
  if (!changed) return false;
32819
- fs40.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32927
+ fs41.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
32820
32928
  `);
32821
32929
  return true;
32822
32930
  }
32823
32931
  function rewriteKnownHookRegistrations(wrapperPath) {
32824
32932
  const home = os15.homedir();
32825
32933
  const candidates = [
32826
- path46.join(home, ".cursor", "hooks.json"),
32827
- path46.join(home, ".claude", "settings.json"),
32828
- path46.join(home, ".codex", "hooks.json")
32934
+ path47.join(home, ".cursor", "hooks.json"),
32935
+ path47.join(home, ".claude", "settings.json"),
32936
+ path47.join(home, ".codex", "hooks.json")
32829
32937
  ];
32830
32938
  for (const filePath of candidates) {
32831
32939
  try {
32832
32940
  rewriteHookCommandsToWrapper(filePath, wrapperPath);
32833
- if (filePath.endsWith(`${path46.sep}.cursor${path46.sep}hooks.json`)) {
32941
+ if (filePath.endsWith(`${path47.sep}.cursor${path47.sep}hooks.json`)) {
32834
32942
  pruneLegacyCursorHookEvents(filePath, wrapperPath);
32835
32943
  }
32836
32944
  } catch {
@@ -32846,7 +32954,7 @@ function ensureOtelHooks(options) {
32846
32954
  const hooksHome = getOtelHooksHome();
32847
32955
  const errors = [];
32848
32956
  const providersSetup = [];
32849
- fs40.mkdirSync(hooksHome, { recursive: true });
32957
+ fs41.mkdirSync(hooksHome, { recursive: true });
32850
32958
  let otelHookCommand = resolveOtelHookCommand(hooksHome);
32851
32959
  const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
32852
32960
  if (needsInstall) {
@@ -32940,14 +33048,14 @@ function ensureOtelHooks(options) {
32940
33048
  function disableOtelHooksExport() {
32941
33049
  return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
32942
33050
  }
32943
- var import_child_process10, fs40, os15, path46, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
33051
+ var import_child_process10, fs41, os15, path47, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
32944
33052
  var init_otel_hooks = __esm({
32945
33053
  "src/core/otel-hooks.ts"() {
32946
33054
  "use strict";
32947
33055
  import_child_process10 = require("child_process");
32948
- fs40 = __toESM(require("fs"));
33056
+ fs41 = __toESM(require("fs"));
32949
33057
  os15 = __toESM(require("os"));
32950
- path46 = __toESM(require("path"));
33058
+ path47 = __toESM(require("path"));
32951
33059
  init_control_config();
32952
33060
  init_telemetry_config();
32953
33061
  OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.1.2";
@@ -34063,15 +34171,15 @@ var require_route = __commonJS({
34063
34171
  };
34064
34172
  }
34065
34173
  function wrapConversion(toModel, graph) {
34066
- const path61 = [graph[toModel].parent, toModel];
34174
+ const path62 = [graph[toModel].parent, toModel];
34067
34175
  let fn = conversions[graph[toModel].parent][toModel];
34068
34176
  let cur = graph[toModel].parent;
34069
34177
  while (graph[cur].parent) {
34070
- path61.unshift(graph[cur].parent);
34178
+ path62.unshift(graph[cur].parent);
34071
34179
  fn = link(conversions[graph[cur].parent][cur], fn);
34072
34180
  cur = graph[cur].parent;
34073
34181
  }
34074
- fn.conversion = path61;
34182
+ fn.conversion = path62;
34075
34183
  return fn;
34076
34184
  }
34077
34185
  module2.exports = function(fromModel) {
@@ -40001,7 +40109,7 @@ var require_iso2022 = __commonJS({
40001
40109
  // node_modules/chardet/index.js
40002
40110
  var require_chardet = __commonJS({
40003
40111
  "node_modules/chardet/index.js"(exports2, module2) {
40004
- var fs47 = require("fs");
40112
+ var fs48 = require("fs");
40005
40113
  var utf8 = require_utf8();
40006
40114
  var unicode = require_unicode();
40007
40115
  var mbcs = require_mbcs();
@@ -40075,28 +40183,28 @@ var require_chardet = __commonJS({
40075
40183
  var fd;
40076
40184
  var handler = function(err, buffer) {
40077
40185
  if (fd) {
40078
- fs47.closeSync(fd);
40186
+ fs48.closeSync(fd);
40079
40187
  }
40080
40188
  if (err) return cb(err, null);
40081
40189
  cb(null, self.detect(buffer, opts));
40082
40190
  };
40083
40191
  if (opts && opts.sampleSize) {
40084
- fd = fs47.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40085
- fs47.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40192
+ fd = fs48.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40193
+ fs48.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40086
40194
  handler(err, sample);
40087
40195
  });
40088
40196
  return;
40089
40197
  }
40090
- fs47.readFile(filepath, handler);
40198
+ fs48.readFile(filepath, handler);
40091
40199
  };
40092
40200
  module2.exports.detectFileSync = function(filepath, opts) {
40093
40201
  if (opts && opts.sampleSize) {
40094
- var fd = fs47.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40095
- fs47.readSync(fd, sample2, 0, opts.sampleSize);
40096
- fs47.closeSync(fd);
40202
+ var fd = fs48.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40203
+ fs48.readSync(fd, sample2, 0, opts.sampleSize);
40204
+ fs48.closeSync(fd);
40097
40205
  return self.detect(sample2, opts);
40098
40206
  }
40099
- return self.detect(fs47.readFileSync(filepath), opts);
40207
+ return self.detect(fs48.readFileSync(filepath), opts);
40100
40208
  };
40101
40209
  module2.exports.detectAll = function(buffer, opts) {
40102
40210
  if (typeof opts !== "object") {
@@ -43561,16 +43669,16 @@ var require_os_tmpdir = __commonJS({
43561
43669
  var isWindows = process.platform === "win32";
43562
43670
  var trailingSlashRe = isWindows ? /[^:]\\$/ : /.\/$/;
43563
43671
  module2.exports = function() {
43564
- var path61;
43672
+ var path62;
43565
43673
  if (isWindows) {
43566
- path61 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43674
+ path62 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43567
43675
  } else {
43568
- path61 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43676
+ path62 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43569
43677
  }
43570
- if (trailingSlashRe.test(path61)) {
43571
- path61 = path61.slice(0, -1);
43678
+ if (trailingSlashRe.test(path62)) {
43679
+ path62 = path62.slice(0, -1);
43572
43680
  }
43573
- return path61;
43681
+ return path62;
43574
43682
  };
43575
43683
  }
43576
43684
  });
@@ -43578,8 +43686,8 @@ var require_os_tmpdir = __commonJS({
43578
43686
  // node_modules/tmp/lib/tmp.js
43579
43687
  var require_tmp = __commonJS({
43580
43688
  "node_modules/tmp/lib/tmp.js"(exports2, module2) {
43581
- var fs47 = require("fs");
43582
- var path61 = require("path");
43689
+ var fs48 = require("fs");
43690
+ var path62 = require("path");
43583
43691
  var crypto6 = require("crypto");
43584
43692
  var osTmpDir = require_os_tmpdir();
43585
43693
  var _c2 = process.binding("constants");
@@ -43621,7 +43729,7 @@ var require_tmp = __commonJS({
43621
43729
  }
43622
43730
  function _generateTmpName(opts) {
43623
43731
  if (opts.name) {
43624
- return path61.join(opts.dir || tmpDir, opts.name);
43732
+ return path62.join(opts.dir || tmpDir, opts.name);
43625
43733
  }
43626
43734
  if (opts.template) {
43627
43735
  return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
@@ -43632,7 +43740,7 @@ var require_tmp = __commonJS({
43632
43740
  _randomChars(12),
43633
43741
  opts.postfix || ""
43634
43742
  ].join("");
43635
- return path61.join(opts.dir || tmpDir, name);
43743
+ return path62.join(opts.dir || tmpDir, name);
43636
43744
  }
43637
43745
  function tmpName(options, callback) {
43638
43746
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1], tries = opts.name ? 1 : opts.tries || DEFAULT_TRIES;
@@ -43642,7 +43750,7 @@ var require_tmp = __commonJS({
43642
43750
  return cb(new Error("Invalid template provided"));
43643
43751
  (function _getUniqueName() {
43644
43752
  const name = _generateTmpName(opts);
43645
- fs47.stat(name, function(err) {
43753
+ fs48.stat(name, function(err) {
43646
43754
  if (!err) {
43647
43755
  if (tries-- > 0) return _getUniqueName();
43648
43756
  return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
@@ -43660,7 +43768,7 @@ var require_tmp = __commonJS({
43660
43768
  do {
43661
43769
  const name = _generateTmpName(opts);
43662
43770
  try {
43663
- fs47.statSync(name);
43771
+ fs48.statSync(name);
43664
43772
  } catch (e) {
43665
43773
  return name;
43666
43774
  }
@@ -43672,13 +43780,13 @@ var require_tmp = __commonJS({
43672
43780
  opts.postfix = _isUndefined(opts.postfix) ? ".tmp" : opts.postfix;
43673
43781
  tmpName(opts, function _tmpNameCreated(err, name) {
43674
43782
  if (err) return cb(err);
43675
- fs47.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43783
+ fs48.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43676
43784
  if (err2) return cb(err2);
43677
43785
  if (opts.discardDescriptor) {
43678
- return fs47.close(fd, function _discardCallback(err3) {
43786
+ return fs48.close(fd, function _discardCallback(err3) {
43679
43787
  if (err3) {
43680
43788
  try {
43681
- fs47.unlinkSync(name);
43789
+ fs48.unlinkSync(name);
43682
43790
  } catch (e) {
43683
43791
  if (!isENOENT(e)) {
43684
43792
  err3 = e;
@@ -43701,9 +43809,9 @@ var require_tmp = __commonJS({
43701
43809
  opts.postfix = opts.postfix || ".tmp";
43702
43810
  const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
43703
43811
  const name = tmpNameSync(opts);
43704
- var fd = fs47.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43812
+ var fd = fs48.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43705
43813
  if (opts.discardDescriptor) {
43706
- fs47.closeSync(fd);
43814
+ fs48.closeSync(fd);
43707
43815
  fd = void 0;
43708
43816
  }
43709
43817
  return {
@@ -43715,9 +43823,9 @@ var require_tmp = __commonJS({
43715
43823
  function _rmdirRecursiveSync(root) {
43716
43824
  const dirs = [root];
43717
43825
  do {
43718
- var dir2 = dirs.pop(), deferred = false, files = fs47.readdirSync(dir2);
43826
+ var dir2 = dirs.pop(), deferred = false, files = fs48.readdirSync(dir2);
43719
43827
  for (var i = 0, length = files.length; i < length; i++) {
43720
- var file2 = path61.join(dir2, files[i]), stat = fs47.lstatSync(file2);
43828
+ var file2 = path62.join(dir2, files[i]), stat = fs48.lstatSync(file2);
43721
43829
  if (stat.isDirectory()) {
43722
43830
  if (!deferred) {
43723
43831
  deferred = true;
@@ -43725,11 +43833,11 @@ var require_tmp = __commonJS({
43725
43833
  }
43726
43834
  dirs.push(file2);
43727
43835
  } else {
43728
- fs47.unlinkSync(file2);
43836
+ fs48.unlinkSync(file2);
43729
43837
  }
43730
43838
  }
43731
43839
  if (!deferred) {
43732
- fs47.rmdirSync(dir2);
43840
+ fs48.rmdirSync(dir2);
43733
43841
  }
43734
43842
  } while (dirs.length !== 0);
43735
43843
  }
@@ -43737,7 +43845,7 @@ var require_tmp = __commonJS({
43737
43845
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1];
43738
43846
  tmpName(opts, function _tmpNameCreated(err, name) {
43739
43847
  if (err) return cb(err);
43740
- fs47.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43848
+ fs48.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43741
43849
  if (err2) return cb(err2);
43742
43850
  cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
43743
43851
  });
@@ -43746,7 +43854,7 @@ var require_tmp = __commonJS({
43746
43854
  function dirSync(options) {
43747
43855
  var args = _parseArguments(options), opts = args[0];
43748
43856
  const name = tmpNameSync(opts);
43749
- fs47.mkdirSync(name, opts.mode || DIR_MODE);
43857
+ fs48.mkdirSync(name, opts.mode || DIR_MODE);
43750
43858
  return {
43751
43859
  name,
43752
43860
  removeCallback: _prepareTmpDirRemoveCallback(name, opts)
@@ -43756,7 +43864,7 @@ var require_tmp = __commonJS({
43756
43864
  const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
43757
43865
  try {
43758
43866
  if (0 <= fdPath[0]) {
43759
- fs47.closeSync(fdPath[0]);
43867
+ fs48.closeSync(fdPath[0]);
43760
43868
  }
43761
43869
  } catch (e) {
43762
43870
  if (!isEBADF(e) && !isENOENT(e)) {
@@ -43764,7 +43872,7 @@ var require_tmp = __commonJS({
43764
43872
  }
43765
43873
  }
43766
43874
  try {
43767
- fs47.unlinkSync(fdPath[1]);
43875
+ fs48.unlinkSync(fdPath[1]);
43768
43876
  } catch (e) {
43769
43877
  if (!isENOENT(e)) {
43770
43878
  throw e;
@@ -43777,7 +43885,7 @@ var require_tmp = __commonJS({
43777
43885
  return removeCallback;
43778
43886
  }
43779
43887
  function _prepareTmpDirRemoveCallback(name, opts) {
43780
- const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs47.rmdirSync.bind(fs47);
43888
+ const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs48.rmdirSync.bind(fs48);
43781
43889
  const removeCallback = _prepareRemoveCallback(removeFunction, name);
43782
43890
  if (!opts.keep) {
43783
43891
  _removeObjects.unshift(removeCallback);
@@ -56910,8 +57018,8 @@ var require_utils = __commonJS({
56910
57018
  }
56911
57019
  return ind;
56912
57020
  }
56913
- function removeDotSegments(path61) {
56914
- let input = path61;
57021
+ function removeDotSegments(path62) {
57022
+ let input = path62;
56915
57023
  const output = [];
56916
57024
  let nextSlash = -1;
56917
57025
  let len = 0;
@@ -57163,8 +57271,8 @@ var require_schemes = __commonJS({
57163
57271
  wsComponent.secure = void 0;
57164
57272
  }
57165
57273
  if (wsComponent.resourceName) {
57166
- const [path61, query] = wsComponent.resourceName.split("?");
57167
- wsComponent.path = path61 && path61 !== "/" ? path61 : void 0;
57274
+ const [path62, query] = wsComponent.resourceName.split("?");
57275
+ wsComponent.path = path62 && path62 !== "/" ? path62 : void 0;
57168
57276
  wsComponent.query = query;
57169
57277
  wsComponent.resourceName = void 0;
57170
57278
  }
@@ -60557,12 +60665,12 @@ var require_dist = __commonJS({
60557
60665
  throw new Error(`Unknown format "${name}"`);
60558
60666
  return f;
60559
60667
  };
60560
- function addFormats(ajv, list, fs47, exportName) {
60668
+ function addFormats(ajv, list, fs48, exportName) {
60561
60669
  var _a2;
60562
60670
  var _b2;
60563
60671
  (_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
60564
60672
  for (const f of list)
60565
- ajv.addFormat(f, fs47[f]);
60673
+ ajv.addFormat(f, fs48[f]);
60566
60674
  }
60567
60675
  module2.exports = exports2 = formatsPlugin;
60568
60676
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -61846,11 +61954,11 @@ var parser = new YargsParser({
61846
61954
  resolve: import_path2.resolve,
61847
61955
  // TODO: figure out a way to combine ESM and CJS coverage, such that
61848
61956
  // we can exercise all the lines below:
61849
- require: (path61) => {
61957
+ require: (path62) => {
61850
61958
  if (typeof require !== "undefined") {
61851
- return require(path61);
61852
- } else if (path61.match(/\.json$/)) {
61853
- return JSON.parse((0, import_fs2.readFileSync)(path61, "utf8"));
61959
+ return require(path62);
61960
+ } else if (path62.match(/\.json$/)) {
61961
+ return JSON.parse((0, import_fs2.readFileSync)(path62, "utf8"));
61854
61962
  } else {
61855
61963
  throw Error("only .json config files are supported in ESM");
61856
61964
  }
@@ -65759,7 +65867,7 @@ function handleRemove(argv) {
65759
65867
  }
65760
65868
 
65761
65869
  // src/cli/commands/env.ts
65762
- var path50 = __toESM(require("path"));
65870
+ var path51 = __toESM(require("path"));
65763
65871
 
65764
65872
  // src/cli/finish-command.ts
65765
65873
  init_sync_context();
@@ -65769,8 +65877,8 @@ async function finishCommand(code) {
65769
65877
  }
65770
65878
 
65771
65879
  // src/core/harness.ts
65772
- var fs36 = __toESM(require("fs"));
65773
- var path41 = __toESM(require("path"));
65880
+ var fs37 = __toESM(require("fs"));
65881
+ var path42 = __toESM(require("path"));
65774
65882
 
65775
65883
  // src/harness/generator.ts
65776
65884
  var fs28 = __toESM(require("fs"));
@@ -65894,9 +66002,485 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
65894
66002
  success("Harness adaptation complete.");
65895
66003
  }
65896
66004
 
65897
- // src/harness/validator.ts
66005
+ // src/harness/agent-md.ts
66006
+ var fs30 = __toESM(require("fs"));
66007
+ var path36 = __toESM(require("path"));
66008
+ init_file_ops();
66009
+ init_logging();
66010
+ init_manifest();
66011
+
66012
+ // src/harness/instruction-files.ts
65898
66013
  var fs29 = __toESM(require("fs"));
66014
+ var os13 = __toESM(require("os"));
65899
66015
  var path35 = __toESM(require("path"));
66016
+ var readline2 = __toESM(require("readline"));
66017
+ init_file_ops();
66018
+ init_logging();
66019
+ var AGENTS_MD = "AGENTS.md";
66020
+ var LEGACY_AGENT_MD = "AGENT.md";
66021
+ var CLAUDE_MD = "CLAUDE.md";
66022
+ var HAR_SECTION_START = "<!-- har:agent-environment:start -->";
66023
+ var HAR_SECTION_END = "<!-- har:agent-environment:end -->";
66024
+ var CLAUDE_HAR_SECTION_START = "<!-- har:claude-pointer:start -->";
66025
+ var CLAUDE_HAR_SECTION_END = "<!-- har:claude-pointer:end -->";
66026
+ var AgentsMdShrinkError = class extends Error {
66027
+ constructor(message) {
66028
+ super(message);
66029
+ this.name = "AgentsMdShrinkError";
66030
+ }
66031
+ };
66032
+ function escapeRegExp(value) {
66033
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
66034
+ }
66035
+ function countNonEmptyLines(text) {
66036
+ return text.split("\n").filter((line) => line.trim().length > 0).length;
66037
+ }
66038
+ function stripClaudePointerFromAgentsMd(content) {
66039
+ if (!content.includes(CLAUDE_HAR_SECTION_START)) return content;
66040
+ const pattern = new RegExp(
66041
+ `${escapeRegExp(CLAUDE_HAR_SECTION_START)}[\\s\\S]*?${escapeRegExp(CLAUDE_HAR_SECTION_END)}\\n?`,
66042
+ "g"
66043
+ );
66044
+ return content.replace(pattern, "").replace(/\n{3,}/g, "\n\n");
66045
+ }
66046
+ function extractOutsideHarSection(content) {
66047
+ const sanitized = stripClaudePointerFromAgentsMd(content);
66048
+ return removeCompleteMarkedBlocks(sanitized, HAR_SECTION_START, HAR_SECTION_END).trim();
66049
+ }
66050
+ function findLastCompleteMarkedBlock(content, startMarker, endMarker) {
66051
+ let last = null;
66052
+ let searchFrom = 0;
66053
+ while (searchFrom < content.length) {
66054
+ const start = content.indexOf(startMarker, searchFrom);
66055
+ if (start === -1) break;
66056
+ const end = content.indexOf(endMarker, start + startMarker.length);
66057
+ if (end === -1) break;
66058
+ const nestedStart = content.indexOf(startMarker, start + startMarker.length);
66059
+ if (nestedStart !== -1 && nestedStart < end) {
66060
+ searchFrom = start + startMarker.length;
66061
+ continue;
66062
+ }
66063
+ last = { start, end: end + endMarker.length };
66064
+ searchFrom = end + endMarker.length;
66065
+ }
66066
+ return last;
66067
+ }
66068
+ function removeCompleteMarkedBlocks(content, startMarker, endMarker) {
66069
+ let result = content;
66070
+ let block = findLastCompleteMarkedBlock(result, startMarker, endMarker);
66071
+ while (block) {
66072
+ result = result.slice(0, block.start) + result.slice(block.end);
66073
+ block = findLastCompleteMarkedBlock(result, startMarker, endMarker);
66074
+ }
66075
+ return result;
66076
+ }
66077
+ function checkOutsideContentPreserved(before, after, options) {
66078
+ const outsideBefore = extractOutsideHarSection(before);
66079
+ const outsideAfter = extractOutsideHarSection(after);
66080
+ const beforeLines = countNonEmptyLines(outsideBefore);
66081
+ const afterLines = countNonEmptyLines(outsideAfter);
66082
+ const minRatio = options.minOutsidePreservationRatio ?? 0.9;
66083
+ if (beforeLines >= 5 && afterLines < beforeLines * minRatio) {
66084
+ return "shrink";
66085
+ }
66086
+ return "ok";
66087
+ }
66088
+ function outsideContentShrinkMessage(beforeLines, afterLines) {
66089
+ 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.`;
66090
+ }
66091
+ function detectInstructionFiles(repoPath) {
66092
+ return {
66093
+ agentsMd: fs29.existsSync(path35.join(repoPath, AGENTS_MD)),
66094
+ agentMd: fs29.existsSync(path35.join(repoPath, LEGACY_AGENT_MD)),
66095
+ claudeMd: fs29.existsSync(path35.join(repoPath, CLAUDE_MD)),
66096
+ cursorDir: fs29.existsSync(path35.join(repoPath, ".cursor")),
66097
+ claudeDir: fs29.existsSync(path35.join(repoPath, ".claude")),
66098
+ codexHome: fs29.existsSync(path35.join(os13.homedir(), ".codex"))
66099
+ };
66100
+ }
66101
+ function formatDetectionReport(detection) {
66102
+ const lines2 = ["Detected:"];
66103
+ lines2.push(` - ${AGENTS_MD} (${detection.agentsMd ? "exists" : "missing"})`);
66104
+ if (detection.agentMd) {
66105
+ lines2.push(` - ${LEGACY_AGENT_MD} (legacy \u2014 will migrate into ${AGENTS_MD})`);
66106
+ }
66107
+ lines2.push(` - ${CLAUDE_MD} (${detection.claudeMd ? "exists" : "missing"})`);
66108
+ lines2.push(` - .cursor/ (${detection.cursorDir ? "exists" : "missing"})`);
66109
+ lines2.push(` - .claude/ (${detection.claudeDir ? "exists" : "missing"})`);
66110
+ lines2.push(` - ~/.codex (${detection.codexHome ? "exists" : "missing"})`);
66111
+ return lines2.join("\n");
66112
+ }
66113
+ function buildInstallPlan(detection, targets, options = {}) {
66114
+ const writeAgentsMd = options.writeAgentsMd !== false;
66115
+ const skillsEnabled = options.skillsEnabled !== false;
66116
+ const cursorExplicit = options.cursorRule;
66117
+ const wantsCursor = cursorExplicit === true || cursorExplicit !== false && (targets.includes("cursor") || detection.cursorDir);
66118
+ return {
66119
+ agentsMd: writeAgentsMd,
66120
+ migrateLegacyAgentMd: writeAgentsMd && detection.agentMd,
66121
+ claudeMd: skillsEnabled && targets.includes("claude"),
66122
+ cursorRule: wantsCursor,
66123
+ skills: skillsEnabled ? targets : []
66124
+ };
66125
+ }
66126
+ function formatInstallPlan(plan, detection) {
66127
+ const mark = (on) => on ? "[x]" : "[ ]";
66128
+ const lines2 = ["After you confirm, HAR will:"];
66129
+ const agentsAction = detection.agentsMd ? `Update ${AGENTS_MD} \u2014 refresh HAR / agent environment section` : `Create ${AGENTS_MD} \u2014 shared HAR workflow (Codex + cross-tool)`;
66130
+ lines2.push(` ${mark(plan.agentsMd)} ${agentsAction}`);
66131
+ if (plan.migrateLegacyAgentMd) {
66132
+ lines2.push(` ${mark(true)} Migrate ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD}, then remove legacy file`);
66133
+ }
66134
+ lines2.push(
66135
+ ` ${mark(plan.claudeMd)} Claude \u2014 ensure ${CLAUDE_MD} points at ${AGENTS_MD}; install .claude/skills if confirmed`
66136
+ );
66137
+ lines2.push(
66138
+ ` ${mark(plan.cursorRule)} Cursor \u2014 install/refresh .cursor/rules/har-workflow.mdc + commands if confirmed`
66139
+ );
66140
+ lines2.push(
66141
+ ` ${mark(plan.skills.includes("codex"))} Codex \u2014 global ~/.codex/prompts (skills); project contract is ${AGENTS_MD}`
66142
+ );
66143
+ return lines2.join("\n");
66144
+ }
66145
+ function loadHarAgentsSectionFromTemplate() {
66146
+ const templatePath = resolveTemplateFile("AGENTS.md.template");
66147
+ if (!templatePath) {
66148
+ throw new Error("AGENTS.md.template not found. Run npm run build.");
66149
+ }
66150
+ const content = fs29.readFileSync(templatePath, "utf8");
66151
+ const start = content.indexOf(HAR_SECTION_START);
66152
+ const end = content.indexOf(HAR_SECTION_END);
66153
+ if (start === -1 || end === -1 || end < start) {
66154
+ throw new Error("AGENTS.md.template is missing har:agent-environment markers.");
66155
+ }
66156
+ return content.slice(start, end + HAR_SECTION_END.length);
66157
+ }
66158
+ function loadAgentsMdTemplate() {
66159
+ const templatePath = resolveTemplateFile("AGENTS.md.template");
66160
+ if (!templatePath) {
66161
+ throw new Error("AGENTS.md.template not found. Run npm run build.");
66162
+ }
66163
+ return fs29.readFileSync(templatePath, "utf8");
66164
+ }
66165
+ function upsertMarkedBlock(content, block, startMarker, endMarker) {
66166
+ const existingBlock = findLastCompleteMarkedBlock(content, startMarker, endMarker);
66167
+ if (existingBlock) {
66168
+ const newContent = content.slice(0, existingBlock.start) + block + content.slice(existingBlock.end);
66169
+ return { content: newContent, action: "updated" };
66170
+ }
66171
+ const suffix = content.endsWith("\n") ? "" : "\n";
66172
+ return { content: `${content}${suffix}
66173
+ ${block}
66174
+ `, action: "appended" };
66175
+ }
66176
+ function mergeAgentsMdContent(existing, incoming) {
66177
+ const sanitizedExisting = stripClaudePointerFromAgentsMd(existing);
66178
+ const sanitizedIncoming = stripClaudePointerFromAgentsMd(incoming);
66179
+ let harSection = loadHarAgentsSectionFromTemplate();
66180
+ if (sanitizedIncoming.includes(HAR_SECTION_START)) {
66181
+ const start = sanitizedIncoming.indexOf(HAR_SECTION_START);
66182
+ const end = sanitizedIncoming.indexOf(HAR_SECTION_END, start + HAR_SECTION_START.length);
66183
+ if (end !== -1) {
66184
+ harSection = sanitizedIncoming.slice(start, end + HAR_SECTION_END.length);
66185
+ }
66186
+ }
66187
+ const { content } = upsertMarkedBlock(
66188
+ sanitizedExisting,
66189
+ harSection,
66190
+ HAR_SECTION_START,
66191
+ HAR_SECTION_END
66192
+ );
66193
+ return content;
66194
+ }
66195
+ function upsertAgentsMdHarSection(repoPath, options = {}) {
66196
+ const dest = path35.join(repoPath, AGENTS_MD);
66197
+ const section = loadHarAgentsSectionFromTemplate();
66198
+ if (!fs29.existsSync(dest)) {
66199
+ writeFileSafe(dest, loadAgentsMdTemplate());
66200
+ return "created";
66201
+ }
66202
+ const existing = fs29.readFileSync(dest, "utf8");
66203
+ const sanitized = stripClaudePointerFromAgentsMd(existing);
66204
+ const { content, action } = upsertMarkedBlock(
66205
+ sanitized,
66206
+ section,
66207
+ HAR_SECTION_START,
66208
+ HAR_SECTION_END
66209
+ );
66210
+ if (checkOutsideContentPreserved(existing, content, options) === "shrink") {
66211
+ const beforeLines = countNonEmptyLines(extractOutsideHarSection(existing));
66212
+ const afterLines = countNonEmptyLines(extractOutsideHarSection(content));
66213
+ const message = outsideContentShrinkMessage(beforeLines, afterLines);
66214
+ if (options.rejectSignificantShrink) {
66215
+ throw new AgentsMdShrinkError(message);
66216
+ }
66217
+ warn(message);
66218
+ return "skipped";
66219
+ }
66220
+ if (content === existing) {
66221
+ return "skipped";
66222
+ }
66223
+ writeFileSafe(dest, content);
66224
+ return action;
66225
+ }
66226
+ function migrateLegacyAgentMd(repoPath) {
66227
+ const legacyPath = path35.join(repoPath, LEGACY_AGENT_MD);
66228
+ const agentsPath = path35.join(repoPath, AGENTS_MD);
66229
+ if (!fs29.existsSync(legacyPath)) return false;
66230
+ const legacy = fs29.readFileSync(legacyPath, "utf8");
66231
+ if (!fs29.existsSync(agentsPath)) {
66232
+ writeFileSafe(agentsPath, legacy);
66233
+ upsertAgentsMdHarSection(repoPath);
66234
+ } else {
66235
+ const agents = fs29.readFileSync(agentsPath, "utf8");
66236
+ const legacyTrimmed = legacy.trim();
66237
+ if (legacyTrimmed.length > 0 && !agents.includes(legacyTrimmed)) {
66238
+ const suffix = agents.endsWith("\n") ? "" : "\n";
66239
+ writeFileSafe(agentsPath, `${agents}${suffix}
66240
+ ${legacyTrimmed}
66241
+ `);
66242
+ }
66243
+ upsertAgentsMdHarSection(repoPath);
66244
+ }
66245
+ fs29.unlinkSync(legacyPath);
66246
+ info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
66247
+ return true;
66248
+ }
66249
+ function loadClaudeMdTemplate(projectName) {
66250
+ const templatePath = resolveTemplateFile("CLAUDE.md.template");
66251
+ if (!templatePath) {
66252
+ throw new Error("CLAUDE.md.template not found. Run npm run build.");
66253
+ }
66254
+ const displayName = projectName.replace(/_/g, " ");
66255
+ return fs29.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
66256
+ }
66257
+ function isThinClaudePointer(content) {
66258
+ const trimmed = content.trim();
66259
+ if (trimmed.length > 600) return false;
66260
+ return /AGENTS\.md|AGENT\.md/.test(trimmed) && (trimmed.includes(".har/README.md") || trimmed.includes("har-workflow"));
66261
+ }
66262
+ var CLAUDE_POINTER_BLOCK = `${CLAUDE_HAR_SECTION_START}
66263
+ ## HAR
66264
+
66265
+ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
66266
+ [\`.har/README.md\`](./.har/README.md) before making changes.
66267
+ ${CLAUDE_HAR_SECTION_END}`;
66268
+ function ensureClaudeMdPointer(repoPath, options = {}) {
66269
+ const dest = path35.join(repoPath, CLAUDE_MD);
66270
+ const projectName = path35.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66271
+ const thin = loadClaudeMdTemplate(projectName);
66272
+ if (!fs29.existsSync(dest)) {
66273
+ writeFileSafe(dest, thin);
66274
+ return "created";
66275
+ }
66276
+ const existing = fs29.readFileSync(dest, "utf8");
66277
+ if (isThinClaudePointer(existing) || options.force) {
66278
+ writeFileSafe(dest, thin);
66279
+ return "updated";
66280
+ }
66281
+ if (existing.includes(CLAUDE_HAR_SECTION_START) || /\[AGENTS\.md\]/.test(existing)) {
66282
+ if (existing.includes(CLAUDE_HAR_SECTION_START)) {
66283
+ const { content: content2, action: action2 } = upsertMarkedBlock(
66284
+ existing,
66285
+ CLAUDE_POINTER_BLOCK,
66286
+ CLAUDE_HAR_SECTION_START,
66287
+ CLAUDE_HAR_SECTION_END
66288
+ );
66289
+ writeFileSafe(dest, content2);
66290
+ return action2;
66291
+ }
66292
+ return "skipped";
66293
+ }
66294
+ const { content, action } = upsertMarkedBlock(
66295
+ existing,
66296
+ CLAUDE_POINTER_BLOCK,
66297
+ CLAUDE_HAR_SECTION_START,
66298
+ CLAUDE_HAR_SECTION_END
66299
+ );
66300
+ writeFileSafe(dest, content);
66301
+ return action;
66302
+ }
66303
+ async function askYesNo2(question, defaultYes = true) {
66304
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
66305
+ return new Promise((resolve47) => {
66306
+ process.stderr.write(`${question} `);
66307
+ rl.once("line", (answer) => {
66308
+ rl.close();
66309
+ const trimmed = answer.trim();
66310
+ if (trimmed === "") {
66311
+ resolve47(defaultYes);
66312
+ return;
66313
+ }
66314
+ resolve47(/^y(es)?$/i.test(trimmed));
66315
+ });
66316
+ });
66317
+ }
66318
+ async function handleInstructionFiles(options) {
66319
+ const { repoPath, mode } = options;
66320
+ const writeAgentsMd = options.writeAgentsMd !== false;
66321
+ const skillsEnabled = options.enabled !== false;
66322
+ const detection = detectInstructionFiles(repoPath);
66323
+ let targets;
66324
+ if (!skillsEnabled) {
66325
+ targets = [];
66326
+ } else if (typeof options.agents === "string") {
66327
+ targets = parseAgentTargets(options.agents);
66328
+ } else {
66329
+ targets = detectAgentTargets(repoPath);
66330
+ }
66331
+ if (skillsEnabled && targets.length === 0 && mode === "init" && typeof options.agents !== "string" && !options.autoYes) {
66332
+ targets = [...AGENT_SKILL_TARGETS];
66333
+ }
66334
+ let plan = buildInstallPlan(detection, targets, {
66335
+ writeAgentsMd,
66336
+ cursorRule: options.cursorRule,
66337
+ skillsEnabled
66338
+ });
66339
+ divider();
66340
+ process.stderr.write(`${formatDetectionReport(detection)}
66341
+
66342
+ `);
66343
+ process.stderr.write(`${formatInstallPlan(plan, detection)}
66344
+ `);
66345
+ divider();
66346
+ const shouldPrompt = !options.autoYes && skillsEnabled && typeof options.agents !== "string" && !(mode === "maintain" && targets.length > 0 && !detection.agentMd);
66347
+ if (shouldPrompt && targets.length > 0) {
66348
+ const accepted = await askYesNo2(
66349
+ `Install HAR agent instructions for: ${targets.join(", ")}? [Y/n]`
66350
+ );
66351
+ if (!accepted) {
66352
+ info("Skipped agent instruction adapters (AGENTS.md will still be updated)");
66353
+ targets = [];
66354
+ plan = buildInstallPlan(detection, targets, {
66355
+ writeAgentsMd,
66356
+ cursorRule: options.cursorRule === true ? true : false,
66357
+ skillsEnabled: false
66358
+ });
66359
+ }
66360
+ }
66361
+ let migratedLegacy = false;
66362
+ let agentsMdAction = null;
66363
+ let claudeMdAction = null;
66364
+ if (writeAgentsMd) {
66365
+ if (detection.agentMd) {
66366
+ migratedLegacy = migrateLegacyAgentMd(repoPath);
66367
+ }
66368
+ agentsMdAction = upsertAgentsMdHarSection(repoPath, {
66369
+ rejectSignificantShrink: options.finalize === true
66370
+ });
66371
+ if (agentsMdAction === "created") {
66372
+ success(`Wrote ${AGENTS_MD}`);
66373
+ } else if (agentsMdAction === "updated" || agentsMdAction === "appended") {
66374
+ info(
66375
+ `${agentsMdAction === "updated" ? "Refreshed" : "Appended"} HAR section in ${AGENTS_MD}`
66376
+ );
66377
+ } else if (agentsMdAction === "skipped" && options.finalize) {
66378
+ warn(
66379
+ `${AGENTS_MD} left unchanged \u2014 project-specific content outside har:agent-environment markers was preserved.`
66380
+ );
66381
+ }
66382
+ } else {
66383
+ agentsMdAction = "skipped";
66384
+ }
66385
+ if (plan.claudeMd) {
66386
+ claudeMdAction = ensureClaudeMdPointer(repoPath);
66387
+ if (claudeMdAction === "created") {
66388
+ success(`Wrote ${CLAUDE_MD} (pointer \u2192 ${AGENTS_MD})`);
66389
+ } else if (claudeMdAction === "updated" || claudeMdAction === "appended") {
66390
+ info(
66391
+ `${claudeMdAction === "updated" ? "Updated" : "Appended"} ${CLAUDE_MD} pointer \u2192 ${AGENTS_MD}`
66392
+ );
66393
+ }
66394
+ } else {
66395
+ claudeMdAction = "skipped";
66396
+ }
66397
+ return {
66398
+ detection,
66399
+ plan,
66400
+ targets,
66401
+ agentsMdAction,
66402
+ migratedLegacy,
66403
+ claudeMdAction
66404
+ };
66405
+ }
66406
+
66407
+ // src/harness/agent-md.ts
66408
+ var AGENTS_MD_PROPOSAL = "AGENTS.md.proposed";
66409
+ var AGENTS_MD_PROPOSAL_META = "AGENTS.md.proposed.meta.json";
66410
+ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
66411
+ var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
66412
+ function readAgentMdProposal(repoPath) {
66413
+ const harnessDir = getHarnessDir(repoPath);
66414
+ const proposalPath = path36.join(harnessDir, AGENTS_MD_PROPOSAL);
66415
+ const metaPath = path36.join(harnessDir, AGENTS_MD_PROPOSAL_META);
66416
+ const legacyProposalPath = path36.join(harnessDir, AGENT_MD_PROPOSAL);
66417
+ const legacyMetaPath = path36.join(harnessDir, AGENT_MD_PROPOSAL_META);
66418
+ const resolvedProposal = fs30.existsSync(proposalPath) ? proposalPath : fs30.existsSync(legacyProposalPath) ? legacyProposalPath : null;
66419
+ if (!resolvedProposal) return null;
66420
+ const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
66421
+ const content = fs30.readFileSync(resolvedProposal, "utf8");
66422
+ let rationale = "";
66423
+ let createdAt = (/* @__PURE__ */ new Date()).toISOString();
66424
+ if (fs30.existsSync(resolvedMeta)) {
66425
+ try {
66426
+ const meta = JSON.parse(fs30.readFileSync(resolvedMeta, "utf8"));
66427
+ rationale = meta.rationale ?? "";
66428
+ createdAt = meta.createdAt ?? createdAt;
66429
+ } catch {
66430
+ rationale = "";
66431
+ }
66432
+ }
66433
+ return { content, rationale, createdAt };
66434
+ }
66435
+ function clearAgentMdProposal(repoPath) {
66436
+ const harnessDir = getHarnessDir(repoPath);
66437
+ for (const file of [
66438
+ AGENTS_MD_PROPOSAL,
66439
+ AGENTS_MD_PROPOSAL_META,
66440
+ AGENT_MD_PROPOSAL,
66441
+ AGENT_MD_PROPOSAL_META
66442
+ ]) {
66443
+ const p = path36.join(harnessDir, file);
66444
+ if (fs30.existsSync(p)) fs30.unlinkSync(p);
66445
+ }
66446
+ }
66447
+ function wouldProposalShrinkExisting(existing, proposal) {
66448
+ const outsideExisting = extractOutsideHarSection(existing);
66449
+ const outsideMerged = extractOutsideHarSection(mergeAgentsMdContent(existing, proposal));
66450
+ const existingLines = outsideExisting.split("\n").filter((l) => l.trim()).length;
66451
+ const mergedLines = outsideMerged.split("\n").filter((l) => l.trim()).length;
66452
+ return existingLines >= 5 && mergedLines < existingLines * 0.9;
66453
+ }
66454
+ function applyAgentMdProposalMerge(repoPath, options = {}) {
66455
+ const proposal = readAgentMdProposal(repoPath);
66456
+ if (!proposal) return false;
66457
+ const agentsMdPath = path36.join(repoPath, AGENTS_MD);
66458
+ if (fs30.existsSync(agentsMdPath)) {
66459
+ const existing = fs30.readFileSync(agentsMdPath, "utf8");
66460
+ if (wouldProposalShrinkExisting(existing, proposal.content)) {
66461
+ 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.`;
66462
+ if (options.rejectSignificantShrink) {
66463
+ throw new AgentsMdShrinkError(message);
66464
+ }
66465
+ warn(message);
66466
+ return false;
66467
+ }
66468
+ writeFileSafe(agentsMdPath, mergeAgentsMdContent(existing, proposal.content));
66469
+ } else {
66470
+ writeFileSafe(agentsMdPath, proposal.content);
66471
+ }
66472
+ clearAgentMdProposal(repoPath);
66473
+ info(`Merged ${AGENTS_MD} proposal into repo root (preserved content outside managed markers)`);
66474
+ return true;
66475
+ }
66476
+ function finalizeAgentsMdInstructionFiles(repoPath) {
66477
+ applyAgentMdProposalMerge(repoPath, { rejectSignificantShrink: true });
66478
+ upsertAgentsMdHarSection(repoPath, { rejectSignificantShrink: true });
66479
+ }
66480
+
66481
+ // src/harness/validator.ts
66482
+ var fs31 = __toESM(require("fs"));
66483
+ var path37 = __toESM(require("path"));
65900
66484
  init_shell();
65901
66485
  init_manifest();
65902
66486
  init_stages();
@@ -65951,22 +66535,22 @@ var SHELL_SCRIPTS = [
65951
66535
  function validateHarness(repoPath) {
65952
66536
  const harnessDir = getHarnessDir(repoPath);
65953
66537
  const issues = [];
65954
- if (!fs29.existsSync(harnessDir)) {
66538
+ if (!fs31.existsSync(harnessDir)) {
65955
66539
  return {
65956
66540
  pass: false,
65957
66541
  issues: [{ file: ".har", message: "Harness directory not found", severity: "error" }]
65958
66542
  };
65959
66543
  }
65960
66544
  for (const file of getRequiredFiles(repoPath)) {
65961
- const filePath = path35.join(harnessDir, file);
65962
- if (!fs29.existsSync(filePath)) {
66545
+ const filePath = path37.join(harnessDir, file);
66546
+ if (!fs31.existsSync(filePath)) {
65963
66547
  issues.push({ file, message: "Required file missing", severity: "error" });
65964
66548
  }
65965
66549
  }
65966
66550
  for (const script of SHELL_SCRIPTS) {
65967
- const scriptPath = path35.join(harnessDir, script);
65968
- if (!fs29.existsSync(scriptPath)) continue;
65969
- const stat = fs29.statSync(scriptPath);
66551
+ const scriptPath = path37.join(harnessDir, script);
66552
+ if (!fs31.existsSync(scriptPath)) continue;
66553
+ const stat = fs31.statSync(scriptPath);
65970
66554
  if (!(stat.mode & 73)) {
65971
66555
  issues.push({ file: script, message: "Script is not executable", severity: "warning" });
65972
66556
  }
@@ -65981,9 +66565,9 @@ function validateHarness(repoPath) {
65981
66565
  }
65982
66566
  const manifest = readManifest(repoPath);
65983
66567
  const profile = manifest?.profile ?? "default";
65984
- const ecosystemPath = path35.join(harnessDir, "ecosystem.agent.template.cjs");
65985
- if (profile !== "cli" && fs29.existsSync(ecosystemPath)) {
65986
- const content = fs29.readFileSync(ecosystemPath, "utf8");
66568
+ const ecosystemPath = path37.join(harnessDir, "ecosystem.agent.template.cjs");
66569
+ if (profile !== "cli" && fs31.existsSync(ecosystemPath)) {
66570
+ const content = fs31.readFileSync(ecosystemPath, "utf8");
65987
66571
  if (!content.includes("module.exports")) {
65988
66572
  issues.push({
65989
66573
  file: "ecosystem.agent.template.cjs",
@@ -65992,9 +66576,9 @@ function validateHarness(repoPath) {
65992
66576
  });
65993
66577
  }
65994
66578
  }
65995
- const harnessEnvPath = path35.join(harnessDir, "harness.env");
65996
- if (fs29.existsSync(harnessEnvPath)) {
65997
- const content = fs29.readFileSync(harnessEnvPath, "utf8");
66579
+ const harnessEnvPath = path37.join(harnessDir, "harness.env");
66580
+ if (fs31.existsSync(harnessEnvPath)) {
66581
+ const content = fs31.readFileSync(harnessEnvPath, "utf8");
65998
66582
  if (content.includes("TODO: set migrate command")) {
65999
66583
  issues.push({ file: "harness.env", message: "Migrate command still has TODO", severity: "warning" });
66000
66584
  }
@@ -66002,17 +66586,17 @@ function validateHarness(repoPath) {
66002
66586
  issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
66003
66587
  }
66004
66588
  }
66005
- const verifyPath = path35.join(harnessDir, "verify.sh");
66006
- if (fs29.existsSync(verifyPath)) {
66007
- const content = fs29.readFileSync(verifyPath, "utf8");
66589
+ const verifyPath = path37.join(harnessDir, "verify.sh");
66590
+ if (fs31.existsSync(verifyPath)) {
66591
+ const content = fs31.readFileSync(verifyPath, "utf8");
66008
66592
  if (content.includes("echo 'TODO:")) {
66009
66593
  issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
66010
66594
  }
66011
66595
  }
66012
- const stagesPath = path35.join(harnessDir, "stages.json");
66013
- if (fs29.existsSync(stagesPath)) {
66596
+ const stagesPath = path37.join(harnessDir, "stages.json");
66597
+ if (fs31.existsSync(stagesPath)) {
66014
66598
  try {
66015
- JSON.parse(fs29.readFileSync(stagesPath, "utf8"));
66599
+ JSON.parse(fs31.readFileSync(stagesPath, "utf8"));
66016
66600
  const registry2 = readStageRegistry(repoPath);
66017
66601
  if (registry2.stages.length === 0) {
66018
66602
  issues.push({ file: "stages.json", message: "No harness stages declared", severity: "warning" });
@@ -66027,9 +66611,9 @@ function validateHarness(repoPath) {
66027
66611
  } else {
66028
66612
  issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
66029
66613
  }
66030
- const readmePath = path35.join(harnessDir, "README.md");
66031
- if (fs29.existsSync(readmePath)) {
66032
- const content = fs29.readFileSync(readmePath, "utf8");
66614
+ const readmePath = path37.join(harnessDir, "README.md");
66615
+ if (fs31.existsSync(readmePath)) {
66616
+ const content = fs31.readFileSync(readmePath, "utf8");
66033
66617
  if (!content.includes(".har")) {
66034
66618
  issues.push({ file: "README.md", message: "README should document .har/ paths", severity: "warning" });
66035
66619
  }
@@ -66043,8 +66627,8 @@ function validateHarness(repoPath) {
66043
66627
  async function smokeTestHarness(repoPath) {
66044
66628
  const harnessDir = getHarnessDir(repoPath);
66045
66629
  const issues = [];
66046
- const setupScript = path35.join(harnessDir, "setup-infra.sh");
66047
- if (fs29.existsSync(setupScript)) {
66630
+ const setupScript = path37.join(harnessDir, "setup-infra.sh");
66631
+ if (fs31.existsSync(setupScript)) {
66048
66632
  const result = run(`bash "${setupScript}"`, { cwd: repoPath });
66049
66633
  if (result.code !== 0) {
66050
66634
  issues.push({
@@ -66059,8 +66643,8 @@ async function smokeTestHarness(repoPath) {
66059
66643
  }
66060
66644
 
66061
66645
  // src/harness/drift.ts
66062
- var fs30 = __toESM(require("fs"));
66063
- var path36 = __toESM(require("path"));
66646
+ var fs32 = __toESM(require("fs"));
66647
+ var path38 = __toESM(require("path"));
66064
66648
  init_env();
66065
66649
  init_manifest();
66066
66650
  init_stages();
@@ -66131,16 +66715,16 @@ function substituteProjectName(content, projectName) {
66131
66715
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
66132
66716
  }
66133
66717
  function listBoilerplateFiles(boilerplateDir) {
66134
- if (!fs30.existsSync(boilerplateDir)) return [];
66135
- return fs30.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
66718
+ if (!fs32.existsSync(boilerplateDir)) return [];
66719
+ return fs32.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
66136
66720
  }
66137
66721
  function compareHarnessToTemplate(repoPath) {
66138
- const resolved = path36.resolve(repoPath);
66722
+ const resolved = path38.resolve(repoPath);
66139
66723
  const manifest = readManifest(resolved);
66140
66724
  const profile = manifest?.profile ?? "default";
66141
66725
  const harnessDir = getHarnessDir(resolved);
66142
- const projectName = path36.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
66143
- const boilerplateDir = path36.join(resolveTemplatesDir(), PROFILE_DIRS2[profile]);
66726
+ const projectName = path38.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
66727
+ const boilerplateDir = path38.join(resolveTemplatesDir(), PROFILE_DIRS2[profile]);
66144
66728
  const templateFiles = listBoilerplateFiles(boilerplateDir);
66145
66729
  const missing = [];
66146
66730
  const checksumMismatch = [];
@@ -66148,17 +66732,17 @@ function compareHarnessToTemplate(repoPath) {
66148
66732
  const unchanged = [];
66149
66733
  for (const file of templateFiles) {
66150
66734
  const harnessFile = harnessFileForTemplate(file);
66151
- const templatePath = path36.join(boilerplateDir, file);
66152
- const harnessPath = path36.join(harnessDir, harnessFile);
66153
- let templateContent = fs30.readFileSync(templatePath, "utf8");
66735
+ const templatePath = path38.join(boilerplateDir, file);
66736
+ const harnessPath = path38.join(harnessDir, harnessFile);
66737
+ let templateContent = fs32.readFileSync(templatePath, "utf8");
66154
66738
  if (file === "harness.env") {
66155
66739
  templateContent = substituteProjectName(templateContent, projectName);
66156
66740
  }
66157
- if (!fs30.existsSync(harnessPath)) {
66741
+ if (!fs32.existsSync(harnessPath)) {
66158
66742
  missing.push(harnessFile);
66159
66743
  continue;
66160
66744
  }
66161
- const harnessChecksum = computeFileChecksum(fs30.readFileSync(harnessPath, "utf8"));
66745
+ const harnessChecksum = computeFileChecksum(fs32.readFileSync(harnessPath, "utf8"));
66162
66746
  const templateChecksum = computeFileChecksum(templateContent);
66163
66747
  if (harnessChecksum === templateChecksum) {
66164
66748
  unchanged.push(harnessFile);
@@ -66166,10 +66750,10 @@ function compareHarnessToTemplate(repoPath) {
66166
66750
  checksumMismatch.push(harnessFile);
66167
66751
  }
66168
66752
  }
66169
- if (fs30.existsSync(harnessDir)) {
66170
- for (const file of fs30.readdirSync(harnessDir)) {
66171
- const full = path36.join(harnessDir, file);
66172
- if (!fs30.statSync(full).isFile()) continue;
66753
+ if (fs32.existsSync(harnessDir)) {
66754
+ for (const file of fs32.readdirSync(harnessDir)) {
66755
+ const full = path38.join(harnessDir, file);
66756
+ if (!fs32.statSync(full).isFile()) continue;
66173
66757
  if (file === "manifest.json" || file.startsWith("ADAPT-PROMPT")) continue;
66174
66758
  if (profile === "cli" && CLI_EXPECTED_ABSENT.has(file)) {
66175
66759
  extra.push(file);
@@ -66200,29 +66784,29 @@ function compareHarnessToTemplate(repoPath) {
66200
66784
  }
66201
66785
 
66202
66786
  // src/harness/maintain-bundle.ts
66203
- var fs35 = __toESM(require("fs"));
66787
+ var fs36 = __toESM(require("fs"));
66204
66788
  var os14 = __toESM(require("os"));
66205
- var path40 = __toESM(require("path"));
66789
+ var path41 = __toESM(require("path"));
66206
66790
  init_file_ops();
66207
66791
  init_shell();
66208
66792
  init_manifest();
66209
66793
 
66210
66794
  // src/harness/plugin-drift.ts
66211
- var fs33 = __toESM(require("fs"));
66212
- var path38 = __toESM(require("path"));
66795
+ var fs35 = __toESM(require("fs"));
66796
+ var path40 = __toESM(require("path"));
66213
66797
  init_manifest();
66214
66798
 
66215
66799
  // src/harness/plugins.ts
66216
- var fs32 = __toESM(require("fs"));
66217
- var path37 = __toESM(require("path"));
66800
+ var fs34 = __toESM(require("fs"));
66801
+ var path39 = __toESM(require("path"));
66218
66802
  init_zod();
66219
66803
  init_logging();
66220
66804
 
66221
66805
  // src/harness/parser.ts
66222
- var fs31 = __toESM(require("fs"));
66806
+ var fs33 = __toESM(require("fs"));
66223
66807
  init_manifest();
66224
66808
  function harnessExists(repoPath) {
66225
- return fs31.existsSync(`${repoPath}/.har/setup-infra.sh`);
66809
+ return fs33.existsSync(`${repoPath}/.har/setup-infra.sh`);
66226
66810
  }
66227
66811
 
66228
66812
  // src/harness/plugins.ts
@@ -66247,16 +66831,16 @@ var PluginManifestSchema = external_exports.object({
66247
66831
  docsPath: external_exports.string().min(1)
66248
66832
  });
66249
66833
  function resolvePluginDir(pluginId) {
66250
- const dir = path37.join(resolveTemplatesDir(), "plugins", pluginId);
66251
- if (!fs32.existsSync(dir)) {
66834
+ const dir = path39.join(resolveTemplatesDir(), "plugins", pluginId);
66835
+ if (!fs34.existsSync(dir)) {
66252
66836
  throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
66253
66837
  }
66254
66838
  return dir;
66255
66839
  }
66256
66840
  function readPluginManifest(pluginId) {
66257
- const manifestPath = path37.join(resolvePluginDir(pluginId), "template.manifest.json");
66841
+ const manifestPath = path39.join(resolvePluginDir(pluginId), "template.manifest.json");
66258
66842
  const parsed = PluginManifestSchema.safeParse(
66259
- JSON.parse(fs32.readFileSync(manifestPath, "utf8"))
66843
+ JSON.parse(fs34.readFileSync(manifestPath, "utf8"))
66260
66844
  );
66261
66845
  if (!parsed.success) {
66262
66846
  throw new Error(`Invalid plugin manifest for ${pluginId}: ${parsed.error.message}`);
@@ -66267,40 +66851,40 @@ function readPluginManifest(pluginId) {
66267
66851
  return parsed.data;
66268
66852
  }
66269
66853
  function ensureParentDir(filePath) {
66270
- const parent = path37.dirname(filePath);
66271
- if (!fs32.existsSync(parent)) {
66272
- fs32.mkdirSync(parent, { recursive: true });
66854
+ const parent = path39.dirname(filePath);
66855
+ if (!fs34.existsSync(parent)) {
66856
+ fs34.mkdirSync(parent, { recursive: true });
66273
66857
  }
66274
66858
  }
66275
66859
  function copyPluginFile(pluginDir, file, repoPath, force) {
66276
- const srcPath = path37.join(pluginDir, file.src);
66277
- const destPath = path37.join(repoPath, file.dest);
66278
- if (!fs32.existsSync(srcPath)) {
66860
+ const srcPath = path39.join(pluginDir, file.src);
66861
+ const destPath = path39.join(repoPath, file.dest);
66862
+ if (!fs34.existsSync(srcPath)) {
66279
66863
  throw new Error(`Plugin file missing: ${file.src}`);
66280
66864
  }
66281
- if (fs32.existsSync(destPath) && !force) {
66865
+ if (fs34.existsSync(destPath) && !force) {
66282
66866
  throw new Error(
66283
66867
  `File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
66284
66868
  );
66285
66869
  }
66286
66870
  ensureParentDir(destPath);
66287
- fs32.copyFileSync(srcPath, destPath);
66871
+ fs34.copyFileSync(srcPath, destPath);
66288
66872
  if (file.executable) {
66289
- fs32.chmodSync(destPath, 493);
66873
+ fs34.chmodSync(destPath, 493);
66290
66874
  }
66291
66875
  return { written: true, path: file.dest };
66292
66876
  }
66293
66877
  function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
66294
- const packagePath = path37.join(repoPath, "package.json");
66295
- if (!fs32.existsSync(packagePath)) {
66878
+ const packagePath = path39.join(repoPath, "package.json");
66879
+ if (!fs34.existsSync(packagePath)) {
66296
66880
  throw new Error("No package.json in repo root. Add one before applying this plugin.");
66297
66881
  }
66298
- const fragmentPath = path37.join(pluginDir, fragmentRelPath);
66299
- if (!fs32.existsSync(fragmentPath)) {
66882
+ const fragmentPath = path39.join(pluginDir, fragmentRelPath);
66883
+ if (!fs34.existsSync(fragmentPath)) {
66300
66884
  throw new Error(`Package fragment missing: ${fragmentRelPath}`);
66301
66885
  }
66302
- const pkg = JSON.parse(fs32.readFileSync(packagePath, "utf8"));
66303
- const fragment = JSON.parse(fs32.readFileSync(fragmentPath, "utf8"));
66886
+ const pkg = JSON.parse(fs34.readFileSync(packagePath, "utf8"));
66887
+ const fragment = JSON.parse(fs34.readFileSync(fragmentPath, "utf8"));
66304
66888
  for (const section of ["scripts", "devDependencies"]) {
66305
66889
  const existing = pkg[section] ?? {};
66306
66890
  const incoming = fragment[section] ?? {};
@@ -66313,7 +66897,7 @@ function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
66313
66897
  }
66314
66898
  pkg[section] = existing;
66315
66899
  }
66316
- fs32.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
66900
+ fs34.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
66317
66901
  }
66318
66902
  function patchStageRegistry(repoPath, manifest, force) {
66319
66903
  const registry2 = readStageRegistry(repoPath);
@@ -66353,8 +66937,8 @@ function assertHarnessPresent(repoPath) {
66353
66937
  }
66354
66938
  function assertStageNotPresent(repoPath, stageId, force) {
66355
66939
  if (force) return;
66356
- const scriptPath = path37.join(repoPath, ".har", "stages", `${stageId}.sh`);
66357
- if (fs32.existsSync(scriptPath)) {
66940
+ const scriptPath = path39.join(repoPath, ".har", "stages", `${stageId}.sh`);
66941
+ if (fs34.existsSync(scriptPath)) {
66358
66942
  throw new Error(
66359
66943
  `Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
66360
66944
  );
@@ -66367,7 +66951,7 @@ function assertStageNotPresent(repoPath, stageId, force) {
66367
66951
  }
66368
66952
  }
66369
66953
  function applyPlugin(repoPath, pluginId, options = {}) {
66370
- const resolved = path37.resolve(repoPath);
66954
+ const resolved = path39.resolve(repoPath);
66371
66955
  const force = options.force ?? false;
66372
66956
  const warnings = [];
66373
66957
  const filesWritten = [];
@@ -66386,7 +66970,7 @@ function applyPlugin(repoPath, pluginId, options = {}) {
66386
66970
  if (file.skipFlag === "skipCi" && options.skipCi) {
66387
66971
  continue;
66388
66972
  }
66389
- if (fs32.existsSync(path37.join(resolved, file.dest)) && !force) {
66973
+ if (fs34.existsSync(path39.join(resolved, file.dest)) && !force) {
66390
66974
  warnings.push(`Skipped optional file (exists): ${file.dest}`);
66391
66975
  continue;
66392
66976
  }
@@ -66421,18 +67005,18 @@ function applyPlugin(repoPath, pluginId, options = {}) {
66421
67005
  };
66422
67006
  }
66423
67007
  function listPluginIds() {
66424
- const root = path37.join(resolveTemplatesDir(), "plugins");
66425
- if (!fs32.existsSync(root)) return [...PLUGIN_IDS];
66426
- return fs32.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
67008
+ const root = path39.join(resolveTemplatesDir(), "plugins");
67009
+ if (!fs34.existsSync(root)) return [...PLUGIN_IDS];
67010
+ return fs34.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
66427
67011
  }
66428
67012
 
66429
67013
  // src/harness/plugin-drift.ts
66430
67014
  init_stages();
66431
67015
  var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
66432
67016
  function detectInstalledPlugins(repoPath) {
66433
- const resolved = path38.resolve(repoPath);
66434
- const registryPath = path38.join(resolved, ".har", "stages.json");
66435
- if (!fs33.existsSync(registryPath)) return [];
67017
+ const resolved = path40.resolve(repoPath);
67018
+ const registryPath = path40.join(resolved, ".har", "stages.json");
67019
+ if (!fs35.existsSync(registryPath)) return [];
66436
67020
  const registry2 = readStageRegistry(resolved);
66437
67021
  const stageIds = new Set(registry2.stages.map((stage) => stage.id));
66438
67022
  const installed = [];
@@ -66445,17 +67029,17 @@ function detectInstalledPlugins(repoPath) {
66445
67029
  return installed;
66446
67030
  }
66447
67031
  function pluginTemplatePath(pluginId, srcRel) {
66448
- return path38.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
67032
+ return path40.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
66449
67033
  }
66450
67034
  function readBundledPluginFile(pluginId, srcRel) {
66451
- return fs33.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
67035
+ return fs35.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
66452
67036
  }
66453
67037
  function listPluginDestPaths(pluginId, repoPath) {
66454
67038
  const manifest = readPluginManifest(pluginId);
66455
67039
  const paths = manifest.files.map((file) => file.dest);
66456
67040
  if (manifest.optionalFiles) {
66457
67041
  for (const file of manifest.optionalFiles) {
66458
- if (fs33.existsSync(path38.join(repoPath, file.dest))) {
67042
+ if (fs35.existsSync(path40.join(repoPath, file.dest))) {
66459
67043
  paths.push(file.dest);
66460
67044
  }
66461
67045
  }
@@ -66514,9 +67098,9 @@ function readTemplatePluginFile(pluginId, dest) {
66514
67098
  return null;
66515
67099
  }
66516
67100
  function readInstalledPluginFile(repoPath, pluginId, dest) {
66517
- const installedPath = path38.join(path38.resolve(repoPath), dest);
66518
- if (!fs33.existsSync(installedPath)) return null;
66519
- const content = fs33.readFileSync(installedPath, "utf8");
67101
+ const installedPath = path40.join(path40.resolve(repoPath), dest);
67102
+ if (!fs35.existsSync(installedPath)) return null;
67103
+ const content = fs35.readFileSync(installedPath, "utf8");
66520
67104
  const manifest = readPluginManifest(pluginId);
66521
67105
  const fragmentRel = manifest.merge?.[dest];
66522
67106
  if (fragmentRel) {
@@ -66535,7 +67119,7 @@ function pluginActionHint(pluginId, dest, kind) {
66535
67119
  }
66536
67120
  function comparePluginToTemplate(repoPath, pluginId) {
66537
67121
  const manifest = readPluginManifest(pluginId);
66538
- const resolved = path38.resolve(repoPath);
67122
+ const resolved = path40.resolve(repoPath);
66539
67123
  const destPaths = listPluginDestPaths(pluginId, resolved);
66540
67124
  const missing = [];
66541
67125
  const checksumMismatch = [];
@@ -66550,8 +67134,8 @@ function comparePluginToTemplate(repoPath, pluginId) {
66550
67134
  }
66551
67135
  if (dest === "package.json") {
66552
67136
  const fragmentRel = manifest.merge?.[dest];
66553
- const installedPath = path38.join(resolved, dest);
66554
- const installedRaw = fs33.readFileSync(installedPath, "utf8");
67137
+ const installedPath = path40.join(resolved, dest);
67138
+ const installedRaw = fs35.readFileSync(installedPath, "utf8");
66555
67139
  if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
66556
67140
  unchanged.push(dest);
66557
67141
  } else if (computeFileChecksum(installedContent) === computeFileChecksum(templateContent)) {
@@ -66609,293 +67193,6 @@ function buildPluginDriftActions(repoPath, pluginDrift) {
66609
67193
  );
66610
67194
  }
66611
67195
 
66612
- // src/harness/instruction-files.ts
66613
- var fs34 = __toESM(require("fs"));
66614
- var os13 = __toESM(require("os"));
66615
- var path39 = __toESM(require("path"));
66616
- var readline2 = __toESM(require("readline"));
66617
- init_file_ops();
66618
- init_logging();
66619
- var AGENTS_MD = "AGENTS.md";
66620
- var LEGACY_AGENT_MD = "AGENT.md";
66621
- var CLAUDE_MD = "CLAUDE.md";
66622
- var HAR_SECTION_START = "<!-- har:agent-environment:start -->";
66623
- var HAR_SECTION_END = "<!-- har:agent-environment:end -->";
66624
- var CLAUDE_HAR_SECTION_START = "<!-- har:claude-pointer:start -->";
66625
- var CLAUDE_HAR_SECTION_END = "<!-- har:claude-pointer:end -->";
66626
- function escapeRegExp(value) {
66627
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
66628
- }
66629
- function detectInstructionFiles(repoPath) {
66630
- return {
66631
- agentsMd: fs34.existsSync(path39.join(repoPath, AGENTS_MD)),
66632
- agentMd: fs34.existsSync(path39.join(repoPath, LEGACY_AGENT_MD)),
66633
- claudeMd: fs34.existsSync(path39.join(repoPath, CLAUDE_MD)),
66634
- cursorDir: fs34.existsSync(path39.join(repoPath, ".cursor")),
66635
- claudeDir: fs34.existsSync(path39.join(repoPath, ".claude")),
66636
- codexHome: fs34.existsSync(path39.join(os13.homedir(), ".codex"))
66637
- };
66638
- }
66639
- function formatDetectionReport(detection) {
66640
- const lines2 = ["Detected:"];
66641
- lines2.push(` - ${AGENTS_MD} (${detection.agentsMd ? "exists" : "missing"})`);
66642
- if (detection.agentMd) {
66643
- lines2.push(` - ${LEGACY_AGENT_MD} (legacy \u2014 will migrate into ${AGENTS_MD})`);
66644
- }
66645
- lines2.push(` - ${CLAUDE_MD} (${detection.claudeMd ? "exists" : "missing"})`);
66646
- lines2.push(` - .cursor/ (${detection.cursorDir ? "exists" : "missing"})`);
66647
- lines2.push(` - .claude/ (${detection.claudeDir ? "exists" : "missing"})`);
66648
- lines2.push(` - ~/.codex (${detection.codexHome ? "exists" : "missing"})`);
66649
- return lines2.join("\n");
66650
- }
66651
- function buildInstallPlan(detection, targets, options = {}) {
66652
- const writeAgentsMd = options.writeAgentsMd !== false;
66653
- const skillsEnabled = options.skillsEnabled !== false;
66654
- const cursorExplicit = options.cursorRule;
66655
- const wantsCursor = cursorExplicit === true || cursorExplicit !== false && (targets.includes("cursor") || detection.cursorDir);
66656
- return {
66657
- agentsMd: writeAgentsMd,
66658
- migrateLegacyAgentMd: writeAgentsMd && detection.agentMd,
66659
- claudeMd: skillsEnabled && targets.includes("claude"),
66660
- cursorRule: wantsCursor,
66661
- skills: skillsEnabled ? targets : []
66662
- };
66663
- }
66664
- function formatInstallPlan(plan, detection) {
66665
- const mark = (on) => on ? "[x]" : "[ ]";
66666
- const lines2 = ["After you confirm, HAR will:"];
66667
- const agentsAction = detection.agentsMd ? `Update ${AGENTS_MD} \u2014 refresh HAR / agent environment section` : `Create ${AGENTS_MD} \u2014 shared HAR workflow (Codex + cross-tool)`;
66668
- lines2.push(` ${mark(plan.agentsMd)} ${agentsAction}`);
66669
- if (plan.migrateLegacyAgentMd) {
66670
- lines2.push(` ${mark(true)} Migrate ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD}, then remove legacy file`);
66671
- }
66672
- lines2.push(
66673
- ` ${mark(plan.claudeMd)} Claude \u2014 ensure ${CLAUDE_MD} points at ${AGENTS_MD}; install .claude/skills if confirmed`
66674
- );
66675
- lines2.push(
66676
- ` ${mark(plan.cursorRule)} Cursor \u2014 install/refresh .cursor/rules/har-workflow.mdc + commands if confirmed`
66677
- );
66678
- lines2.push(
66679
- ` ${mark(plan.skills.includes("codex"))} Codex \u2014 global ~/.codex/prompts (skills); project contract is ${AGENTS_MD}`
66680
- );
66681
- return lines2.join("\n");
66682
- }
66683
- function loadHarAgentsSectionFromTemplate() {
66684
- const templatePath = resolveTemplateFile("AGENTS.md.template");
66685
- if (!templatePath) {
66686
- throw new Error("AGENTS.md.template not found. Run npm run build.");
66687
- }
66688
- const content = fs34.readFileSync(templatePath, "utf8");
66689
- const start = content.indexOf(HAR_SECTION_START);
66690
- const end = content.indexOf(HAR_SECTION_END);
66691
- if (start === -1 || end === -1 || end < start) {
66692
- throw new Error("AGENTS.md.template is missing har:agent-environment markers.");
66693
- }
66694
- return content.slice(start, end + HAR_SECTION_END.length);
66695
- }
66696
- function loadAgentsMdTemplate() {
66697
- const templatePath = resolveTemplateFile("AGENTS.md.template");
66698
- if (!templatePath) {
66699
- throw new Error("AGENTS.md.template not found. Run npm run build.");
66700
- }
66701
- return fs34.readFileSync(templatePath, "utf8");
66702
- }
66703
- function upsertMarkedBlock(content, block, startMarker, endMarker) {
66704
- if (content.includes(startMarker)) {
66705
- const pattern = new RegExp(
66706
- `${escapeRegExp(startMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`
66707
- );
66708
- return { content: content.replace(pattern, block), action: "updated" };
66709
- }
66710
- const suffix = content.endsWith("\n") ? "" : "\n";
66711
- return { content: `${content}${suffix}
66712
- ${block}
66713
- `, action: "appended" };
66714
- }
66715
- function upsertAgentsMdHarSection(repoPath) {
66716
- const dest = path39.join(repoPath, AGENTS_MD);
66717
- const section = loadHarAgentsSectionFromTemplate();
66718
- if (!fs34.existsSync(dest)) {
66719
- writeFileSafe(dest, loadAgentsMdTemplate());
66720
- return "created";
66721
- }
66722
- const existing = fs34.readFileSync(dest, "utf8");
66723
- const { content, action } = upsertMarkedBlock(
66724
- existing,
66725
- section,
66726
- HAR_SECTION_START,
66727
- HAR_SECTION_END
66728
- );
66729
- writeFileSafe(dest, content);
66730
- return action;
66731
- }
66732
- function migrateLegacyAgentMd(repoPath) {
66733
- const legacyPath = path39.join(repoPath, LEGACY_AGENT_MD);
66734
- const agentsPath = path39.join(repoPath, AGENTS_MD);
66735
- if (!fs34.existsSync(legacyPath)) return false;
66736
- const legacy = fs34.readFileSync(legacyPath, "utf8");
66737
- if (!fs34.existsSync(agentsPath)) {
66738
- writeFileSafe(agentsPath, legacy);
66739
- upsertAgentsMdHarSection(repoPath);
66740
- } else {
66741
- upsertAgentsMdHarSection(repoPath);
66742
- }
66743
- fs34.unlinkSync(legacyPath);
66744
- info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
66745
- return true;
66746
- }
66747
- function loadClaudeMdTemplate(projectName) {
66748
- const templatePath = resolveTemplateFile("CLAUDE.md.template");
66749
- if (!templatePath) {
66750
- throw new Error("CLAUDE.md.template not found. Run npm run build.");
66751
- }
66752
- const displayName = projectName.replace(/_/g, " ");
66753
- return fs34.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
66754
- }
66755
- function isThinClaudePointer(content) {
66756
- const trimmed = content.trim();
66757
- if (trimmed.length > 600) return false;
66758
- return /AGENTS\.md|AGENT\.md/.test(trimmed) && (trimmed.includes(".har/README.md") || trimmed.includes("har-workflow"));
66759
- }
66760
- var CLAUDE_POINTER_BLOCK = `${CLAUDE_HAR_SECTION_START}
66761
- ## HAR
66762
-
66763
- This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
66764
- [\`.har/README.md\`](./.har/README.md) before making changes.
66765
- ${CLAUDE_HAR_SECTION_END}`;
66766
- function ensureClaudeMdPointer(repoPath, options = {}) {
66767
- const dest = path39.join(repoPath, CLAUDE_MD);
66768
- const projectName = path39.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66769
- const thin = loadClaudeMdTemplate(projectName);
66770
- if (!fs34.existsSync(dest)) {
66771
- writeFileSafe(dest, thin);
66772
- return "created";
66773
- }
66774
- const existing = fs34.readFileSync(dest, "utf8");
66775
- if (isThinClaudePointer(existing) || options.force) {
66776
- writeFileSafe(dest, thin);
66777
- return "updated";
66778
- }
66779
- if (existing.includes(CLAUDE_HAR_SECTION_START) || /\[AGENTS\.md\]/.test(existing)) {
66780
- if (existing.includes(CLAUDE_HAR_SECTION_START)) {
66781
- const { content: content2, action: action2 } = upsertMarkedBlock(
66782
- existing,
66783
- CLAUDE_POINTER_BLOCK,
66784
- CLAUDE_HAR_SECTION_START,
66785
- CLAUDE_HAR_SECTION_END
66786
- );
66787
- writeFileSafe(dest, content2);
66788
- return action2;
66789
- }
66790
- return "skipped";
66791
- }
66792
- const { content, action } = upsertMarkedBlock(
66793
- existing,
66794
- CLAUDE_POINTER_BLOCK,
66795
- CLAUDE_HAR_SECTION_START,
66796
- CLAUDE_HAR_SECTION_END
66797
- );
66798
- writeFileSafe(dest, content);
66799
- return action;
66800
- }
66801
- async function askYesNo2(question, defaultYes = true) {
66802
- const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
66803
- return new Promise((resolve47) => {
66804
- process.stderr.write(`${question} `);
66805
- rl.once("line", (answer) => {
66806
- rl.close();
66807
- const trimmed = answer.trim();
66808
- if (trimmed === "") {
66809
- resolve47(defaultYes);
66810
- return;
66811
- }
66812
- resolve47(/^y(es)?$/i.test(trimmed));
66813
- });
66814
- });
66815
- }
66816
- async function handleInstructionFiles(options) {
66817
- const { repoPath, mode } = options;
66818
- const writeAgentsMd = options.writeAgentsMd !== false;
66819
- const skillsEnabled = options.enabled !== false;
66820
- const detection = detectInstructionFiles(repoPath);
66821
- let targets;
66822
- if (!skillsEnabled) {
66823
- targets = [];
66824
- } else if (typeof options.agents === "string") {
66825
- targets = parseAgentTargets(options.agents);
66826
- } else {
66827
- targets = detectAgentTargets(repoPath);
66828
- }
66829
- if (skillsEnabled && targets.length === 0 && mode === "init" && typeof options.agents !== "string" && !options.autoYes) {
66830
- targets = [...AGENT_SKILL_TARGETS];
66831
- }
66832
- let plan = buildInstallPlan(detection, targets, {
66833
- writeAgentsMd,
66834
- cursorRule: options.cursorRule,
66835
- skillsEnabled
66836
- });
66837
- divider();
66838
- process.stderr.write(`${formatDetectionReport(detection)}
66839
-
66840
- `);
66841
- process.stderr.write(`${formatInstallPlan(plan, detection)}
66842
- `);
66843
- divider();
66844
- const shouldPrompt = !options.autoYes && skillsEnabled && typeof options.agents !== "string" && !(mode === "maintain" && targets.length > 0 && !detection.agentMd);
66845
- if (shouldPrompt && targets.length > 0) {
66846
- const accepted = await askYesNo2(
66847
- `Install HAR agent instructions for: ${targets.join(", ")}? [Y/n]`
66848
- );
66849
- if (!accepted) {
66850
- info("Skipped agent instruction adapters (AGENTS.md will still be updated)");
66851
- targets = [];
66852
- plan = buildInstallPlan(detection, targets, {
66853
- writeAgentsMd,
66854
- cursorRule: options.cursorRule === true ? true : false,
66855
- skillsEnabled: false
66856
- });
66857
- }
66858
- }
66859
- let migratedLegacy = false;
66860
- let agentsMdAction = null;
66861
- let claudeMdAction = null;
66862
- if (writeAgentsMd) {
66863
- if (detection.agentMd) {
66864
- migratedLegacy = migrateLegacyAgentMd(repoPath);
66865
- }
66866
- agentsMdAction = upsertAgentsMdHarSection(repoPath);
66867
- if (agentsMdAction === "created") {
66868
- success(`Wrote ${AGENTS_MD}`);
66869
- } else if (agentsMdAction === "updated" || agentsMdAction === "appended") {
66870
- info(
66871
- `${agentsMdAction === "updated" ? "Refreshed" : "Appended"} HAR section in ${AGENTS_MD}`
66872
- );
66873
- }
66874
- } else {
66875
- agentsMdAction = "skipped";
66876
- }
66877
- if (plan.claudeMd) {
66878
- claudeMdAction = ensureClaudeMdPointer(repoPath);
66879
- if (claudeMdAction === "created") {
66880
- success(`Wrote ${CLAUDE_MD} (pointer \u2192 ${AGENTS_MD})`);
66881
- } else if (claudeMdAction === "updated" || claudeMdAction === "appended") {
66882
- info(
66883
- `${claudeMdAction === "updated" ? "Updated" : "Appended"} ${CLAUDE_MD} pointer \u2192 ${AGENTS_MD}`
66884
- );
66885
- }
66886
- } else {
66887
- claudeMdAction = "skipped";
66888
- }
66889
- return {
66890
- detection,
66891
- plan,
66892
- targets,
66893
- agentsMdAction,
66894
- migratedLegacy,
66895
- claudeMdAction
66896
- };
66897
- }
66898
-
66899
67196
  // src/harness/maintain-bundle.ts
66900
67197
  var MAINTAIN_DIR = "maintain";
66901
67198
  var PROFILE_DIRS3 = {
@@ -66907,14 +67204,14 @@ function substituteProjectName2(content, projectName) {
66907
67204
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
66908
67205
  }
66909
67206
  function projectNameFromRepo(repoPath) {
66910
- return path40.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
67207
+ return path41.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
66911
67208
  }
66912
67209
  function boilerplateDirForProfile(profile) {
66913
- return path40.join(resolveTemplatesDir(), PROFILE_DIRS3[profile]);
67210
+ return path41.join(resolveTemplatesDir(), PROFILE_DIRS3[profile]);
66914
67211
  }
66915
67212
  function readBundledTemplateContent(repoPath, profile, file) {
66916
- const templatePath = path40.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
66917
- let content = fs35.readFileSync(templatePath, "utf8");
67213
+ const templatePath = path41.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
67214
+ let content = fs36.readFileSync(templatePath, "utf8");
66918
67215
  if (file === "harness.env") {
66919
67216
  content = substituteProjectName2(content, projectNameFromRepo(repoPath));
66920
67217
  }
@@ -66945,12 +67242,12 @@ function actionHint(file, kind) {
66945
67242
  return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
66946
67243
  }
66947
67244
  function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
66948
- const tmpDir = fs35.mkdtempSync(path40.join(os14.tmpdir(), "har-maintain-diff-"));
67245
+ const tmpDir = fs36.mkdtempSync(path41.join(os14.tmpdir(), "har-maintain-diff-"));
66949
67246
  try {
66950
- const installedPath = path40.join(tmpDir, "installed");
66951
- const templatePath = path40.join(tmpDir, "template");
66952
- fs35.writeFileSync(installedPath, installedContent);
66953
- fs35.writeFileSync(templatePath, templateContent);
67247
+ const installedPath = path41.join(tmpDir, "installed");
67248
+ const templatePath = path41.join(tmpDir, "template");
67249
+ fs36.writeFileSync(installedPath, installedContent);
67250
+ fs36.writeFileSync(templatePath, templateContent);
66954
67251
  const result = run(`diff -u "${installedPath}" "${templatePath}"`);
66955
67252
  const body = result.stdout.trim();
66956
67253
  if (!body) return "";
@@ -66959,7 +67256,7 @@ function createUnifiedDiff(installedContent, templateContent, installedLabel, te
66959
67256
  ${body.split("\n").slice(2).join("\n")}
66960
67257
  `;
66961
67258
  } finally {
66962
- fs35.rmSync(tmpDir, { recursive: true, force: true });
67259
+ fs36.rmSync(tmpDir, { recursive: true, force: true });
66963
67260
  }
66964
67261
  }
66965
67262
  function buildActions(repoPath, profile, drift) {
@@ -66974,7 +67271,7 @@ function buildActions(repoPath, profile, drift) {
66974
67271
  });
66975
67272
  }
66976
67273
  for (const file of drift.checksumMismatch) {
66977
- const installedPath = path40.join(harnessDir, file);
67274
+ const installedPath = path41.join(harnessDir, file);
66978
67275
  const installedRel = `maintain/installed/${file}`;
66979
67276
  const templateRel = `maintain/templates/${file}`;
66980
67277
  const diffRel = `maintain/diffs/${file}.diff`;
@@ -66982,7 +67279,7 @@ function buildActions(repoPath, profile, drift) {
66982
67279
  file,
66983
67280
  kind: "drift",
66984
67281
  template: templateRel,
66985
- installed: fs35.existsSync(installedPath) ? installedRel : void 0,
67282
+ installed: fs36.existsSync(installedPath) ? installedRel : void 0,
66986
67283
  diff: diffRel,
66987
67284
  hint: actionHint(file, "drift")
66988
67285
  });
@@ -67101,6 +67398,10 @@ function buildReadme(report) {
67101
67398
  lines2.push("", "## Agent instruction files (generator 0.5.0)", "");
67102
67399
  lines2.push(
67103
67400
  "Repo-root agent docs are **outside** `.har/` checksum drift. Apply while adapting:",
67401
+ "",
67402
+ "**Merge contract:** `har env maintain --finalize` refreshes only the content between",
67403
+ "`<!-- har:agent-environment:start/end -->` in `AGENTS.md`. Custom `## Project` sections and",
67404
+ "other guidance **outside** those markers must survive finalize \u2014 relocate them if needed.",
67104
67405
  ""
67105
67406
  );
67106
67407
  for (const note of report.instructionFiles) {
@@ -67130,28 +67431,28 @@ function buildReadme(report) {
67130
67431
  }
67131
67432
  function writeBundleArtifacts(repoPath, profile, drift, report) {
67132
67433
  const harnessDir = getHarnessDir(repoPath);
67133
- const bundleDir = path40.join(harnessDir, MAINTAIN_DIR);
67134
- if (fs35.existsSync(bundleDir)) {
67135
- fs35.rmSync(bundleDir, { recursive: true, force: true });
67434
+ const bundleDir = path41.join(harnessDir, MAINTAIN_DIR);
67435
+ if (fs36.existsSync(bundleDir)) {
67436
+ fs36.rmSync(bundleDir, { recursive: true, force: true });
67136
67437
  }
67137
67438
  const dirs = [
67138
67439
  bundleDir,
67139
- path40.join(bundleDir, "templates"),
67140
- path40.join(bundleDir, "installed"),
67141
- path40.join(bundleDir, "diffs"),
67142
- path40.join(bundleDir, "stale")
67440
+ path41.join(bundleDir, "templates"),
67441
+ path41.join(bundleDir, "installed"),
67442
+ path41.join(bundleDir, "diffs"),
67443
+ path41.join(bundleDir, "stale")
67143
67444
  ];
67144
67445
  for (const dir of dirs) {
67145
- fs35.mkdirSync(dir, { recursive: true });
67446
+ fs36.mkdirSync(dir, { recursive: true });
67146
67447
  }
67147
67448
  const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
67148
67449
  for (const file of affectedFiles) {
67149
67450
  const templateContent = readBundledTemplateContent(repoPath, profile, file);
67150
- writeFileSafe(path40.join(bundleDir, "templates", file), templateContent);
67151
- const harnessPath = path40.join(harnessDir, file);
67152
- if (fs35.existsSync(harnessPath)) {
67153
- const installedContent = fs35.readFileSync(harnessPath, "utf8");
67154
- writeFileSafe(path40.join(bundleDir, "installed", file), installedContent);
67451
+ writeFileSafe(path41.join(bundleDir, "templates", file), templateContent);
67452
+ const harnessPath = path41.join(harnessDir, file);
67453
+ if (fs36.existsSync(harnessPath)) {
67454
+ const installedContent = fs36.readFileSync(harnessPath, "utf8");
67455
+ writeFileSafe(path41.join(bundleDir, "installed", file), installedContent);
67155
67456
  const diff = createUnifiedDiff(
67156
67457
  installedContent,
67157
67458
  templateContent,
@@ -67159,14 +67460,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
67159
67460
  `templates/${file}`
67160
67461
  );
67161
67462
  if (diff) {
67162
- writeFileSafe(path40.join(bundleDir, "diffs", `${file}.diff`), diff);
67463
+ writeFileSafe(path41.join(bundleDir, "diffs", `${file}.diff`), diff);
67163
67464
  }
67164
67465
  }
67165
67466
  }
67166
- writeFileSafe(path40.join(bundleDir, "README.md"), buildReadme(report));
67167
- writeFileSafe(path40.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
67467
+ writeFileSafe(path41.join(bundleDir, "README.md"), buildReadme(report));
67468
+ writeFileSafe(path41.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
67168
67469
  writeFileSafe(
67169
- path40.join(bundleDir, "validation.json"),
67470
+ path41.join(bundleDir, "validation.json"),
67170
67471
  JSON.stringify(report.validation, null, 2) + "\n"
67171
67472
  );
67172
67473
  if (report.stale.length > 0) {
@@ -67178,34 +67479,34 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
67178
67479
  ...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
67179
67480
  ""
67180
67481
  ];
67181
- writeFileSafe(path40.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
67482
+ writeFileSafe(path41.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
67182
67483
  }
67183
67484
  return bundleDir;
67184
67485
  }
67185
67486
  function ensureParentDir2(filePath) {
67186
- const parent = path40.dirname(filePath);
67187
- if (!fs35.existsSync(parent)) {
67188
- fs35.mkdirSync(parent, { recursive: true });
67487
+ const parent = path41.dirname(filePath);
67488
+ if (!fs36.existsSync(parent)) {
67489
+ fs36.mkdirSync(parent, { recursive: true });
67189
67490
  }
67190
67491
  }
67191
67492
  function writePluginBundleArtifacts(repoPath, bundleDir, report) {
67192
67493
  if (report.pluginActions.length === 0) return;
67193
67494
  for (const action of report.pluginActions) {
67194
- const pluginRoot = path40.join(bundleDir, "plugins", action.pluginId);
67195
- const templatesDir = path40.join(pluginRoot, "templates");
67196
- const installedDir = path40.join(pluginRoot, "installed");
67197
- const diffsDir = path40.join(pluginRoot, "diffs");
67495
+ const pluginRoot = path41.join(bundleDir, "plugins", action.pluginId);
67496
+ const templatesDir = path41.join(pluginRoot, "templates");
67497
+ const installedDir = path41.join(pluginRoot, "installed");
67498
+ const diffsDir = path41.join(pluginRoot, "diffs");
67198
67499
  for (const dir of [templatesDir, installedDir, diffsDir]) {
67199
- fs35.mkdirSync(dir, { recursive: true });
67500
+ fs36.mkdirSync(dir, { recursive: true });
67200
67501
  }
67201
67502
  const templateContent = readTemplatePluginFile(action.pluginId, action.file);
67202
67503
  if (templateContent === null) continue;
67203
- const templatePath = path40.join(templatesDir, action.file);
67504
+ const templatePath = path41.join(templatesDir, action.file);
67204
67505
  ensureParentDir2(templatePath);
67205
67506
  writeFileSafe(templatePath, templateContent);
67206
67507
  const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
67207
67508
  if (installedContent !== null) {
67208
- const installedPath = path40.join(installedDir, action.file);
67509
+ const installedPath = path41.join(installedDir, action.file);
67209
67510
  ensureParentDir2(installedPath);
67210
67511
  writeFileSafe(installedPath, installedContent);
67211
67512
  const diff = createUnifiedDiff(
@@ -67215,7 +67516,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
67215
67516
  `templates/${action.file}`
67216
67517
  );
67217
67518
  if (diff) {
67218
- const diffPath = path40.join(diffsDir, `${action.file}.diff`);
67519
+ const diffPath = path41.join(diffsDir, `${action.file}.diff`);
67219
67520
  ensureParentDir2(diffPath);
67220
67521
  writeFileSafe(diffPath, diff);
67221
67522
  }
@@ -67251,9 +67552,9 @@ function buildMaintainBundle(repoPath, validation2, drift) {
67251
67552
  return { bundleDir, report };
67252
67553
  }
67253
67554
  function removeMaintainBundle(repoPath) {
67254
- const bundleDir = path40.join(getHarnessDir(repoPath), MAINTAIN_DIR);
67255
- if (fs35.existsSync(bundleDir)) {
67256
- fs35.rmSync(bundleDir, { recursive: true, force: true });
67555
+ const bundleDir = path41.join(getHarnessDir(repoPath), MAINTAIN_DIR);
67556
+ if (fs36.existsSync(bundleDir)) {
67557
+ fs36.rmSync(bundleDir, { recursive: true, force: true });
67257
67558
  }
67258
67559
  }
67259
67560
  function formatMaintainBundlePromptSection(report) {
@@ -67342,11 +67643,11 @@ init_manifest();
67342
67643
  init_stages();
67343
67644
  function listHarnessScripts(repoPath) {
67344
67645
  const harnessDir = getHarnessDir(repoPath);
67345
- if (!fs36.existsSync(harnessDir)) return [];
67346
- return fs36.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
67646
+ if (!fs37.existsSync(harnessDir)) return [];
67647
+ return fs37.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
67347
67648
  }
67348
67649
  function describeProject(repoPath) {
67349
- const resolved = path41.resolve(repoPath);
67650
+ const resolved = path42.resolve(repoPath);
67350
67651
  const manifest = readManifest(resolved);
67351
67652
  const present = harnessExists(resolved);
67352
67653
  return {
@@ -67366,8 +67667,8 @@ function describeProject(repoPath) {
67366
67667
  };
67367
67668
  }
67368
67669
  async function initHarness(options) {
67369
- const repoPath = path41.resolve(options.repoPath);
67370
- if (!fs36.existsSync(repoPath)) {
67670
+ const repoPath = path42.resolve(options.repoPath);
67671
+ if (!fs37.existsSync(repoPath)) {
67371
67672
  throw new Error(`Path not found: ${repoPath}`);
67372
67673
  }
67373
67674
  const scaffold = scaffoldHarnessBoilerplate(repoPath, {
@@ -67387,9 +67688,9 @@ async function initHarness(options) {
67387
67688
  };
67388
67689
  }
67389
67690
  async function maintainHarness(options) {
67390
- const repoPath = path41.resolve(options.repoPath);
67691
+ const repoPath = path42.resolve(options.repoPath);
67391
67692
  const harnessDir = getHarnessDir(repoPath);
67392
- if (!fs36.existsSync(harnessDir)) {
67693
+ if (!fs37.existsSync(harnessDir)) {
67393
67694
  throw new Error('No .har/ found. Run "har env init" first.');
67394
67695
  }
67395
67696
  const drift = compareHarnessToTemplate(repoPath);
@@ -67399,6 +67700,7 @@ async function maintainHarness(options) {
67399
67700
  throw new Error("Cannot finalize: harness validation has errors. Fix them first.");
67400
67701
  }
67401
67702
  syncAgentSlotsToHarnessEnv(repoPath);
67703
+ finalizeAgentsMdInstructionFiles(repoPath);
67402
67704
  const existing = readManifest(repoPath);
67403
67705
  finalizeHarness(
67404
67706
  repoPath,
@@ -67423,13 +67725,13 @@ function addPlugin(repoPath, pluginId, options = {}) {
67423
67725
  }
67424
67726
 
67425
67727
  // src/harness/custom-stage.ts
67426
- var fs37 = __toESM(require("fs"));
67427
- var path42 = __toESM(require("path"));
67728
+ var fs38 = __toESM(require("fs"));
67729
+ var path43 = __toESM(require("path"));
67428
67730
  init_schema2();
67429
67731
  init_stages();
67430
67732
  var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
67431
67733
  function addCustomStage(repoPath, options) {
67432
- const resolved = path42.resolve(repoPath);
67734
+ const resolved = path43.resolve(repoPath);
67433
67735
  if (!harnessExists(resolved)) {
67434
67736
  throw new Error('No .har/ harness found. Run "har env init" first.');
67435
67737
  }
@@ -67466,20 +67768,20 @@ function addCustomStage(repoPath, options) {
67466
67768
  if (options.command) {
67467
67769
  stage.command = options.command;
67468
67770
  } else {
67469
- const scriptRel = path42.join("stages", `${id}.sh`);
67470
- const scriptAbs = path42.join(resolved, ".har", scriptRel);
67471
- if (fs37.existsSync(scriptAbs) && !options.force) {
67771
+ const scriptRel = path43.join("stages", `${id}.sh`);
67772
+ const scriptAbs = path43.join(resolved, ".har", scriptRel);
67773
+ if (fs38.existsSync(scriptAbs) && !options.force) {
67472
67774
  throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
67473
67775
  }
67474
- const skeletonPath = path42.join(
67776
+ const skeletonPath = path43.join(
67475
67777
  resolveTemplatesDir(),
67476
67778
  "plugins",
67477
67779
  "custom-stage-skeleton.sh"
67478
67780
  );
67479
- const skeleton = fs37.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
67480
- fs37.mkdirSync(path42.dirname(scriptAbs), { recursive: true });
67481
- fs37.writeFileSync(scriptAbs, skeleton);
67482
- fs37.chmodSync(scriptAbs, 493);
67781
+ const skeleton = fs38.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
67782
+ fs38.mkdirSync(path43.dirname(scriptAbs), { recursive: true });
67783
+ fs38.writeFileSync(scriptAbs, skeleton);
67784
+ fs38.chmodSync(scriptAbs, 493);
67483
67785
  filesWritten.push(`.har/${scriptRel}`);
67484
67786
  stage.script = scriptRel;
67485
67787
  stage.artifacts = [
@@ -67527,8 +67829,8 @@ function addCustomStage(repoPath, options) {
67527
67829
  }
67528
67830
 
67529
67831
  // src/harness/adaptation-prompt.ts
67530
- var fs38 = __toESM(require("fs"));
67531
- var path43 = __toESM(require("path"));
67832
+ var fs39 = __toESM(require("fs"));
67833
+ var path44 = __toESM(require("path"));
67532
67834
  var readline3 = __toESM(require("readline"));
67533
67835
 
67534
67836
  // src/utils/clipboard.ts
@@ -67618,7 +67920,7 @@ function loadTemplate(name) {
67618
67920
  if (!filePath) {
67619
67921
  throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
67620
67922
  }
67621
- return fs38.readFileSync(filePath, "utf8");
67923
+ return fs39.readFileSync(filePath, "utf8");
67622
67924
  }
67623
67925
  function applyProfilePlaceholders(content, profile) {
67624
67926
  return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
@@ -67640,7 +67942,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
67640
67942
  }
67641
67943
  function writeAdaptationPrompt(repoPath, content) {
67642
67944
  const harnessDir = getHarnessDir(repoPath);
67643
- const filePath = path43.join(harnessDir, ADAPTATION_PROMPT_FILE);
67945
+ const filePath = path44.join(harnessDir, ADAPTATION_PROMPT_FILE);
67644
67946
  writeFileSafe(filePath, content);
67645
67947
  return filePath;
67646
67948
  }
@@ -67695,27 +67997,27 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
67695
67997
  }
67696
67998
 
67697
67999
  // src/harness/cursor-rule.ts
67698
- var fs39 = __toESM(require("fs"));
67699
- var path44 = __toESM(require("path"));
68000
+ var fs40 = __toESM(require("fs"));
68001
+ var path45 = __toESM(require("path"));
67700
68002
  var readline4 = __toESM(require("readline"));
67701
68003
  init_file_ops();
67702
68004
  init_logging();
67703
68005
  var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
67704
68006
  function getCursorRulePath(repoPath) {
67705
- return path44.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
68007
+ return path45.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
67706
68008
  }
67707
68009
  function isCursorWorkspace(repoPath) {
67708
- return fs39.existsSync(path44.join(repoPath, ".cursor"));
68010
+ return fs40.existsSync(path45.join(repoPath, ".cursor"));
67709
68011
  }
67710
68012
  function cursorRuleExists(repoPath) {
67711
- return fs39.existsSync(getCursorRulePath(repoPath));
68013
+ return fs40.existsSync(getCursorRulePath(repoPath));
67712
68014
  }
67713
68015
  function scaffoldCursorRule(repoPath) {
67714
68016
  const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
67715
68017
  if (!templatePath) {
67716
68018
  throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
67717
68019
  }
67718
- const content = fs39.readFileSync(templatePath, "utf8");
68020
+ const content = fs40.readFileSync(templatePath, "utf8");
67719
68021
  writeFileSafe(getCursorRulePath(repoPath), content);
67720
68022
  }
67721
68023
  async function handleCursorRule(options) {
@@ -67805,7 +68107,7 @@ init_control_config();
67805
68107
 
67806
68108
  // src/core/control-lifecycle.ts
67807
68109
  var import_child_process9 = require("child_process");
67808
- var path45 = __toESM(require("path"));
68110
+ var path46 = __toESM(require("path"));
67809
68111
 
67810
68112
  // src/core/control-image.ts
67811
68113
  var DEFAULT_CONTROL_IMAGE = "theosfactory/har-control";
@@ -67831,10 +68133,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
67831
68133
  var CONTROL_CONTAINER_PORT = 3847;
67832
68134
  var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
67833
68135
  function resolveControlDir() {
67834
- return path45.resolve(__dirname, "..", "control");
68136
+ return path46.resolve(__dirname, "..", "control");
67835
68137
  }
67836
68138
  function resolveControlBuildContext() {
67837
- return path45.resolve(resolveControlDir(), "..");
68139
+ return path46.resolve(resolveControlDir(), "..");
67838
68140
  }
67839
68141
  function buildDockerRunArgs(options) {
67840
68142
  const name = options.containerName ?? CONTROL_CONTAINER_NAME;
@@ -67890,7 +68192,7 @@ async function startMissionControl(options) {
67890
68192
  "-t",
67891
68193
  imageRef,
67892
68194
  "-f",
67893
- path45.join(resolveControlDir(), "Dockerfile"),
68195
+ path46.join(resolveControlDir(), "Dockerfile"),
67894
68196
  resolveControlBuildContext()
67895
68197
  ]);
67896
68198
  if (buildCode !== 0) {
@@ -68037,7 +68339,7 @@ async function ensureTelemetryInfrastructure(options) {
68037
68339
  // src/core/run-service.ts
68038
68340
  init_telemetry_config();
68039
68341
  init_telemetry_env();
68040
- var path47 = __toESM(require("path"));
68342
+ var path48 = __toESM(require("path"));
68041
68343
  init_local_executor();
68042
68344
  function extractShellOutput(result) {
68043
68345
  const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
@@ -68240,12 +68542,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
68240
68542
  suffix: session.suffix,
68241
68543
  createdAt: session.createdAt
68242
68544
  });
68243
- const envFile = path47.join(session.workDir, `.env.agent.${options.agentId}`);
68545
+ const envFile = path48.join(session.workDir, `.env.agent.${options.agentId}`);
68244
68546
  try {
68245
68547
  appendTelemetryEnvToFile(envFile, {
68246
68548
  sessionKey,
68247
68549
  agentId: options.agentId,
68248
- repoPath: path47.resolve(options.repoPath),
68550
+ repoPath: path48.resolve(options.repoPath),
68249
68551
  workDir: session.workDir,
68250
68552
  branch: session.branch,
68251
68553
  suffix: session.suffix,
@@ -68483,9 +68785,9 @@ init_slot_status();
68483
68785
  var readline5 = __toESM(require("readline"));
68484
68786
 
68485
68787
  // src/core/hooks.ts
68486
- var fs41 = __toESM(require("fs"));
68788
+ var fs42 = __toESM(require("fs"));
68487
68789
  var os16 = __toESM(require("os"));
68488
- var path48 = __toESM(require("path"));
68790
+ var path49 = __toESM(require("path"));
68489
68791
  init_shell();
68490
68792
  init_schema2();
68491
68793
  init_stages();
@@ -68516,7 +68818,7 @@ function resolveCheckoutRoot(cwd) {
68516
68818
  function resolveHooksDir(checkoutDir) {
68517
68819
  const hooksPath = tryGit3(checkoutDir, "rev-parse --git-path hooks");
68518
68820
  if (!hooksPath) throw new Error(`Not a git checkout: ${checkoutDir}`);
68519
- return path48.resolve(checkoutDir, hooksPath);
68821
+ return path49.resolve(checkoutDir, hooksPath);
68520
68822
  }
68521
68823
  function getConfiguredHooksPath(checkoutDir) {
68522
68824
  return tryGit3(checkoutDir, "config core.hooksPath") || void 0;
@@ -68524,9 +68826,9 @@ function getConfiguredHooksPath(checkoutDir) {
68524
68826
  function defaultHarInvocation() {
68525
68827
  const entry = process.argv[1];
68526
68828
  if (entry && entry.endsWith(".js")) {
68527
- return `"${process.execPath}" "${path48.resolve(entry)}"`;
68829
+ return `"${process.execPath}" "${path49.resolve(entry)}"`;
68528
68830
  }
68529
- if (entry) return `"${path48.resolve(entry)}"`;
68831
+ if (entry) return `"${path49.resolve(entry)}"`;
68530
68832
  return "har";
68531
68833
  }
68532
68834
  function buildHookScript(harInvocation, subcommand, failOpenNotice) {
@@ -68547,40 +68849,40 @@ exit 0
68547
68849
  `;
68548
68850
  }
68549
68851
  function upsertMarkedBlock2(filePath, block) {
68550
- if (!fs41.existsSync(filePath)) {
68551
- fs41.writeFileSync(filePath, `#!/bin/sh
68852
+ if (!fs42.existsSync(filePath)) {
68853
+ fs42.writeFileSync(filePath, `#!/bin/sh
68552
68854
  ${block}
68553
68855
  `, { mode: 493 });
68554
68856
  return "created";
68555
68857
  }
68556
- const content = fs41.readFileSync(filePath, "utf8");
68858
+ const content = fs42.readFileSync(filePath, "utf8");
68557
68859
  if (content.includes(MARKER_START)) {
68558
68860
  const pattern = new RegExp(
68559
68861
  `${escapeRegExp2(MARKER_START)}[\\s\\S]*?${escapeRegExp2(MARKER_END)}`
68560
68862
  );
68561
- fs41.writeFileSync(filePath, content.replace(pattern, block));
68562
- fs41.chmodSync(filePath, 493);
68863
+ fs42.writeFileSync(filePath, content.replace(pattern, block));
68864
+ fs42.chmodSync(filePath, 493);
68563
68865
  return "updated";
68564
68866
  }
68565
68867
  const suffix = content.endsWith("\n") ? "" : "\n";
68566
- fs41.writeFileSync(filePath, `${content}${suffix}
68868
+ fs42.writeFileSync(filePath, `${content}${suffix}
68567
68869
  ${block}
68568
68870
  `);
68569
- fs41.chmodSync(filePath, 493);
68871
+ fs42.chmodSync(filePath, 493);
68570
68872
  return "appended";
68571
68873
  }
68572
68874
  function removeMarkedBlock(filePath) {
68573
- if (!fs41.existsSync(filePath)) return false;
68574
- const content = fs41.readFileSync(filePath, "utf8");
68875
+ if (!fs42.existsSync(filePath)) return false;
68876
+ const content = fs42.readFileSync(filePath, "utf8");
68575
68877
  if (!content.includes(MARKER_START)) return false;
68576
68878
  const pattern = new RegExp(
68577
68879
  `\\n?${escapeRegExp2(MARKER_START)}[\\s\\S]*?${escapeRegExp2(MARKER_END)}\\n?`
68578
68880
  );
68579
68881
  const stripped = content.replace(pattern, "\n");
68580
68882
  if (stripped.replace(/^#!\/bin\/sh\n?/, "").trim() === "") {
68581
- fs41.rmSync(filePath);
68883
+ fs42.rmSync(filePath);
68582
68884
  } else {
68583
- fs41.writeFileSync(filePath, stripped);
68885
+ fs42.writeFileSync(filePath, stripped);
68584
68886
  }
68585
68887
  return true;
68586
68888
  }
@@ -68602,20 +68904,20 @@ Or re-run with --force to write into that directory anyway.`
68602
68904
  );
68603
68905
  }
68604
68906
  const hooksDir = resolveHooksDir(checkout);
68605
- fs41.mkdirSync(hooksDir, { recursive: true });
68907
+ fs42.mkdirSync(hooksDir, { recursive: true });
68606
68908
  const invocation = options.harInvocation ?? defaultHarInvocation();
68607
- fs41.writeFileSync(
68608
- path48.join(hooksDir, "har-pre-commit"),
68909
+ fs42.writeFileSync(
68910
+ path49.join(hooksDir, "har-pre-commit"),
68609
68911
  buildHookScript(invocation, "check", "har: binary not found; skipping commit gate (reinstall with har hooks install)"),
68610
68912
  { mode: 493 }
68611
68913
  );
68612
- fs41.writeFileSync(
68613
- path48.join(hooksDir, "har-post-commit"),
68914
+ fs42.writeFileSync(
68915
+ path49.join(hooksDir, "har-post-commit"),
68614
68916
  buildHookScript(invocation, "record-commit", "har: binary not found; skipping commit association"),
68615
68917
  { mode: 493 }
68616
68918
  );
68617
- const preCommit = upsertMarkedBlock2(path48.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
68618
- const postCommit = upsertMarkedBlock2(path48.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
68919
+ const preCommit = upsertMarkedBlock2(path49.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
68920
+ const postCommit = upsertMarkedBlock2(path49.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
68619
68921
  ensureValidationsIgnored(checkout);
68620
68922
  return { hooksDir, preCommit, postCommit };
68621
68923
  }
@@ -68624,12 +68926,12 @@ function uninstallHooks(repoPath) {
68624
68926
  if (!checkout) throw new Error(`Not a git repository: ${repoPath}`);
68625
68927
  const hooksDir = resolveHooksDir(checkout);
68626
68928
  let removed = false;
68627
- removed = removeMarkedBlock(path48.join(hooksDir, "pre-commit")) || removed;
68628
- removed = removeMarkedBlock(path48.join(hooksDir, "post-commit")) || removed;
68929
+ removed = removeMarkedBlock(path49.join(hooksDir, "pre-commit")) || removed;
68930
+ removed = removeMarkedBlock(path49.join(hooksDir, "post-commit")) || removed;
68629
68931
  for (const file of ["har-pre-commit", "har-post-commit"]) {
68630
- const full = path48.join(hooksDir, file);
68631
- if (fs41.existsSync(full)) {
68632
- fs41.rmSync(full);
68932
+ const full = path49.join(hooksDir, file);
68933
+ if (fs42.existsSync(full)) {
68934
+ fs42.rmSync(full);
68633
68935
  removed = true;
68634
68936
  }
68635
68937
  }
@@ -68648,10 +68950,10 @@ function isAgentWorktree(checkoutDir) {
68648
68950
  if (branch && (/^har-agent-\d+$/.test(branch) || /-har-agent-\d+-[a-z0-9]+$/.test(branch))) {
68649
68951
  return true;
68650
68952
  }
68651
- const worktreesRoot = path48.join(os16.homedir(), "worktrees");
68652
- const resolved = path48.resolve(checkoutDir);
68653
- const name = path48.basename(resolved);
68654
- return resolved.startsWith(`${worktreesRoot}${path48.sep}`) && (/-agent-\d+$/.test(name) || /-har-agent-\d+-[a-z0-9]+$/.test(name));
68953
+ const worktreesRoot = path49.join(os16.homedir(), "worktrees");
68954
+ const resolved = path49.resolve(checkoutDir);
68955
+ const name = path49.basename(resolved);
68956
+ return resolved.startsWith(`${worktreesRoot}${path49.sep}`) && (/-agent-\d+$/.test(name) || /-har-agent-\d+-[a-z0-9]+$/.test(name));
68655
68957
  }
68656
68958
  function resolveEffectiveMode(checkoutDir, gate) {
68657
68959
  if (!gate.enabled) return "off";
@@ -68664,15 +68966,15 @@ function getHooksStatus(repoPath) {
68664
68966
  const hooksDir = resolveHooksDir(checkout);
68665
68967
  const gate = getCommitGateConfig(checkout);
68666
68968
  const hasBlock = (name) => {
68667
- const file = path48.join(hooksDir, name);
68668
- return fs41.existsSync(file) && fs41.readFileSync(file, "utf8").includes(MARKER_START);
68969
+ const file = path49.join(hooksDir, name);
68970
+ return fs42.existsSync(file) && fs42.readFileSync(file, "utf8").includes(MARKER_START);
68669
68971
  };
68670
68972
  return {
68671
68973
  checkout,
68672
68974
  hooksDir,
68673
68975
  configuredHooksPath: getConfiguredHooksPath(checkout),
68674
- preCommitInstalled: hasBlock("pre-commit") && fs41.existsSync(path48.join(hooksDir, "har-pre-commit")),
68675
- postCommitInstalled: hasBlock("post-commit") && fs41.existsSync(path48.join(hooksDir, "har-post-commit")),
68976
+ preCommitInstalled: hasBlock("pre-commit") && fs42.existsSync(path49.join(hooksDir, "har-pre-commit")),
68977
+ postCommitInstalled: hasBlock("post-commit") && fs42.existsSync(path49.join(hooksDir, "har-post-commit")),
68676
68978
  gate,
68677
68979
  effectiveMode: resolveEffectiveMode(checkout, gate)
68678
68980
  };
@@ -68683,7 +68985,7 @@ function checkCommitGate(cwd) {
68683
68985
  }
68684
68986
  const checkout = resolveCheckoutRoot(cwd);
68685
68987
  if (!checkout) return { exitCode: 0, messages: [] };
68686
- if (!fs41.existsSync(path48.join(checkout, ".har", "stages.json"))) {
68988
+ if (!fs42.existsSync(path49.join(checkout, ".har", "stages.json"))) {
68687
68989
  return { exitCode: 0, messages: [] };
68688
68990
  }
68689
68991
  const gate = getCommitGateConfig(checkout);
@@ -68805,21 +69107,21 @@ async function handleCommitGateOnboarding(options) {
68805
69107
  }
68806
69108
 
68807
69109
  // src/core/onboarding-preferences.ts
68808
- var fs42 = __toESM(require("fs"));
69110
+ var fs43 = __toESM(require("fs"));
68809
69111
  var os17 = __toESM(require("os"));
68810
- var path49 = __toESM(require("path"));
69112
+ var path50 = __toESM(require("path"));
68811
69113
  init_schema2();
68812
69114
  function getOnboardingPreferencesPath() {
68813
69115
  if (process.env.HAR_PREFERENCES_PATH) {
68814
- return path49.resolve(process.env.HAR_PREFERENCES_PATH);
69116
+ return path50.resolve(process.env.HAR_PREFERENCES_PATH);
68815
69117
  }
68816
- return path49.join(os17.homedir(), ".har", "preferences.json");
69118
+ return path50.join(os17.homedir(), ".har", "preferences.json");
68817
69119
  }
68818
69120
  function readOnboardingPreferences() {
68819
69121
  const preferencePath = getOnboardingPreferencesPath();
68820
69122
  try {
68821
- if (!fs42.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
68822
- return OnboardingPreferencesSchema.parse(JSON.parse(fs42.readFileSync(preferencePath, "utf8")));
69123
+ if (!fs43.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
69124
+ return OnboardingPreferencesSchema.parse(JSON.parse(fs43.readFileSync(preferencePath, "utf8")));
68823
69125
  } catch {
68824
69126
  return OnboardingPreferencesSchema.parse({});
68825
69127
  }
@@ -68844,8 +69146,8 @@ function writeOnboardingPreferences(overrides) {
68844
69146
  };
68845
69147
  const parsed = OnboardingPreferencesSchema.parse(preference);
68846
69148
  const preferencePath = getOnboardingPreferencesPath();
68847
- fs42.mkdirSync(path49.dirname(preferencePath), { recursive: true });
68848
- fs42.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
69149
+ fs43.mkdirSync(path50.dirname(preferencePath), { recursive: true });
69150
+ fs43.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
68849
69151
  `);
68850
69152
  return parsed;
68851
69153
  }
@@ -69136,7 +69438,7 @@ var envCommand = {
69136
69438
  }
69137
69439
  };
69138
69440
  async function handleInit(argv) {
69139
- const repoPath = path50.resolve(argv.repo);
69441
+ const repoPath = path51.resolve(argv.repo);
69140
69442
  const onboarding = resolveOnboardingOptions(argv);
69141
69443
  header("har env init");
69142
69444
  info(`Repository: ${repoPath}`);
@@ -69182,7 +69484,7 @@ async function handleInit(argv) {
69182
69484
  }
69183
69485
  }
69184
69486
  async function handleMaintain(argv) {
69185
- const repoPath = path50.resolve(argv.repo);
69487
+ const repoPath = path51.resolve(argv.repo);
69186
69488
  const onboarding = resolveOnboardingOptions(argv);
69187
69489
  header("har env maintain");
69188
69490
  info(`Repository: ${repoPath}`);
@@ -69237,6 +69539,8 @@ async function handleMaintain(argv) {
69237
69539
  mode: "maintain",
69238
69540
  autoYes: argv.yes,
69239
69541
  cursorRule: onboarding.cursorRule,
69542
+ writeAgentsMd: !argv.finalize,
69543
+ finalize: argv.finalize,
69240
69544
  ...onboarding.agentSkills
69241
69545
  });
69242
69546
  } catch (err) {
@@ -69288,7 +69592,9 @@ async function applyAgentIntegrations(options) {
69288
69592
  enabled: options.enabled,
69289
69593
  cursorRule: options.cursorRule,
69290
69594
  autoYes: options.autoYes,
69291
- mode: options.mode
69595
+ mode: options.mode,
69596
+ writeAgentsMd: options.writeAgentsMd,
69597
+ finalize: options.finalize
69292
69598
  });
69293
69599
  const cursorRuleFlag = options.cursorRule === false ? false : options.cursorRule === true || instruction.plan.cursorRule ? true : false;
69294
69600
  await handleCursorRule({
@@ -69309,7 +69615,7 @@ async function applyAgentIntegrations(options) {
69309
69615
  }
69310
69616
  }
69311
69617
  async function handleAddPlugin(argv) {
69312
- const repoPath = path50.resolve(argv.repo);
69618
+ const repoPath = path51.resolve(argv.repo);
69313
69619
  const available = listPluginIds();
69314
69620
  if (argv.list) {
69315
69621
  for (const id of available) {
@@ -69347,7 +69653,7 @@ async function handleAddPlugin(argv) {
69347
69653
  }
69348
69654
  }
69349
69655
  async function handleAddStage(argv) {
69350
- const repoPath = path50.resolve(argv.repo);
69656
+ const repoPath = path51.resolve(argv.repo);
69351
69657
  const available = listPluginIds();
69352
69658
  if (argv.list) {
69353
69659
  warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
@@ -69413,7 +69719,7 @@ async function handleAddStage(argv) {
69413
69719
  });
69414
69720
  }
69415
69721
  async function handlePreflight(argv) {
69416
- const repo = path50.resolve(argv.repo);
69722
+ const repo = path51.resolve(argv.repo);
69417
69723
  const agentId = validateAgentId(argv.id, repo);
69418
69724
  const result = await preflightEnvironment({
69419
69725
  repoPath: repo,
@@ -69429,7 +69735,7 @@ async function handlePreflight(argv) {
69429
69735
  return finishCommand(result.code);
69430
69736
  }
69431
69737
  async function handleLaunch(argv) {
69432
- const repo = path50.resolve(argv.repo);
69738
+ const repo = path51.resolve(argv.repo);
69433
69739
  const agentId = validateAgentId(argv.id, repo);
69434
69740
  if (!argv.resume) {
69435
69741
  const guard = checkLaunchGuard2(repo, agentId, {});
@@ -69484,7 +69790,7 @@ async function handleRecover(argv) {
69484
69790
  });
69485
69791
  }
69486
69792
  async function handleVerify(argv) {
69487
- const repo = path50.resolve(argv.repo);
69793
+ const repo = path51.resolve(argv.repo);
69488
69794
  const agentId = validateAgentId(argv.id, repo);
69489
69795
  const result = await runVerification({
69490
69796
  repoPath: repo,
@@ -69496,7 +69802,7 @@ async function handleVerify(argv) {
69496
69802
  return finishCommand(result.code);
69497
69803
  }
69498
69804
  async function handleTeardown(argv) {
69499
- const repo = path50.resolve(argv.repo);
69805
+ const repo = path51.resolve(argv.repo);
69500
69806
  const agentId = validateAgentId(argv.id, repo);
69501
69807
  const result = await teardownEnvironment({
69502
69808
  repoPath: repo,
@@ -69507,7 +69813,7 @@ async function handleTeardown(argv) {
69507
69813
  return finishCommand(result.code);
69508
69814
  }
69509
69815
  async function handleComplete(argv) {
69510
- const repo = path50.resolve(argv.repo);
69816
+ const repo = path51.resolve(argv.repo);
69511
69817
  const agentId = validateAgentId(argv.id, repo);
69512
69818
  const result = await completeEnvironment({
69513
69819
  repoPath: repo,
@@ -69528,7 +69834,7 @@ async function handleComplete(argv) {
69528
69834
  return finishCommand(result.code);
69529
69835
  }
69530
69836
  async function handleStatus(argv) {
69531
- const repoPath = path50.resolve(argv.repo);
69837
+ const repoPath = path51.resolve(argv.repo);
69532
69838
  if (argv.json) {
69533
69839
  const status = collectEnvironmentStatus(repoPath);
69534
69840
  const output = EnvironmentStatusSchema.parse(status);
@@ -69541,7 +69847,7 @@ async function handleStatus(argv) {
69541
69847
  });
69542
69848
  }
69543
69849
  async function handleRunsList(argv) {
69544
- const repoPath = path50.resolve(argv.repo);
69850
+ const repoPath = path51.resolve(argv.repo);
69545
69851
  const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
69546
69852
  if (argv.json) {
69547
69853
  process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
@@ -69558,7 +69864,7 @@ async function handleRunsList(argv) {
69558
69864
  }
69559
69865
  }
69560
69866
  async function handleRunsGet(argv) {
69561
- const run2 = getRun(path50.resolve(argv.repo), argv.runId);
69867
+ const run2 = getRun(path51.resolve(argv.repo), argv.runId);
69562
69868
  if (!run2) {
69563
69869
  error(`Run not found: ${argv.runId}`);
69564
69870
  return finishCommand(1);
@@ -69640,7 +69946,7 @@ function printNextSteps() {
69640
69946
  }
69641
69947
 
69642
69948
  // src/cli/commands/control.ts
69643
- var path54 = __toESM(require("path"));
69949
+ var path55 = __toESM(require("path"));
69644
69950
 
69645
69951
  // node_modules/@inquirer/core/dist/esm/lib/key.mjs
69646
69952
  var isUpKey = (key) => (
@@ -71694,9 +72000,9 @@ var import_run_async = __toESM(require_run_async(), 1);
71694
72000
  var import_mute_stream2 = __toESM(require_lib(), 1);
71695
72001
  var import_ansi_escapes5 = __toESM(require_ansi_escapes(), 1);
71696
72002
  var _ = {
71697
- set: (obj, path61 = "", value) => {
72003
+ set: (obj, path62 = "", value) => {
71698
72004
  let pointer = obj;
71699
- path61.split(".").forEach((key, index, arr) => {
72005
+ path62.split(".").forEach((key, index, arr) => {
71700
72006
  if (key === "__proto__" || key === "constructor")
71701
72007
  return;
71702
72008
  if (index === arr.length - 1) {
@@ -71707,8 +72013,8 @@ var _ = {
71707
72013
  pointer = pointer[key];
71708
72014
  });
71709
72015
  },
71710
- get: (obj, path61 = "", defaultValue) => {
71711
- const travel = (regexp) => String.prototype.split.call(path61, regexp).filter(Boolean).reduce(
72016
+ get: (obj, path62 = "", defaultValue) => {
72017
+ const travel = (regexp) => String.prototype.split.call(path62, regexp).filter(Boolean).reduce(
71712
72018
  // @ts-expect-error implicit any on res[key]
71713
72019
  (res, key) => res !== null && res !== void 0 ? res[key] : res,
71714
72020
  obj
@@ -71962,21 +72268,21 @@ init_control_port();
71962
72268
  init_control_sync();
71963
72269
 
71964
72270
  // src/core/control-sync-selection.ts
71965
- var fs43 = __toESM(require("fs"));
72271
+ var fs44 = __toESM(require("fs"));
71966
72272
  var os18 = __toESM(require("os"));
71967
- var path51 = __toESM(require("path"));
72273
+ var path52 = __toESM(require("path"));
71968
72274
  init_control_repo_path();
71969
72275
  function getSelectionPath() {
71970
72276
  if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
71971
- return path51.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
72277
+ return path52.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
71972
72278
  }
71973
- return path51.join(os18.homedir(), ".har", "sync-selection.json");
72279
+ return path52.join(os18.homedir(), ".har", "sync-selection.json");
71974
72280
  }
71975
72281
  function readSyncSelection() {
71976
72282
  const selectionPath = getSelectionPath();
71977
72283
  try {
71978
- if (!fs43.existsSync(selectionPath)) return null;
71979
- const parsed = JSON.parse(fs43.readFileSync(selectionPath, "utf8"));
72284
+ if (!fs44.existsSync(selectionPath)) return null;
72285
+ const parsed = JSON.parse(fs44.readFileSync(selectionPath, "utf8"));
71980
72286
  if (!Array.isArray(parsed.repos)) return null;
71981
72287
  return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
71982
72288
  } catch {
@@ -71986,8 +72292,8 @@ function readSyncSelection() {
71986
72292
  function writeSyncSelection(repos) {
71987
72293
  const selectionPath = getSelectionPath();
71988
72294
  const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
71989
- fs43.mkdirSync(path51.dirname(selectionPath), { recursive: true });
71990
- fs43.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
72295
+ fs44.mkdirSync(path52.dirname(selectionPath), { recursive: true });
72296
+ fs44.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
71991
72297
  }
71992
72298
  function resolveSyncSelection(input) {
71993
72299
  const { discovered, stored, forceSelect, isTTY } = input;
@@ -72094,8 +72400,8 @@ If your browser did not open, paste that URL.
72094
72400
  }
72095
72401
 
72096
72402
  // src/core/control-unregister.ts
72097
- var fs44 = __toESM(require("fs"));
72098
- var path52 = __toESM(require("path"));
72403
+ var fs45 = __toESM(require("fs"));
72404
+ var path53 = __toESM(require("path"));
72099
72405
  init_control_repo_path();
72100
72406
  init_control_registry();
72101
72407
  init_control_config();
@@ -72105,9 +72411,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
72105
72411
  const harnessRoot = canonicalizeControlRepoPath(repoPath);
72106
72412
  const byPath = /* @__PURE__ */ new Map();
72107
72413
  const add = (partial2) => {
72108
- const resolved = path52.resolve(partial2.worktreePath);
72414
+ const resolved = path53.resolve(partial2.worktreePath);
72109
72415
  if (!resolved || resolved === harnessRoot) return;
72110
- const exists = partial2.exists ?? fs44.existsSync(resolved);
72416
+ const exists = partial2.exists ?? fs45.existsSync(resolved);
72111
72417
  const prev = byPath.get(resolved);
72112
72418
  if (prev) {
72113
72419
  byPath.set(resolved, {
@@ -72221,28 +72527,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
72221
72527
  trigger: "cli"
72222
72528
  });
72223
72529
  if (result.code !== 0) {
72224
- if (fs44.existsSync(candidate.worktreePath)) {
72225
- fs44.rmSync(candidate.worktreePath, { recursive: true, force: true });
72530
+ if (fs45.existsSync(candidate.worktreePath)) {
72531
+ fs45.rmSync(candidate.worktreePath, { recursive: true, force: true });
72226
72532
  }
72227
72533
  }
72228
72534
  outcomes.push({
72229
72535
  path: candidate.worktreePath,
72230
72536
  agentId: candidate.agentId,
72231
- deleted: !fs44.existsSync(candidate.worktreePath),
72232
- error: result.code !== 0 && fs44.existsSync(candidate.worktreePath) ? result.stderr : void 0
72537
+ deleted: !fs45.existsSync(candidate.worktreePath),
72538
+ error: result.code !== 0 && fs45.existsSync(candidate.worktreePath) ? result.stderr : void 0
72233
72539
  });
72234
72540
  } catch (err) {
72235
72541
  const message = err instanceof Error ? err.message : String(err);
72236
72542
  try {
72237
- if (fs44.existsSync(candidate.worktreePath)) {
72238
- fs44.rmSync(candidate.worktreePath, { recursive: true, force: true });
72543
+ if (fs45.existsSync(candidate.worktreePath)) {
72544
+ fs45.rmSync(candidate.worktreePath, { recursive: true, force: true });
72239
72545
  }
72240
72546
  } catch {
72241
72547
  }
72242
72548
  outcomes.push({
72243
72549
  path: candidate.worktreePath,
72244
72550
  agentId: candidate.agentId,
72245
- deleted: !fs44.existsSync(candidate.worktreePath),
72551
+ deleted: !fs45.existsSync(candidate.worktreePath),
72246
72552
  error: message
72247
72553
  });
72248
72554
  }
@@ -72305,16 +72611,16 @@ init_control_config();
72305
72611
  init_control_registry();
72306
72612
 
72307
72613
  // src/core/harness-scrub.ts
72308
- var fs45 = __toESM(require("fs"));
72309
- var path53 = __toESM(require("path"));
72614
+ var fs46 = __toESM(require("fs"));
72615
+ var path54 = __toESM(require("path"));
72310
72616
  var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
72311
72617
  function scrubLocalHarnessDirs(repoPath) {
72312
72618
  const results = [];
72313
- const resolved = path53.resolve(repoPath);
72314
- if (!fs45.existsSync(resolved)) {
72619
+ const resolved = path54.resolve(repoPath);
72620
+ if (!fs46.existsSync(resolved)) {
72315
72621
  for (const directory of HARNESS_SCRUB_DIRS) {
72316
72622
  results.push({
72317
- path: path53.join(resolved, ".har", directory),
72623
+ path: path54.join(resolved, ".har", directory),
72318
72624
  directory,
72319
72625
  deleted: false,
72320
72626
  error: "repository path does not exist"
@@ -72323,24 +72629,24 @@ function scrubLocalHarnessDirs(repoPath) {
72323
72629
  return results;
72324
72630
  }
72325
72631
  for (const directory of HARNESS_SCRUB_DIRS) {
72326
- const target = path53.join(resolved, ".har", directory);
72327
- if (!fs45.existsSync(target)) {
72632
+ const target = path54.join(resolved, ".har", directory);
72633
+ if (!fs46.existsSync(target)) {
72328
72634
  results.push({ path: target, directory, deleted: true });
72329
72635
  continue;
72330
72636
  }
72331
72637
  try {
72332
- fs45.rmSync(target, { recursive: true, force: true });
72638
+ fs46.rmSync(target, { recursive: true, force: true });
72333
72639
  results.push({
72334
72640
  path: target,
72335
72641
  directory,
72336
- deleted: !fs45.existsSync(target),
72337
- error: fs45.existsSync(target) ? "failed to remove directory" : void 0
72642
+ deleted: !fs46.existsSync(target),
72643
+ error: fs46.existsSync(target) ? "failed to remove directory" : void 0
72338
72644
  });
72339
72645
  } catch (err) {
72340
72646
  results.push({
72341
72647
  path: target,
72342
72648
  directory,
72343
- deleted: !fs45.existsSync(target),
72649
+ deleted: !fs46.existsSync(target),
72344
72650
  error: err instanceof Error ? err.message : String(err)
72345
72651
  });
72346
72652
  }
@@ -72351,7 +72657,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
72351
72657
  const results = [];
72352
72658
  const seen = /* @__PURE__ */ new Set();
72353
72659
  for (const repoPath of repoPaths) {
72354
- const key = path53.resolve(repoPath);
72660
+ const key = path54.resolve(repoPath);
72355
72661
  if (seen.has(key)) continue;
72356
72662
  seen.add(key);
72357
72663
  results.push(...scrubLocalHarnessDirs(key));
@@ -72607,7 +72913,7 @@ async function handleDown() {
72607
72913
  return finishCommand(code);
72608
72914
  }
72609
72915
  async function handleRegister(argv) {
72610
- const repoPath = path54.resolve(argv.repo);
72916
+ const repoPath = path55.resolve(argv.repo);
72611
72917
  header("har control register");
72612
72918
  info(`Repository: ${repoPath}`);
72613
72919
  try {
@@ -72699,7 +73005,7 @@ async function handleReset(argv) {
72699
73005
  }
72700
73006
  }
72701
73007
  async function handleUnregister(argv) {
72702
- const repoPath = path54.resolve(argv.repo);
73008
+ const repoPath = path55.resolve(argv.repo);
72703
73009
  const worktrees = listUnregisterWorktreeCandidates(repoPath);
72704
73010
  try {
72705
73011
  let deleteWorktrees = argv.deleteWorktrees;
@@ -72878,11 +73184,11 @@ async function handleLogin(argv) {
72878
73184
  }
72879
73185
 
72880
73186
  // src/cli/commands/hooks.ts
72881
- var path56 = __toESM(require("path"));
73187
+ var path57 = __toESM(require("path"));
72882
73188
 
72883
73189
  // src/core/claude-hooks.ts
72884
- var fs46 = __toESM(require("fs"));
72885
- var path55 = __toESM(require("path"));
73190
+ var fs47 = __toESM(require("fs"));
73191
+ var path56 = __toESM(require("path"));
72886
73192
  var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
72887
73193
  var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
72888
73194
  var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
@@ -72893,8 +73199,8 @@ function isHarGuardEntry(entry) {
72893
73199
  );
72894
73200
  }
72895
73201
  function readSettings(settingsPath) {
72896
- if (!fs46.existsSync(settingsPath)) return {};
72897
- const raw = fs46.readFileSync(settingsPath, "utf8").trim();
73202
+ if (!fs47.existsSync(settingsPath)) return {};
73203
+ const raw = fs47.readFileSync(settingsPath, "utf8").trim();
72898
73204
  if (raw === "") return {};
72899
73205
  const parsed = JSON.parse(raw);
72900
73206
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -72903,19 +73209,19 @@ function readSettings(settingsPath) {
72903
73209
  return parsed;
72904
73210
  }
72905
73211
  function writeSettings(settingsPath, settings) {
72906
- fs46.mkdirSync(path55.dirname(settingsPath), { recursive: true });
72907
- fs46.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
73212
+ fs47.mkdirSync(path56.dirname(settingsPath), { recursive: true });
73213
+ fs47.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
72908
73214
  }
72909
73215
  function installClaudeGuard(repoPath) {
72910
73216
  const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
72911
73217
  if (!templatePath) {
72912
73218
  throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
72913
73219
  }
72914
- const guardScript = path55.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
72915
- fs46.mkdirSync(path55.dirname(guardScript), { recursive: true });
72916
- fs46.copyFileSync(templatePath, guardScript);
72917
- fs46.chmodSync(guardScript, 493);
72918
- const settingsPath = path55.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73220
+ const guardScript = path56.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73221
+ fs47.mkdirSync(path56.dirname(guardScript), { recursive: true });
73222
+ fs47.copyFileSync(templatePath, guardScript);
73223
+ fs47.chmodSync(guardScript, 493);
73224
+ const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
72919
73225
  const settings = readSettings(settingsPath);
72920
73226
  const hooks = settings.hooks ?? {};
72921
73227
  const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
@@ -72929,15 +73235,15 @@ function installClaudeGuard(repoPath) {
72929
73235
  }
72930
73236
  function uninstallClaudeGuard(repoPath) {
72931
73237
  let removed = false;
72932
- const guardScript = path55.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
72933
- if (fs46.existsSync(guardScript)) {
72934
- fs46.rmSync(guardScript);
73238
+ const guardScript = path56.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73239
+ if (fs47.existsSync(guardScript)) {
73240
+ fs47.rmSync(guardScript);
72935
73241
  removed = true;
72936
- const parent = path55.dirname(guardScript);
72937
- if (fs46.existsSync(parent) && fs46.readdirSync(parent).length === 0) fs46.rmdirSync(parent);
73242
+ const parent = path56.dirname(guardScript);
73243
+ if (fs47.existsSync(parent) && fs47.readdirSync(parent).length === 0) fs47.rmdirSync(parent);
72938
73244
  }
72939
- const settingsPath = path55.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
72940
- if (fs46.existsSync(settingsPath)) {
73245
+ const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73246
+ if (fs47.existsSync(settingsPath)) {
72941
73247
  const settings = readSettings(settingsPath);
72942
73248
  const preToolUse = settings.hooks?.PreToolUse;
72943
73249
  if (preToolUse) {
@@ -72962,8 +73268,8 @@ function uninstallClaudeGuard(repoPath) {
72962
73268
  return { removed };
72963
73269
  }
72964
73270
  function claudeGuardInstalled(repoPath) {
72965
- const settingsPath = path55.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
72966
- if (!fs46.existsSync(settingsPath)) return false;
73271
+ const settingsPath = path56.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73272
+ if (!fs47.existsSync(settingsPath)) return false;
72967
73273
  try {
72968
73274
  const settings = readSettings(settingsPath);
72969
73275
  return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
@@ -72980,7 +73286,7 @@ function repoOption(y) {
72980
73286
  function handleInstall2(argv) {
72981
73287
  try {
72982
73288
  if (argv.claude) {
72983
- const result2 = installClaudeGuard(path56.resolve(argv.repo));
73289
+ const result2 = installClaudeGuard(path57.resolve(argv.repo));
72984
73290
  success("Claude Code worktree guard installed.");
72985
73291
  info(`Guard script: ${result2.guardScript}`);
72986
73292
  info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
@@ -72988,7 +73294,7 @@ function handleInstall2(argv) {
72988
73294
  info("Commit both files so the guard travels with the repo.");
72989
73295
  return;
72990
73296
  }
72991
- const result = installHooks({ repoPath: path56.resolve(argv.repo), force: argv.force });
73297
+ const result = installHooks({ repoPath: path57.resolve(argv.repo), force: argv.force });
72992
73298
  success(`Commit gate installed in ${result.hooksDir}`);
72993
73299
  info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
72994
73300
  info("Commits of unverified change batches will be blocked in agent worktrees.");
@@ -73001,7 +73307,7 @@ function handleInstall2(argv) {
73001
73307
  function handleUninstall(argv) {
73002
73308
  try {
73003
73309
  if (argv.claude) {
73004
- const result2 = uninstallClaudeGuard(path56.resolve(argv.repo));
73310
+ const result2 = uninstallClaudeGuard(path57.resolve(argv.repo));
73005
73311
  if (result2.removed) {
73006
73312
  success("Claude Code worktree guard removed.");
73007
73313
  } else {
@@ -73009,7 +73315,7 @@ function handleUninstall(argv) {
73009
73315
  }
73010
73316
  return;
73011
73317
  }
73012
- const result = uninstallHooks(path56.resolve(argv.repo));
73318
+ const result = uninstallHooks(path57.resolve(argv.repo));
73013
73319
  if (result.removed) {
73014
73320
  success(`Commit gate removed from ${result.hooksDir}`);
73015
73321
  } else {
@@ -73022,7 +73328,7 @@ function handleUninstall(argv) {
73022
73328
  }
73023
73329
  function handleStatus2(argv) {
73024
73330
  try {
73025
- const status = getHooksStatus(path56.resolve(argv.repo));
73331
+ const status = getHooksStatus(path57.resolve(argv.repo));
73026
73332
  if (argv.json) {
73027
73333
  process.stdout.write(`${JSON.stringify(status, null, 2)}
73028
73334
  `);
@@ -73040,7 +73346,7 @@ function handleStatus2(argv) {
73040
73346
  );
73041
73347
  info(`Effective: ${status.effectiveMode} (in this checkout)`);
73042
73348
  info(
73043
- `Claude guard: ${claudeGuardInstalled(path56.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
73349
+ `Claude guard: ${claudeGuardInstalled(path57.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
73044
73350
  );
73045
73351
  } catch (err) {
73046
73352
  error(err instanceof Error ? err.message : String(err));
@@ -73301,10 +73607,10 @@ function assignProp(target, prop, value) {
73301
73607
  configurable: true
73302
73608
  });
73303
73609
  }
73304
- function getElementAtPath(obj, path61) {
73305
- if (!path61)
73610
+ function getElementAtPath(obj, path62) {
73611
+ if (!path62)
73306
73612
  return obj;
73307
- return path61.reduce((acc, key) => acc?.[key], obj);
73613
+ return path62.reduce((acc, key) => acc?.[key], obj);
73308
73614
  }
73309
73615
  function promiseAllObject(promisesObj) {
73310
73616
  const keys = Object.keys(promisesObj);
@@ -73624,11 +73930,11 @@ function aborted(x, startIndex = 0) {
73624
73930
  }
73625
73931
  return false;
73626
73932
  }
73627
- function prefixIssues(path61, issues) {
73933
+ function prefixIssues(path62, issues) {
73628
73934
  return issues.map((iss) => {
73629
73935
  var _a2;
73630
73936
  (_a2 = iss).path ?? (_a2.path = []);
73631
- iss.path.unshift(path61);
73937
+ iss.path.unshift(path62);
73632
73938
  return iss;
73633
73939
  });
73634
73940
  }
@@ -80102,7 +80408,7 @@ var Server = class extends Protocol {
80102
80408
  };
80103
80409
 
80104
80410
  // src/mcp/server.ts
80105
- var path57 = __toESM(require("path"));
80411
+ var path58 = __toESM(require("path"));
80106
80412
 
80107
80413
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
80108
80414
  var import_node_process3 = __toESM(require("node:process"), 1);
@@ -80745,7 +81051,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
80745
81051
  const input = ControlUpInputSchema.parse({ ...args, repo });
80746
81052
  const result = await startControlAndSync({
80747
81053
  detach: input.detach,
80748
- cwd: path57.resolve(input.repo)
81054
+ cwd: path58.resolve(input.repo)
80749
81055
  });
80750
81056
  if (result.code !== 0) {
80751
81057
  return {
@@ -80809,11 +81115,11 @@ var mcpCommand = {
80809
81115
  };
80810
81116
 
80811
81117
  // src/cli/commands/onboard.ts
80812
- var path59 = __toESM(require("path"));
81118
+ var path60 = __toESM(require("path"));
80813
81119
  init_stages();
80814
81120
 
80815
81121
  // src/core/onboarding.ts
80816
- var path58 = __toESM(require("path"));
81122
+ var path59 = __toESM(require("path"));
80817
81123
  init_control_config();
80818
81124
  init_control_sync();
80819
81125
  init_otel_hooks();
@@ -80948,7 +81254,7 @@ async function defaultEnsureControl(options) {
80948
81254
  return { started: true, apiUrl: result.apiUrl };
80949
81255
  }
80950
81256
  async function runOnboarding(options, deps = {}) {
80951
- const repoPath = path58.resolve(options.repoPath);
81257
+ const repoPath = path59.resolve(options.repoPath);
80952
81258
  const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
80953
81259
  const ensureControl = deps.ensureControl ?? defaultEnsureControl;
80954
81260
  const init = deps.initHarness ?? initHarness;
@@ -81136,7 +81442,7 @@ async function promptChoices(args) {
81136
81442
  };
81137
81443
  }
81138
81444
  const pluginChoices = listPluginChoices();
81139
- const repoPath = path59.resolve(args.repo);
81445
+ const repoPath = path60.resolve(args.repo);
81140
81446
  const alreadyPresent = harnessExists(repoPath);
81141
81447
  const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
81142
81448
  const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
@@ -81253,7 +81559,7 @@ function printSummary(result) {
81253
81559
  console.error("");
81254
81560
  }
81255
81561
  async function handleOnboard(argv) {
81256
- const repoPath = path59.resolve(argv.repo);
81562
+ const repoPath = path60.resolve(argv.repo);
81257
81563
  header("har onboard");
81258
81564
  info(`Repository: ${repoPath}`);
81259
81565
  try {
@@ -81484,7 +81790,7 @@ var preferencesCommand = {
81484
81790
  };
81485
81791
 
81486
81792
  // src/cli/commands/telemetry.ts
81487
- var path60 = __toESM(require("path"));
81793
+ var path61 = __toESM(require("path"));
81488
81794
  init_control_config();
81489
81795
  init_control_sync();
81490
81796
  init_manifest();
@@ -81577,7 +81883,7 @@ async function handleOff() {
81577
81883
  info("Mission Control will not auto-start. Existing usage rows are kept.");
81578
81884
  }
81579
81885
  async function handleWriteEnv(argv) {
81580
- const repoPath = path60.resolve(argv.repo);
81886
+ const repoPath = path61.resolve(argv.repo);
81581
81887
  const harnessRoot = resolveHarnessRoot(repoPath);
81582
81888
  const session = readSlotRegistry(harnessRoot, argv.agentId);
81583
81889
  const workDir = argv.workDir ?? session?.workDir ?? repoPath;
@@ -81589,7 +81895,7 @@ async function handleWriteEnv(argv) {
81589
81895
  suffix,
81590
81896
  createdAt: session?.createdAt
81591
81897
  });
81592
- const envFile = argv.envFile ?? path60.join(workDir, `.env.agent.${argv.agentId}`);
81898
+ const envFile = argv.envFile ?? path61.join(workDir, `.env.agent.${argv.agentId}`);
81593
81899
  const attrs = {
81594
81900
  sessionKey,
81595
81901
  agentId: argv.agentId,
@@ -81605,7 +81911,7 @@ async function handleWriteEnv(argv) {
81605
81911
  success(`Wrote session attribution to ${envFile}`);
81606
81912
  }
81607
81913
  function handlePrintEnv(argv) {
81608
- const repoPath = path60.resolve(argv.repo);
81914
+ const repoPath = path61.resolve(argv.repo);
81609
81915
  const workDir = argv.workDir ?? repoPath;
81610
81916
  const sessionKey = buildSessionKey({
81611
81917
  branch: argv.branch,