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