@osfactory/har 1.14.0 → 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -35872,6 +35872,20 @@ function resolveMainWorkingTree(cwd) {
|
|
|
35872
35872
|
}
|
|
35873
35873
|
return path7.resolve(toplevel);
|
|
35874
35874
|
}
|
|
35875
|
+
function listLinkedWorktrees(cwd) {
|
|
35876
|
+
const porcelain = tryGit(cwd, "worktree list --porcelain");
|
|
35877
|
+
if (!porcelain) return [];
|
|
35878
|
+
const main = resolveMainWorkingTree(cwd);
|
|
35879
|
+
const mainResolved = main ? path7.resolve(main) : void 0;
|
|
35880
|
+
const paths = [];
|
|
35881
|
+
for (const line of porcelain.split("\n")) {
|
|
35882
|
+
if (!line.startsWith("worktree ")) continue;
|
|
35883
|
+
const worktree = path7.resolve(line.slice("worktree ".length));
|
|
35884
|
+
if (mainResolved && worktree === mainResolved) continue;
|
|
35885
|
+
paths.push(worktree);
|
|
35886
|
+
}
|
|
35887
|
+
return paths;
|
|
35888
|
+
}
|
|
35875
35889
|
function canonicalizeControlRepoPath(repoPath) {
|
|
35876
35890
|
const resolved = path7.resolve(repoPath);
|
|
35877
35891
|
const toplevel = tryGit(resolved, "rev-parse --show-toplevel");
|
|
@@ -37467,13 +37481,55 @@ var init_work_units = __esm({
|
|
|
37467
37481
|
// src/core/sync-sources.ts
|
|
37468
37482
|
function resolveSyncSourcePaths(canonicalPath, workspacePath) {
|
|
37469
37483
|
const canonical = path18.resolve(canonicalPath);
|
|
37470
|
-
|
|
37471
|
-
const
|
|
37472
|
-
|
|
37473
|
-
|
|
37474
|
-
|
|
37475
|
-
|
|
37476
|
-
|
|
37484
|
+
const paths = [canonical];
|
|
37485
|
+
const seenRoots = /* @__PURE__ */ new Set([path18.resolve(resolveHarnessRoot(canonical))]);
|
|
37486
|
+
const add = (candidate) => {
|
|
37487
|
+
const resolved = path18.resolve(candidate);
|
|
37488
|
+
const root = path18.resolve(resolveHarnessRoot(resolved));
|
|
37489
|
+
if (seenRoots.has(root)) return;
|
|
37490
|
+
seenRoots.add(root);
|
|
37491
|
+
paths.push(resolved);
|
|
37492
|
+
};
|
|
37493
|
+
if (workspacePath) add(workspacePath);
|
|
37494
|
+
for (const worktree of listLinkedWorktrees(canonical)) {
|
|
37495
|
+
if (hasHarnessEvidence(worktree)) add(worktree);
|
|
37496
|
+
}
|
|
37497
|
+
return paths;
|
|
37498
|
+
}
|
|
37499
|
+
function hasHarnessEvidence(repoPath) {
|
|
37500
|
+
const root = resolveHarnessRoot(repoPath);
|
|
37501
|
+
const harDir = path18.join(root, DEFAULT_HAR_DIR);
|
|
37502
|
+
if (!fs18.existsSync(harDir)) return false;
|
|
37503
|
+
for (const sub of EVIDENCE_SUBDIRS) {
|
|
37504
|
+
const dir = path18.join(harDir, sub);
|
|
37505
|
+
if (!fs18.existsSync(dir)) continue;
|
|
37506
|
+
try {
|
|
37507
|
+
if (fs18.readdirSync(dir).length > 0) return true;
|
|
37508
|
+
} catch {
|
|
37509
|
+
continue;
|
|
37510
|
+
}
|
|
37511
|
+
}
|
|
37512
|
+
return false;
|
|
37513
|
+
}
|
|
37514
|
+
function mergeSlotStatuses(groups) {
|
|
37515
|
+
const byId = /* @__PURE__ */ new Map();
|
|
37516
|
+
for (const group of groups) {
|
|
37517
|
+
for (const slot of group) {
|
|
37518
|
+
const existing = byId.get(slot.agentId);
|
|
37519
|
+
byId.set(slot.agentId, existing ? preferSlotStatus(existing, slot) : slot);
|
|
37520
|
+
}
|
|
37521
|
+
}
|
|
37522
|
+
return [...byId.values()].sort((a, b2) => a.agentId - b2.agentId);
|
|
37523
|
+
}
|
|
37524
|
+
function preferSlotStatus(a, b2) {
|
|
37525
|
+
if (a.active !== b2.active) return a.active ? a : b2;
|
|
37526
|
+
const aCreated = a.sessionCreatedAt ?? "";
|
|
37527
|
+
const bCreated = b2.sessionCreatedAt ?? "";
|
|
37528
|
+
if (aCreated !== bCreated) return aCreated >= bCreated ? a : b2;
|
|
37529
|
+
const aRun = a.lastRunAt ?? "";
|
|
37530
|
+
const bRun = b2.lastRunAt ?? "";
|
|
37531
|
+
if (aRun !== bRun) return aRun >= bRun ? a : b2;
|
|
37532
|
+
return a;
|
|
37477
37533
|
}
|
|
37478
37534
|
function mergeById(groups, id) {
|
|
37479
37535
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -37537,16 +37593,19 @@ function collectCommitBindingsForSync(sourcePaths) {
|
|
|
37537
37593
|
(record2) => record2.bindingId
|
|
37538
37594
|
);
|
|
37539
37595
|
}
|
|
37540
|
-
var path18;
|
|
37596
|
+
var fs18, path18, EVIDENCE_SUBDIRS;
|
|
37541
37597
|
var init_sync_sources = __esm({
|
|
37542
37598
|
"src/core/sync-sources.ts"() {
|
|
37543
37599
|
"use strict";
|
|
37600
|
+
fs18 = __toESM(require("fs"));
|
|
37544
37601
|
path18 = __toESM(require("path"));
|
|
37545
37602
|
init_manifest();
|
|
37546
37603
|
init_commit_bindings();
|
|
37604
|
+
init_control_repo_path();
|
|
37547
37605
|
init_runs();
|
|
37548
37606
|
init_validations();
|
|
37549
37607
|
init_work_units();
|
|
37608
|
+
EVIDENCE_SUBDIRS = ["slots", "runs", "work-units", "validations"];
|
|
37550
37609
|
}
|
|
37551
37610
|
});
|
|
37552
37611
|
|
|
@@ -37689,18 +37748,18 @@ function spawnResult(cmd, args, opts, shell) {
|
|
|
37689
37748
|
proc.on("close", (code) => resolve70({ code: code ?? 1, stdout, stderr }));
|
|
37690
37749
|
});
|
|
37691
37750
|
}
|
|
37692
|
-
var import_child_process4,
|
|
37751
|
+
var import_child_process4, fs19, path19, realSystemOps, defaultExec, stderrLog, realSleep;
|
|
37693
37752
|
var init_exec = __esm({
|
|
37694
37753
|
"src/runtime/exec.ts"() {
|
|
37695
37754
|
"use strict";
|
|
37696
37755
|
import_child_process4 = require("child_process");
|
|
37697
|
-
|
|
37756
|
+
fs19 = __toESM(require("fs"));
|
|
37698
37757
|
path19 = __toESM(require("path"));
|
|
37699
37758
|
realSystemOps = {
|
|
37700
37759
|
which(cmd) {
|
|
37701
37760
|
if (cmd.includes("/")) {
|
|
37702
37761
|
try {
|
|
37703
|
-
|
|
37762
|
+
fs19.accessSync(cmd, fs19.constants.X_OK);
|
|
37704
37763
|
return cmd;
|
|
37705
37764
|
} catch {
|
|
37706
37765
|
return null;
|
|
@@ -37710,8 +37769,8 @@ var init_exec = __esm({
|
|
|
37710
37769
|
if (!dir) continue;
|
|
37711
37770
|
const candidate = path19.join(dir, cmd);
|
|
37712
37771
|
try {
|
|
37713
|
-
|
|
37714
|
-
if (
|
|
37772
|
+
fs19.accessSync(candidate, fs19.constants.X_OK);
|
|
37773
|
+
if (fs19.statSync(candidate).isFile()) return candidate;
|
|
37715
37774
|
} catch {
|
|
37716
37775
|
}
|
|
37717
37776
|
}
|
|
@@ -37758,15 +37817,15 @@ function declaredNodePackageManager(dir, env3 = {}, _ops = realSystemOps) {
|
|
|
37758
37817
|
const explicit = env3.HARNESS_NODE_PACKAGE_MANAGER;
|
|
37759
37818
|
if (explicit) return explicit;
|
|
37760
37819
|
const pkgPath = path20.join(dir, "package.json");
|
|
37761
|
-
if (
|
|
37762
|
-
const raw =
|
|
37820
|
+
if (fs20.existsSync(pkgPath)) {
|
|
37821
|
+
const raw = fs20.readFileSync(pkgPath, "utf8");
|
|
37763
37822
|
const match = raw.match(/"packageManager"\s*:\s*"([a-z]*)@/);
|
|
37764
37823
|
if (match && match[1]) return match[1];
|
|
37765
37824
|
}
|
|
37766
|
-
if (
|
|
37767
|
-
if (
|
|
37768
|
-
if (
|
|
37769
|
-
if (
|
|
37825
|
+
if (fs20.existsSync(path20.join(dir, "bun.lock")) || fs20.existsSync(path20.join(dir, "bun.lockb"))) return "bun";
|
|
37826
|
+
if (fs20.existsSync(path20.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
37827
|
+
if (fs20.existsSync(path20.join(dir, "yarn.lock"))) return "yarn";
|
|
37828
|
+
if (fs20.existsSync(path20.join(dir, "package-lock.json"))) return "npm";
|
|
37770
37829
|
return "";
|
|
37771
37830
|
}
|
|
37772
37831
|
function nodePackageManager(dir, env3 = {}, ops = realSystemOps) {
|
|
@@ -37794,11 +37853,11 @@ function nodeLockfile(manager) {
|
|
|
37794
37853
|
async function nodeInstall(dir, manager, declared = "", ops = realSystemOps) {
|
|
37795
37854
|
const substituting = declared !== "" && declared !== manager;
|
|
37796
37855
|
const lockfile = substituting ? nodeLockfile(manager) : "";
|
|
37797
|
-
const hadLockfile = lockfile !== "" &&
|
|
37856
|
+
const hadLockfile = lockfile !== "" && fs20.existsSync(path20.join(dir, lockfile));
|
|
37798
37857
|
const result = await ops.run(manager, ["install", "--silent"], { cwd: dir, stream: true });
|
|
37799
37858
|
if (substituting && !hadLockfile && lockfile !== "") {
|
|
37800
|
-
|
|
37801
|
-
if (manager === "bun")
|
|
37859
|
+
fs20.rmSync(path20.join(dir, lockfile), { force: true });
|
|
37860
|
+
if (manager === "bun") fs20.rmSync(path20.join(dir, "bun.lockb"), { force: true });
|
|
37802
37861
|
}
|
|
37803
37862
|
return result.code;
|
|
37804
37863
|
}
|
|
@@ -37818,11 +37877,11 @@ function pkgExec(manager, env3 = {}, ops = realSystemOps) {
|
|
|
37818
37877
|
if (ops.which("pnpm")) return "pnpm dlx";
|
|
37819
37878
|
return "npx --yes";
|
|
37820
37879
|
}
|
|
37821
|
-
var
|
|
37880
|
+
var fs20, path20, NODE_PACKAGE_MANAGERS;
|
|
37822
37881
|
var init_node_pm = __esm({
|
|
37823
37882
|
"src/runtime/node-pm.ts"() {
|
|
37824
37883
|
"use strict";
|
|
37825
|
-
|
|
37884
|
+
fs20 = __toESM(require("fs"));
|
|
37826
37885
|
path20 = __toESM(require("path"));
|
|
37827
37886
|
init_exec();
|
|
37828
37887
|
NODE_PACKAGE_MANAGERS = ["npm", "bun", "pnpm", "yarn"];
|
|
@@ -37836,15 +37895,15 @@ function quoteEnvValue(value) {
|
|
|
37836
37895
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
37837
37896
|
}
|
|
37838
37897
|
function toolchainReady(workDir) {
|
|
37839
|
-
if (
|
|
37898
|
+
if (fs21.existsSync(path21.join(workDir, "package.json")) && fs21.existsSync(path21.join(workDir, "node_modules"))) {
|
|
37840
37899
|
return true;
|
|
37841
37900
|
}
|
|
37842
|
-
return
|
|
37901
|
+
return fs21.existsSync(path21.join(workDir, ".har", "venv"));
|
|
37843
37902
|
}
|
|
37844
37903
|
function detectEcosystem(dir, env3 = {}) {
|
|
37845
37904
|
const configured = env3.HARNESS_ECOSYSTEM ?? "auto";
|
|
37846
37905
|
if (configured && configured !== "auto") return configured;
|
|
37847
|
-
const has = (name) =>
|
|
37906
|
+
const has = (name) => fs21.existsSync(path21.join(dir, name));
|
|
37848
37907
|
if (has("package.json")) return "node";
|
|
37849
37908
|
if (has("pyproject.toml") || has("setup.py") || has("setup.cfg") || has("requirements.txt") || has("Pipfile")) {
|
|
37850
37909
|
return "python";
|
|
@@ -37877,22 +37936,22 @@ function pythonRequiresMinimum(spec) {
|
|
|
37877
37936
|
}
|
|
37878
37937
|
function pythonReadDotVersion(dir) {
|
|
37879
37938
|
const file = path21.join(dir, ".python-version");
|
|
37880
|
-
if (!
|
|
37881
|
-
const first =
|
|
37939
|
+
if (!fs21.existsSync(file)) return null;
|
|
37940
|
+
const first = fs21.readFileSync(file, "utf8").split("\n")[0].replace(/\s/g, "");
|
|
37882
37941
|
return first || null;
|
|
37883
37942
|
}
|
|
37884
37943
|
function pythonReadRequiresSpec(dir) {
|
|
37885
37944
|
const pyproject = path21.join(dir, "pyproject.toml");
|
|
37886
|
-
if (
|
|
37887
|
-
for (const line of
|
|
37945
|
+
if (fs21.existsSync(pyproject)) {
|
|
37946
|
+
for (const line of fs21.readFileSync(pyproject, "utf8").split("\n")) {
|
|
37888
37947
|
const m = line.match(/^\s*requires-python\s*=\s*"([^"]*)"/);
|
|
37889
37948
|
if (m) return m[1];
|
|
37890
37949
|
}
|
|
37891
37950
|
}
|
|
37892
37951
|
const setupCfg = path21.join(dir, "setup.cfg");
|
|
37893
|
-
if (
|
|
37952
|
+
if (fs21.existsSync(setupCfg)) {
|
|
37894
37953
|
let inOptions = false;
|
|
37895
|
-
for (const line of
|
|
37954
|
+
for (const line of fs21.readFileSync(setupCfg, "utf8").split("\n")) {
|
|
37896
37955
|
if (/^\[options\]/.test(line)) {
|
|
37897
37956
|
inOptions = true;
|
|
37898
37957
|
continue;
|
|
@@ -37916,10 +37975,10 @@ function pythonProjectMinimum(dir) {
|
|
|
37916
37975
|
return reqMin ?? dotVer;
|
|
37917
37976
|
}
|
|
37918
37977
|
function pythonIsUvProject(dir) {
|
|
37919
|
-
if (
|
|
37978
|
+
if (fs21.existsSync(path21.join(dir, "uv.lock"))) return true;
|
|
37920
37979
|
const pyproject = path21.join(dir, "pyproject.toml");
|
|
37921
|
-
if (!
|
|
37922
|
-
return /^\[tool\.uv\]/m.test(
|
|
37980
|
+
if (!fs21.existsSync(pyproject)) return false;
|
|
37981
|
+
return /^\[tool\.uv\]/m.test(fs21.readFileSync(pyproject, "utf8"));
|
|
37923
37982
|
}
|
|
37924
37983
|
function iosFindProjectFile(dir, suffix) {
|
|
37925
37984
|
const matches = [];
|
|
@@ -37927,7 +37986,7 @@ function iosFindProjectFile(dir, suffix) {
|
|
|
37927
37986
|
const abs = rel ? path21.join(dir, rel) : dir;
|
|
37928
37987
|
let entries;
|
|
37929
37988
|
try {
|
|
37930
|
-
entries =
|
|
37989
|
+
entries = fs21.readdirSync(abs, { withFileTypes: true });
|
|
37931
37990
|
} catch {
|
|
37932
37991
|
return;
|
|
37933
37992
|
}
|
|
@@ -37950,15 +38009,15 @@ function iosHasProject(dir, env3) {
|
|
|
37950
38009
|
const workspace = env3.HARNESS_XCODE_WORKSPACE;
|
|
37951
38010
|
const project = env3.HARNESS_XCODE_PROJECT;
|
|
37952
38011
|
if (workspace || project) {
|
|
37953
|
-
if (workspace &&
|
|
37954
|
-
if (project &&
|
|
38012
|
+
if (workspace && fs21.existsSync(path21.join(dir, workspace))) return true;
|
|
38013
|
+
if (project && fs21.existsSync(path21.join(dir, project))) return true;
|
|
37955
38014
|
return false;
|
|
37956
38015
|
}
|
|
37957
38016
|
if (iosFindProjectFile(dir, ".xcworkspace")) return true;
|
|
37958
38017
|
return iosFindProjectFile(dir, ".xcodeproj") !== null;
|
|
37959
38018
|
}
|
|
37960
38019
|
function iosProjectGenerator(dir) {
|
|
37961
|
-
const has = (name) =>
|
|
38020
|
+
const has = (name) => fs21.existsSync(path21.join(dir, name));
|
|
37962
38021
|
if (has("Project.swift") || has("Workspace.swift")) return "tuist";
|
|
37963
38022
|
if (has("project.yml") || has("project.yaml")) return "xcodegen";
|
|
37964
38023
|
if (has("Podfile")) return "pod";
|
|
@@ -37967,11 +38026,11 @@ function iosProjectGenerator(dir) {
|
|
|
37967
38026
|
async function provisionToolchain(options) {
|
|
37968
38027
|
return new Provisioner(options).provision();
|
|
37969
38028
|
}
|
|
37970
|
-
var
|
|
38029
|
+
var fs21, path21, ProvisionError, Provisioner;
|
|
37971
38030
|
var init_provision = __esm({
|
|
37972
38031
|
"src/runtime/provision.ts"() {
|
|
37973
38032
|
"use strict";
|
|
37974
|
-
|
|
38033
|
+
fs21 = __toESM(require("fs"));
|
|
37975
38034
|
path21 = __toESM(require("path"));
|
|
37976
38035
|
init_exec();
|
|
37977
38036
|
init_node_pm();
|
|
@@ -38003,11 +38062,11 @@ var init_provision = __esm({
|
|
|
38003
38062
|
this.logFn(message);
|
|
38004
38063
|
}
|
|
38005
38064
|
appendEnv(key, value) {
|
|
38006
|
-
|
|
38065
|
+
fs21.appendFileSync(this.envFile, `${key}=${quoteEnvValue(value)}
|
|
38007
38066
|
`);
|
|
38008
38067
|
}
|
|
38009
38068
|
appendPathPrefix(prefix) {
|
|
38010
|
-
if (!prefix || !
|
|
38069
|
+
if (!prefix || !fs21.existsSync(prefix)) return;
|
|
38011
38070
|
this.appendEnv("PATH", `${prefix}:${process.env.PATH ?? ""}`);
|
|
38012
38071
|
}
|
|
38013
38072
|
/** Extra process env for subprocesses (venv activation is PATH + VIRTUAL_ENV). */
|
|
@@ -38075,7 +38134,7 @@ var init_provision = __esm({
|
|
|
38075
38134
|
const found = await this.pythonUvFind(dir, minimum);
|
|
38076
38135
|
if (executable(found)) return found;
|
|
38077
38136
|
}
|
|
38078
|
-
if (
|
|
38137
|
+
if (fs21.existsSync(path21.join(dir, ".python-version"))) {
|
|
38079
38138
|
const found = await this.pythonUvFind(dir, pythonReadDotVersion(dir));
|
|
38080
38139
|
if (executable(found)) return found;
|
|
38081
38140
|
if (this.ops.which("pyenv")) {
|
|
@@ -38142,23 +38201,23 @@ var init_provision = __esm({
|
|
|
38142
38201
|
}
|
|
38143
38202
|
await this.pythonWarnIfBelowMinimum(interpreter, projectMin);
|
|
38144
38203
|
const venvPython = path21.join(venvDir, "bin", "python");
|
|
38145
|
-
if (
|
|
38204
|
+
if (fs21.existsSync(venvDir) && fs21.existsSync(venvPython) && projectMin) {
|
|
38146
38205
|
const venvVer = await this.pythonVersionFromBin(venvPython);
|
|
38147
38206
|
if (venvVer && !pythonVersionGe(venvVer, projectMin)) {
|
|
38148
38207
|
this.log(`Existing venv Python ${venvVer} is older than required ${projectMin} \u2014 recreating...`);
|
|
38149
|
-
|
|
38208
|
+
fs21.rmSync(venvDir, { recursive: true, force: true });
|
|
38150
38209
|
}
|
|
38151
38210
|
}
|
|
38152
|
-
if (!
|
|
38211
|
+
if (!fs21.existsSync(venvDir)) {
|
|
38153
38212
|
if (!await this.pythonCreateVenv(dir, venvDir, interpreter)) {
|
|
38154
|
-
|
|
38213
|
+
fs21.rmSync(venvDir, { recursive: true, force: true });
|
|
38155
38214
|
this.log("venv creation failed (on Debian/Ubuntu install python3-venv) \u2014 using resolved interpreter");
|
|
38156
38215
|
this.appendEnv("HARNESS_ECOSYSTEM", "python");
|
|
38157
38216
|
this.appendEnv("PYTHON_BIN", interpreter);
|
|
38158
38217
|
return;
|
|
38159
38218
|
}
|
|
38160
38219
|
}
|
|
38161
|
-
if (!
|
|
38220
|
+
if (!fs21.existsSync(venvPython)) {
|
|
38162
38221
|
this.log(`Python venv at ${venvRel} is missing or broken \u2014 using resolved interpreter`);
|
|
38163
38222
|
this.appendEnv("HARNESS_ECOSYSTEM", "python");
|
|
38164
38223
|
this.appendEnv("PYTHON_BIN", interpreter);
|
|
@@ -38178,19 +38237,19 @@ var init_provision = __esm({
|
|
|
38178
38237
|
quietStderr: quiet,
|
|
38179
38238
|
stream: !quiet
|
|
38180
38239
|
});
|
|
38181
|
-
if (
|
|
38240
|
+
if (fs21.existsSync(path21.join(dir, "pyproject.toml"))) {
|
|
38182
38241
|
const dev = await pip(["install", "-q", "-e", ".[dev]"], true);
|
|
38183
38242
|
if (dev.code !== 0) {
|
|
38184
38243
|
const plain = await pip(["install", "-q", "-e", "."], false);
|
|
38185
38244
|
if (plain.code !== 0) throw new ProvisionError("pip install -e . failed");
|
|
38186
38245
|
}
|
|
38187
|
-
} else if (
|
|
38246
|
+
} else if (fs21.existsSync(path21.join(dir, "requirements.txt"))) {
|
|
38188
38247
|
const result = await pip(["install", "-q", "-r", "requirements.txt"], false);
|
|
38189
38248
|
if (result.code !== 0) throw new ProvisionError("pip install -r requirements.txt failed");
|
|
38190
|
-
} else if (
|
|
38249
|
+
} else if (fs21.existsSync(path21.join(dir, "setup.py")) || fs21.existsSync(path21.join(dir, "setup.cfg"))) {
|
|
38191
38250
|
const result = await pip(["install", "-q", "-e", "."], false);
|
|
38192
38251
|
if (result.code !== 0) throw new ProvisionError("pip install -e . failed");
|
|
38193
|
-
} else if (
|
|
38252
|
+
} else if (fs21.existsSync(path21.join(dir, "Pipfile")) && this.ops.which("pipenv")) {
|
|
38194
38253
|
const result = await this.ops.run("pipenv", ["install", "--dev"], {
|
|
38195
38254
|
cwd: dir,
|
|
38196
38255
|
stream: true,
|
|
@@ -38250,7 +38309,7 @@ var init_provision = __esm({
|
|
|
38250
38309
|
const mvn = this.ops.which("mvn");
|
|
38251
38310
|
if (mvn) {
|
|
38252
38311
|
this.appendEnv("MVN_BIN", mvn);
|
|
38253
|
-
} else if (
|
|
38312
|
+
} else if (fs21.existsSync(path21.join(dir, "gradlew"))) {
|
|
38254
38313
|
this.appendEnv("GRADLE_BIN", path21.join(dir, "gradlew"));
|
|
38255
38314
|
} else {
|
|
38256
38315
|
const gradle = this.ops.which("gradle");
|
|
@@ -38303,8 +38362,8 @@ var init_provision = __esm({
|
|
|
38303
38362
|
}
|
|
38304
38363
|
}
|
|
38305
38364
|
async iosPodInstall(dir) {
|
|
38306
|
-
if (!
|
|
38307
|
-
if (
|
|
38365
|
+
if (!fs21.existsSync(path21.join(dir, "Podfile"))) return;
|
|
38366
|
+
if (fs21.existsSync(path21.join(dir, "Pods"))) return;
|
|
38308
38367
|
if (!this.ops.which("pod")) {
|
|
38309
38368
|
this.log("ERROR: this repo uses CocoaPods (Podfile, no Pods/) and pod is not on PATH.");
|
|
38310
38369
|
this.log(" Install CocoaPods, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way.");
|
|
@@ -38330,8 +38389,8 @@ var init_provision = __esm({
|
|
|
38330
38389
|
// ── monorepo root ──
|
|
38331
38390
|
async provisionMonorepoRoot() {
|
|
38332
38391
|
if (!this.relPrefix || !this.worktreeDir) return;
|
|
38333
|
-
if (!
|
|
38334
|
-
if (
|
|
38392
|
+
if (!fs21.existsSync(path21.join(this.worktreeDir, "package.json"))) return;
|
|
38393
|
+
if (fs21.existsSync(path21.join(this.worktreeDir, "node_modules"))) return;
|
|
38335
38394
|
const manager = nodePackageManager(this.worktreeDir, this.env, this.ops);
|
|
38336
38395
|
this.log(`Installing monorepo root dependencies in ${this.worktreeDir} with ${manager}...`);
|
|
38337
38396
|
const code = await nodeInstall(
|
|
@@ -38454,8 +38513,8 @@ function seedGitExclude(repoRoot, git2 = defaultGit) {
|
|
|
38454
38513
|
if (!commonDir) return;
|
|
38455
38514
|
const resolved = path22.isAbsolute(commonDir) ? commonDir : path22.resolve(repoRoot, commonDir);
|
|
38456
38515
|
const excludeFile = path22.join(resolved, "info", "exclude");
|
|
38457
|
-
if (!
|
|
38458
|
-
const existing =
|
|
38516
|
+
if (!fs22.existsSync(path22.dirname(excludeFile))) return;
|
|
38517
|
+
const existing = fs22.existsSync(excludeFile) ? fs22.readFileSync(excludeFile, "utf8") : "";
|
|
38459
38518
|
const lines = new Set(existing.split("\n"));
|
|
38460
38519
|
let appended = "";
|
|
38461
38520
|
for (const pattern of GIT_EXCLUDE_PATTERNS) {
|
|
@@ -38464,7 +38523,7 @@ function seedGitExclude(repoRoot, git2 = defaultGit) {
|
|
|
38464
38523
|
}
|
|
38465
38524
|
if (!appended) return;
|
|
38466
38525
|
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
38467
|
-
|
|
38526
|
+
fs22.appendFileSync(excludeFile, prefix + appended);
|
|
38468
38527
|
}
|
|
38469
38528
|
function resolveResumeSession(repoPath, agentId) {
|
|
38470
38529
|
const session = readSlotRegistry(repoPath, agentId);
|
|
@@ -38477,7 +38536,7 @@ function resolveResumeSession(repoPath, agentId) {
|
|
|
38477
38536
|
};
|
|
38478
38537
|
}
|
|
38479
38538
|
const workDir = session?.workDir ?? "";
|
|
38480
|
-
if (!workDir || !
|
|
38539
|
+
if (!workDir || !fs22.existsSync(workDir) || !fs22.statSync(workDir).isDirectory()) {
|
|
38481
38540
|
return {
|
|
38482
38541
|
ok: false,
|
|
38483
38542
|
code: "missing-work-dir",
|
|
@@ -38485,7 +38544,7 @@ function resolveResumeSession(repoPath, agentId) {
|
|
|
38485
38544
|
};
|
|
38486
38545
|
}
|
|
38487
38546
|
const envFile = path22.join(workDir, `.env.agent.${agentId}`);
|
|
38488
|
-
if (!
|
|
38547
|
+
if (!fs22.existsSync(envFile)) {
|
|
38489
38548
|
return {
|
|
38490
38549
|
ok: false,
|
|
38491
38550
|
code: "missing-env-file",
|
|
@@ -38517,7 +38576,7 @@ function removeSessionWorktree(options) {
|
|
|
38517
38576
|
}
|
|
38518
38577
|
const owned = options.mode === void 0 || options.mode === "worktree";
|
|
38519
38578
|
if (!owned) {
|
|
38520
|
-
if (worktreePath &&
|
|
38579
|
+
if (worktreePath && fs22.existsSync(worktreePath) && options.mode === "external") {
|
|
38521
38580
|
result.preservedWorktree = worktreePath;
|
|
38522
38581
|
}
|
|
38523
38582
|
tryGit3(git2, ["worktree", "prune"], options.repoRoot);
|
|
@@ -38531,17 +38590,17 @@ function removeSessionWorktree(options) {
|
|
|
38531
38590
|
}
|
|
38532
38591
|
return result;
|
|
38533
38592
|
}
|
|
38534
|
-
if (worktreePath &&
|
|
38593
|
+
if (worktreePath && fs22.existsSync(worktreePath)) {
|
|
38535
38594
|
for (const name of [
|
|
38536
38595
|
`.env.agent.${options.agentId}`,
|
|
38537
38596
|
`ecosystem.agent.${options.agentId}.config.cjs`
|
|
38538
38597
|
]) {
|
|
38539
|
-
|
|
38598
|
+
fs22.rmSync(path22.join(worktreePath, name), { force: true });
|
|
38540
38599
|
}
|
|
38541
38600
|
try {
|
|
38542
38601
|
git2(["worktree", "remove", worktreePath, "--force"], options.repoRoot);
|
|
38543
38602
|
} catch {
|
|
38544
|
-
|
|
38603
|
+
fs22.rmSync(worktreePath, { recursive: true, force: true });
|
|
38545
38604
|
}
|
|
38546
38605
|
result.removedWorktree = worktreePath;
|
|
38547
38606
|
}
|
|
@@ -38556,12 +38615,12 @@ function removeSessionWorktree(options) {
|
|
|
38556
38615
|
}
|
|
38557
38616
|
return result;
|
|
38558
38617
|
}
|
|
38559
|
-
var import_child_process5,
|
|
38618
|
+
var import_child_process5, fs22, os8, path22, crypto6, defaultGit, GIT_EXCLUDE_PATTERNS;
|
|
38560
38619
|
var init_worktree = __esm({
|
|
38561
38620
|
"src/runtime/worktree.ts"() {
|
|
38562
38621
|
"use strict";
|
|
38563
38622
|
import_child_process5 = require("child_process");
|
|
38564
|
-
|
|
38623
|
+
fs22 = __toESM(require("fs"));
|
|
38565
38624
|
os8 = __toESM(require("os"));
|
|
38566
38625
|
path22 = __toESM(require("path"));
|
|
38567
38626
|
crypto6 = __toESM(require("crypto"));
|
|
@@ -38621,8 +38680,8 @@ function appendTelemetryEnvToFile(envFilePath, attrs) {
|
|
|
38621
38680
|
${TELEMETRY_MARKER_END}
|
|
38622
38681
|
`;
|
|
38623
38682
|
let existing = "";
|
|
38624
|
-
if (
|
|
38625
|
-
existing =
|
|
38683
|
+
if (fs23.existsSync(envFilePath)) {
|
|
38684
|
+
existing = fs23.readFileSync(envFilePath, "utf8");
|
|
38626
38685
|
const start = existing.indexOf(TELEMETRY_MARKER_START);
|
|
38627
38686
|
if (start >= 0) {
|
|
38628
38687
|
const end = existing.indexOf(TELEMETRY_MARKER_END, start);
|
|
@@ -38633,15 +38692,15 @@ ${TELEMETRY_MARKER_END}
|
|
|
38633
38692
|
}
|
|
38634
38693
|
}
|
|
38635
38694
|
}
|
|
38636
|
-
|
|
38695
|
+
fs23.mkdirSync(path23.dirname(envFilePath), { recursive: true });
|
|
38637
38696
|
const combined = (existing.replace(/\n+$/, "\n") + block).replace(/^\n+/, "");
|
|
38638
|
-
|
|
38697
|
+
fs23.writeFileSync(envFilePath, combined.endsWith("\n") ? combined : combined + "\n");
|
|
38639
38698
|
}
|
|
38640
|
-
var
|
|
38699
|
+
var fs23, path23, TELEMETRY_MARKER_START, TELEMETRY_MARKER_END;
|
|
38641
38700
|
var init_telemetry_env = __esm({
|
|
38642
38701
|
"src/core/telemetry-env.ts"() {
|
|
38643
38702
|
"use strict";
|
|
38644
|
-
|
|
38703
|
+
fs23 = __toESM(require("fs"));
|
|
38645
38704
|
path23 = __toESM(require("path"));
|
|
38646
38705
|
init_control_config();
|
|
38647
38706
|
init_shell();
|
|
@@ -38665,8 +38724,8 @@ function substituteEnvTemplate(template, values) {
|
|
|
38665
38724
|
}
|
|
38666
38725
|
function generateAgentEnvFile(options) {
|
|
38667
38726
|
const templatePath = options.templatePath ?? path24.join(options.harnessDir, "env.template");
|
|
38668
|
-
if (!
|
|
38669
|
-
const template =
|
|
38727
|
+
if (!fs24.existsSync(templatePath)) return false;
|
|
38728
|
+
const template = fs24.readFileSync(templatePath, "utf8");
|
|
38670
38729
|
const v2 = options.values;
|
|
38671
38730
|
const rendered = substituteEnvTemplate(template, {
|
|
38672
38731
|
AGENT_ID: v2.agentId,
|
|
@@ -38678,8 +38737,8 @@ function generateAgentEnvFile(options) {
|
|
|
38678
38737
|
BROWSER_PORT: v2.browserPort,
|
|
38679
38738
|
REPO_ROOT: v2.repoRoot
|
|
38680
38739
|
});
|
|
38681
|
-
|
|
38682
|
-
|
|
38740
|
+
fs24.mkdirSync(path24.dirname(options.envFile), { recursive: true });
|
|
38741
|
+
fs24.writeFileSync(options.envFile, rendered);
|
|
38683
38742
|
return true;
|
|
38684
38743
|
}
|
|
38685
38744
|
function appendSessionTelemetry(options) {
|
|
@@ -38707,11 +38766,11 @@ function appendSessionTelemetry(options) {
|
|
|
38707
38766
|
appendTelemetryEnvToFile(envFile, attrs);
|
|
38708
38767
|
return envFile;
|
|
38709
38768
|
}
|
|
38710
|
-
var
|
|
38769
|
+
var fs24, path24, AGENT_ENV_TEMPLATE_VARS;
|
|
38711
38770
|
var init_agent_env = __esm({
|
|
38712
38771
|
"src/runtime/agent-env.ts"() {
|
|
38713
38772
|
"use strict";
|
|
38714
|
-
|
|
38773
|
+
fs24 = __toESM(require("fs"));
|
|
38715
38774
|
path24 = __toESM(require("path"));
|
|
38716
38775
|
init_telemetry_env();
|
|
38717
38776
|
init_slot_registry();
|
|
@@ -38736,20 +38795,20 @@ function resolveTemplatesDir() {
|
|
|
38736
38795
|
path25.join(__dirname, "..", "harness", "templates")
|
|
38737
38796
|
];
|
|
38738
38797
|
for (const dir of candidates) {
|
|
38739
|
-
if (
|
|
38798
|
+
if (fs25.existsSync(path25.join(dir, "har-boilerplate"))) return dir;
|
|
38740
38799
|
}
|
|
38741
38800
|
throw new Error("Templates directory not found. Run npm run build.");
|
|
38742
38801
|
}
|
|
38743
38802
|
function resolveTemplateFile(name) {
|
|
38744
38803
|
const dir = resolveTemplatesDir();
|
|
38745
38804
|
const filePath = path25.join(dir, name);
|
|
38746
|
-
return
|
|
38805
|
+
return fs25.existsSync(filePath) ? filePath : null;
|
|
38747
38806
|
}
|
|
38748
|
-
var
|
|
38807
|
+
var fs25, path25;
|
|
38749
38808
|
var init_paths = __esm({
|
|
38750
38809
|
"src/utils/paths.ts"() {
|
|
38751
38810
|
"use strict";
|
|
38752
|
-
|
|
38811
|
+
fs25 = __toESM(require("fs"));
|
|
38753
38812
|
path25 = __toESM(require("path"));
|
|
38754
38813
|
}
|
|
38755
38814
|
});
|
|
@@ -38761,10 +38820,10 @@ function templatesDirFor(options) {
|
|
|
38761
38820
|
function readProfileManifest(profile, options) {
|
|
38762
38821
|
const templates = templatesDirFor(options);
|
|
38763
38822
|
const manifestPath = path26.join(templates, "profiles", profile, "profile.manifest.json");
|
|
38764
|
-
if (!
|
|
38823
|
+
if (!fs26.existsSync(manifestPath)) {
|
|
38765
38824
|
throw new Error(`Profile manifest not found: ${manifestPath}. Run npm run build.`);
|
|
38766
38825
|
}
|
|
38767
|
-
const parsed = ProfileManifestSchema.safeParse(JSON.parse(
|
|
38826
|
+
const parsed = ProfileManifestSchema.safeParse(JSON.parse(fs26.readFileSync(manifestPath, "utf8")));
|
|
38768
38827
|
if (!parsed.success) {
|
|
38769
38828
|
throw new Error(`Invalid profile manifest for ${profile}: ${parsed.error.message}`);
|
|
38770
38829
|
}
|
|
@@ -38782,7 +38841,7 @@ function readProfileCapabilities(profile, options) {
|
|
|
38782
38841
|
}
|
|
38783
38842
|
function resolveProfileBundleDir(bundle, options) {
|
|
38784
38843
|
const dir = path26.join(templatesDirFor(options), bundle.path);
|
|
38785
|
-
if (!
|
|
38844
|
+
if (!fs26.existsSync(dir)) {
|
|
38786
38845
|
throw new Error(`Profile bundle not found: ${bundle.id} (${bundle.path}). Run npm run build.`);
|
|
38787
38846
|
}
|
|
38788
38847
|
return dir;
|
|
@@ -38801,21 +38860,21 @@ function renderProfileDoc(profile, docName, options) {
|
|
|
38801
38860
|
const parts = sections.map((name) => {
|
|
38802
38861
|
const profilePath = path26.join(templates, "profiles", profile, "docs", dir, `${name}.md`);
|
|
38803
38862
|
const sharedPath = path26.join(templates, "shared-docs", dir, `${name}.md`);
|
|
38804
|
-
const sectionPath =
|
|
38805
|
-
if (!
|
|
38863
|
+
const sectionPath = fs26.existsSync(profilePath) ? profilePath : sharedPath;
|
|
38864
|
+
if (!fs26.existsSync(sectionPath)) {
|
|
38806
38865
|
throw new Error(`Doc section not found for ${profile}/${docName}: ${name} (${sectionPath})`);
|
|
38807
38866
|
}
|
|
38808
|
-
return
|
|
38867
|
+
return fs26.readFileSync(sectionPath, "utf8");
|
|
38809
38868
|
});
|
|
38810
38869
|
return parts.join("\n");
|
|
38811
38870
|
}
|
|
38812
38871
|
function readComposedTemplateContent(entry) {
|
|
38813
38872
|
if (entry.content !== void 0) return entry.content;
|
|
38814
|
-
return
|
|
38873
|
+
return fs26.readFileSync(entry.sourcePath, "utf8");
|
|
38815
38874
|
}
|
|
38816
38875
|
function walkTemplateFiles(dir, prefix = "") {
|
|
38817
38876
|
const out = [];
|
|
38818
|
-
for (const entry of
|
|
38877
|
+
for (const entry of fs26.readdirSync(dir, { withFileTypes: true })) {
|
|
38819
38878
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
38820
38879
|
if (entry.isDirectory()) {
|
|
38821
38880
|
out.push(...walkTemplateFiles(path26.join(dir, entry.name), rel));
|
|
@@ -38844,11 +38903,11 @@ function composeProfileTemplateMap(profile, options) {
|
|
|
38844
38903
|
}
|
|
38845
38904
|
return map;
|
|
38846
38905
|
}
|
|
38847
|
-
var
|
|
38906
|
+
var fs26, path26, ProfileBundleRefSchema, ProfileCapabilitiesSchema, ProfileManifestSchema;
|
|
38848
38907
|
var init_profiles = __esm({
|
|
38849
38908
|
"src/harness/profiles.ts"() {
|
|
38850
38909
|
"use strict";
|
|
38851
|
-
|
|
38910
|
+
fs26 = __toESM(require("fs"));
|
|
38852
38911
|
path26 = __toESM(require("path"));
|
|
38853
38912
|
init_zod();
|
|
38854
38913
|
init_paths();
|
|
@@ -38905,13 +38964,13 @@ function harnessUsesPm2(repoPath) {
|
|
|
38905
38964
|
const capabilities = harnessCapabilities(repoPath);
|
|
38906
38965
|
if (capabilities) return capabilities.processManager === "pm2";
|
|
38907
38966
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
38908
|
-
return
|
|
38967
|
+
return fs27.existsSync(path27.join(harnessRoot, ".har", "ecosystem.agent.template.cjs"));
|
|
38909
38968
|
}
|
|
38910
|
-
var
|
|
38969
|
+
var fs27, path27;
|
|
38911
38970
|
var init_capabilities = __esm({
|
|
38912
38971
|
"src/harness/capabilities.ts"() {
|
|
38913
38972
|
"use strict";
|
|
38914
|
-
|
|
38973
|
+
fs27 = __toESM(require("fs"));
|
|
38915
38974
|
path27 = __toESM(require("path"));
|
|
38916
38975
|
init_manifest();
|
|
38917
38976
|
init_env();
|
|
@@ -38922,7 +38981,7 @@ var init_capabilities = __esm({
|
|
|
38922
38981
|
// src/core/slot-ports.ts
|
|
38923
38982
|
function loadInfraState(harnessRoot, repoRoot) {
|
|
38924
38983
|
let statePath = path28.join(harnessRoot, ".har", "state", "infra.env");
|
|
38925
|
-
if (!
|
|
38984
|
+
if (!fs28.existsSync(statePath) && repoRoot) {
|
|
38926
38985
|
try {
|
|
38927
38986
|
const commonDir = (0, import_child_process6.execSync)("git rev-parse --git-common-dir", {
|
|
38928
38987
|
cwd: repoRoot,
|
|
@@ -38940,8 +38999,8 @@ function loadInfraState(harnessRoot, repoRoot) {
|
|
|
38940
38999
|
} catch {
|
|
38941
39000
|
}
|
|
38942
39001
|
}
|
|
38943
|
-
if (!
|
|
38944
|
-
return parseHarnessEnvSource(
|
|
39002
|
+
if (!fs28.existsSync(statePath)) return {};
|
|
39003
|
+
return parseHarnessEnvSource(fs28.readFileSync(statePath, "utf8")).values;
|
|
38945
39004
|
}
|
|
38946
39005
|
function portStep(env3) {
|
|
38947
39006
|
return Number(env3.HARNESS_PORT_STEP ?? 10);
|
|
@@ -39008,12 +39067,12 @@ function allocateAppPorts(repoPath, agentId) {
|
|
|
39008
39067
|
allocated: frontend !== feDefault || api !== apiDefault || debug !== debugDefault
|
|
39009
39068
|
};
|
|
39010
39069
|
}
|
|
39011
|
-
var import_child_process6,
|
|
39070
|
+
var import_child_process6, fs28, path28;
|
|
39012
39071
|
var init_slot_ports = __esm({
|
|
39013
39072
|
"src/core/slot-ports.ts"() {
|
|
39014
39073
|
"use strict";
|
|
39015
39074
|
import_child_process6 = require("child_process");
|
|
39016
|
-
|
|
39075
|
+
fs28 = __toESM(require("fs"));
|
|
39017
39076
|
path28 = __toESM(require("path"));
|
|
39018
39077
|
init_env();
|
|
39019
39078
|
init_manifest();
|
|
@@ -39082,9 +39141,9 @@ function infraStatePath(harnessDir) {
|
|
|
39082
39141
|
}
|
|
39083
39142
|
function readInfraState(harnessDir) {
|
|
39084
39143
|
const statePath = infraStatePath(harnessDir);
|
|
39085
|
-
if (!
|
|
39144
|
+
if (!fs29.existsSync(statePath)) return {};
|
|
39086
39145
|
const ports = {};
|
|
39087
|
-
for (const line of
|
|
39146
|
+
for (const line of fs29.readFileSync(statePath, "utf8").split("\n")) {
|
|
39088
39147
|
const match = line.match(/^export\s+([A-Z_]+)=(\d+)\s*$/);
|
|
39089
39148
|
if (match) ports[match[1]] = Number(match[2]);
|
|
39090
39149
|
}
|
|
@@ -39092,8 +39151,8 @@ function readInfraState(harnessDir) {
|
|
|
39092
39151
|
}
|
|
39093
39152
|
function writeInfraState(harnessDir, ports) {
|
|
39094
39153
|
const statePath = infraStatePath(harnessDir);
|
|
39095
|
-
|
|
39096
|
-
|
|
39154
|
+
fs29.mkdirSync(path29.dirname(statePath), { recursive: true });
|
|
39155
|
+
fs29.writeFileSync(
|
|
39097
39156
|
statePath,
|
|
39098
39157
|
`# Persisted by setup-infra.sh \u2014 host ports for shared docker compose services.
|
|
39099
39158
|
export AGENT_DB_PORT=${ports.AGENT_DB_PORT}
|
|
@@ -39254,7 +39313,7 @@ async function setupInfra(options) {
|
|
|
39254
39313
|
}
|
|
39255
39314
|
}
|
|
39256
39315
|
const sharedEcosystem = path29.join(harnessDir, "ecosystem.shared.config.cjs");
|
|
39257
|
-
if (
|
|
39316
|
+
if (fs29.existsSync(sharedEcosystem)) {
|
|
39258
39317
|
log("Starting shared app services from ecosystem.shared.config.cjs...");
|
|
39259
39318
|
const [pkgCmd, ...pkgArgs] = pkgExecPrefix;
|
|
39260
39319
|
exec(pkgCmd, [...pkgArgs, "pm2", "startOrReload", sharedEcosystem], { cwd: repoRoot });
|
|
@@ -39317,11 +39376,11 @@ async function removeMinioBucket(agentId, options) {
|
|
|
39317
39376
|
const port = options.minioPort ?? 19e3;
|
|
39318
39377
|
await request("DELETE", `http://localhost:${port}/agent-${agentId}?force=true`, "minioadmin:minioadmin");
|
|
39319
39378
|
}
|
|
39320
|
-
var
|
|
39379
|
+
var fs29, path29, INFRA_LANES, defaultHttpRequest;
|
|
39321
39380
|
var init_infra = __esm({
|
|
39322
39381
|
"src/runtime/infra.ts"() {
|
|
39323
39382
|
"use strict";
|
|
39324
|
-
|
|
39383
|
+
fs29 = __toESM(require("fs"));
|
|
39325
39384
|
path29 = __toESM(require("path"));
|
|
39326
39385
|
init_slot_ports();
|
|
39327
39386
|
init_exec();
|
|
@@ -39366,7 +39425,7 @@ function renderTemplate(template, vars) {
|
|
|
39366
39425
|
);
|
|
39367
39426
|
}
|
|
39368
39427
|
function generateEcosystemConfig(options) {
|
|
39369
|
-
const template =
|
|
39428
|
+
const template = fs30.readFileSync(options.templatePath, "utf8");
|
|
39370
39429
|
const rendered = renderTemplate(template, {
|
|
39371
39430
|
AGENT_ID: String(options.agentId),
|
|
39372
39431
|
HARNESS_PROJECT_NAME: options.projectName,
|
|
@@ -39374,7 +39433,7 @@ function generateEcosystemConfig(options) {
|
|
|
39374
39433
|
DEBUG_PORT: String(options.debugPort)
|
|
39375
39434
|
});
|
|
39376
39435
|
const configPath = path30.join(options.workDir, `ecosystem.agent.${options.agentId}.config.cjs`);
|
|
39377
|
-
|
|
39436
|
+
fs30.writeFileSync(configPath, rendered);
|
|
39378
39437
|
return configPath;
|
|
39379
39438
|
}
|
|
39380
39439
|
function pm2(args, options, cwd) {
|
|
@@ -39420,11 +39479,11 @@ async function waitForHealthCheck(options) {
|
|
|
39420
39479
|
log(`Check logs: ./.har/agent-cli.sh ${agentId} logs`);
|
|
39421
39480
|
return false;
|
|
39422
39481
|
}
|
|
39423
|
-
var
|
|
39482
|
+
var fs30, path30, defaultHttpStatus;
|
|
39424
39483
|
var init_process = __esm({
|
|
39425
39484
|
"src/runtime/process.ts"() {
|
|
39426
39485
|
"use strict";
|
|
39427
|
-
|
|
39486
|
+
fs30 = __toESM(require("fs"));
|
|
39428
39487
|
path30 = __toESM(require("path"));
|
|
39429
39488
|
init_exec();
|
|
39430
39489
|
defaultHttpStatus = async (url) => {
|
|
@@ -39452,7 +39511,7 @@ function simSlug(value) {
|
|
|
39452
39511
|
function repoDigest(repoRoot) {
|
|
39453
39512
|
let resolved = repoRoot;
|
|
39454
39513
|
try {
|
|
39455
|
-
resolved =
|
|
39514
|
+
resolved = fs31.realpathSync(repoRoot);
|
|
39456
39515
|
} catch {
|
|
39457
39516
|
}
|
|
39458
39517
|
return crypto7.createHash("sha1").update(resolved).digest("hex").slice(0, 6);
|
|
@@ -39473,7 +39532,7 @@ function claimFile(harnessDir, agentId) {
|
|
|
39473
39532
|
}
|
|
39474
39533
|
function writeClaim(harnessDir, agentId, udid, name, createdByHar, now = () => /* @__PURE__ */ new Date()) {
|
|
39475
39534
|
const file = claimFile(harnessDir, agentId);
|
|
39476
|
-
|
|
39535
|
+
fs31.mkdirSync(path31.dirname(file), { recursive: true });
|
|
39477
39536
|
const claim = {
|
|
39478
39537
|
agentId,
|
|
39479
39538
|
udid,
|
|
@@ -39481,21 +39540,21 @@ function writeClaim(harnessDir, agentId, udid, name, createdByHar, now = () => /
|
|
|
39481
39540
|
createdByHar,
|
|
39482
39541
|
claimedAt: now().toISOString()
|
|
39483
39542
|
};
|
|
39484
|
-
|
|
39543
|
+
fs31.writeFileSync(file, JSON.stringify(claim, null, 2) + "\n");
|
|
39485
39544
|
}
|
|
39486
39545
|
function readClaim(harnessDir, agentId) {
|
|
39487
39546
|
const file = claimFile(harnessDir, agentId);
|
|
39488
|
-
if (!
|
|
39547
|
+
if (!fs31.existsSync(file)) return void 0;
|
|
39489
39548
|
try {
|
|
39490
|
-
return JSON.parse(
|
|
39549
|
+
return JSON.parse(fs31.readFileSync(file, "utf8"));
|
|
39491
39550
|
} catch {
|
|
39492
39551
|
return void 0;
|
|
39493
39552
|
}
|
|
39494
39553
|
}
|
|
39495
39554
|
function claimOwnerOf(harnessDir, udid, selfAgentId, slotIsLive) {
|
|
39496
39555
|
const dir = claimsDir(harnessDir);
|
|
39497
|
-
if (!
|
|
39498
|
-
for (const entry of
|
|
39556
|
+
if (!fs31.existsSync(dir)) return void 0;
|
|
39557
|
+
for (const entry of fs31.readdirSync(dir)) {
|
|
39499
39558
|
const match = entry.match(/^agent-(\d+)\.json$/);
|
|
39500
39559
|
if (!match) continue;
|
|
39501
39560
|
const id = Number(match[1]);
|
|
@@ -39697,7 +39756,7 @@ function releaseSimulator(ctx, stdout = (message) => process.stdout.write(`${mes
|
|
|
39697
39756
|
const log = ctx.log ?? simLog;
|
|
39698
39757
|
const claim = readClaim(ctx.harnessDir, ctx.agentId);
|
|
39699
39758
|
if (claim) {
|
|
39700
|
-
|
|
39759
|
+
fs31.rmSync(claimFile(ctx.harnessDir, ctx.agentId), { force: true });
|
|
39701
39760
|
if (claim.createdByHar === true && claim.udid) {
|
|
39702
39761
|
simctl.tryCall(["shutdown", claim.udid]);
|
|
39703
39762
|
if (simctl.tryCall(["delete", claim.udid])) {
|
|
@@ -39710,12 +39769,12 @@ function releaseSimulator(ctx, stdout = (message) => process.stdout.write(`${mes
|
|
|
39710
39769
|
}
|
|
39711
39770
|
deleteDevicesWithPrefix(simctl, deviceLabelPrefix(ctx.env, ctx.repoRoot, ctx.agentId), log);
|
|
39712
39771
|
}
|
|
39713
|
-
var crypto7,
|
|
39772
|
+
var crypto7, fs31, path31, simLog, Simctl;
|
|
39714
39773
|
var init_xcode_sim = __esm({
|
|
39715
39774
|
"src/runtime/xcode-sim.ts"() {
|
|
39716
39775
|
"use strict";
|
|
39717
39776
|
crypto7 = __toESM(require("crypto"));
|
|
39718
|
-
|
|
39777
|
+
fs31 = __toESM(require("fs"));
|
|
39719
39778
|
path31 = __toESM(require("path"));
|
|
39720
39779
|
init_exec();
|
|
39721
39780
|
simLog = (message) => process.stderr.write(`==> simulator: ${message}
|
|
@@ -39853,7 +39912,7 @@ function inspectControlUpReadiness(repoPath) {
|
|
|
39853
39912
|
const control = controlContainerOnPort(containers, port);
|
|
39854
39913
|
const warnings = [];
|
|
39855
39914
|
const controlHarnessDir = path32.join(resolved, "control", ".har");
|
|
39856
|
-
const harnessSlot1Active =
|
|
39915
|
+
const harnessSlot1Active = fs32.existsSync(controlHarnessDir) && readSlotRegistry(path32.join(resolved, "control"), 1)?.status === "active";
|
|
39857
39916
|
if (control) {
|
|
39858
39917
|
return {
|
|
39859
39918
|
warnings,
|
|
@@ -39882,12 +39941,12 @@ function inspectControlUpReadiness(repoPath) {
|
|
|
39882
39941
|
harnessSlot1Active
|
|
39883
39942
|
};
|
|
39884
39943
|
}
|
|
39885
|
-
var import_child_process7,
|
|
39944
|
+
var import_child_process7, fs32, path32;
|
|
39886
39945
|
var init_control_port = __esm({
|
|
39887
39946
|
"src/core/control-port.ts"() {
|
|
39888
39947
|
"use strict";
|
|
39889
39948
|
import_child_process7 = require("child_process");
|
|
39890
|
-
|
|
39949
|
+
fs32 = __toESM(require("fs"));
|
|
39891
39950
|
path32 = __toESM(require("path"));
|
|
39892
39951
|
init_control_config();
|
|
39893
39952
|
init_slot_registry();
|
|
@@ -39922,20 +39981,20 @@ function sameGitCheckout2(a, b2) {
|
|
|
39922
39981
|
}
|
|
39923
39982
|
function discoverWorktree(harnessRoot, agentId, projectName) {
|
|
39924
39983
|
const session = readSlotRegistry(harnessRoot, agentId);
|
|
39925
|
-
if (session?.worktreePath &&
|
|
39984
|
+
if (session?.worktreePath && fs33.existsSync(session.worktreePath)) {
|
|
39926
39985
|
return session.worktreePath;
|
|
39927
39986
|
}
|
|
39928
39987
|
const legacy = path33.join(os9.homedir(), "worktrees", `${projectName}-agent-${agentId}`);
|
|
39929
|
-
if (
|
|
39988
|
+
if (fs33.existsSync(legacy) && sameGitCheckout2(harnessRoot, legacy)) return legacy;
|
|
39930
39989
|
const worktreesRoot = path33.join(os9.homedir(), "worktrees");
|
|
39931
|
-
if (!
|
|
39990
|
+
if (!fs33.existsSync(worktreesRoot)) return void 0;
|
|
39932
39991
|
const suffix = `-har-agent-${agentId}-`;
|
|
39933
39992
|
const relPrefix = runGit(harnessRoot, "rev-parse --show-prefix") ?? "";
|
|
39934
|
-
for (const name of
|
|
39993
|
+
for (const name of fs33.readdirSync(worktreesRoot)) {
|
|
39935
39994
|
if (!name.includes(suffix)) continue;
|
|
39936
39995
|
const candidate = path33.join(worktreesRoot, name);
|
|
39937
39996
|
if (!sameGitCheckout2(harnessRoot, candidate)) continue;
|
|
39938
|
-
if (!
|
|
39997
|
+
if (!fs33.existsSync(path33.join(candidate, relPrefix, `.env.agent.${agentId}`))) continue;
|
|
39939
39998
|
return candidate;
|
|
39940
39999
|
}
|
|
39941
40000
|
return void 0;
|
|
@@ -39947,9 +40006,9 @@ function collectOccupiedSlot(repoPath, agentId) {
|
|
|
39947
40006
|
const session = readSlotRegistry(harnessRoot, agentId);
|
|
39948
40007
|
const worktreePath = discoverWorktree(harnessRoot, agentId, projectName);
|
|
39949
40008
|
const workDir = session?.workDir;
|
|
39950
|
-
const envInWorkDir = workDir ?
|
|
39951
|
-
const envInRoot =
|
|
39952
|
-
const envInWorktree = worktreePath ?
|
|
40009
|
+
const envInWorkDir = workDir ? fs33.existsSync(path33.join(workDir, `.env.agent.${agentId}`)) : false;
|
|
40010
|
+
const envInRoot = fs33.existsSync(path33.join(harnessRoot, `.env.agent.${agentId}`));
|
|
40011
|
+
const envInWorktree = worktreePath ? fs33.existsSync(path33.join(worktreePath, `.env.agent.${agentId}`)) : false;
|
|
39953
40012
|
const active = session !== void 0 && session.status !== "completed" || envInWorkDir || envInRoot || envInWorktree;
|
|
39954
40013
|
if (!active) return void 0;
|
|
39955
40014
|
const dirty = worktreePath ? worktreeDirty(worktreePath) : void 0;
|
|
@@ -40040,11 +40099,11 @@ function checkLaunchGuard(repoPath, agentId, options = {}) {
|
|
|
40040
40099
|
reason: formatOccupiedSlot(slot, repoPath)
|
|
40041
40100
|
};
|
|
40042
40101
|
}
|
|
40043
|
-
var
|
|
40102
|
+
var fs33, os9, path33, import_child_process8;
|
|
40044
40103
|
var init_slot_launch_guard_occupied = __esm({
|
|
40045
40104
|
"src/core/slot-launch-guard-occupied.ts"() {
|
|
40046
40105
|
"use strict";
|
|
40047
|
-
|
|
40106
|
+
fs33 = __toESM(require("fs"));
|
|
40048
40107
|
os9 = __toESM(require("os"));
|
|
40049
40108
|
path33 = __toESM(require("path"));
|
|
40050
40109
|
import_child_process8 = require("child_process");
|
|
@@ -40096,40 +40155,40 @@ exit 0
|
|
|
40096
40155
|
`;
|
|
40097
40156
|
}
|
|
40098
40157
|
function upsertMarkedBlock(filePath, block) {
|
|
40099
|
-
if (!
|
|
40100
|
-
|
|
40158
|
+
if (!fs34.existsSync(filePath)) {
|
|
40159
|
+
fs34.writeFileSync(filePath, `#!/bin/sh
|
|
40101
40160
|
${block}
|
|
40102
40161
|
`, { mode: 493 });
|
|
40103
40162
|
return "created";
|
|
40104
40163
|
}
|
|
40105
|
-
const content =
|
|
40164
|
+
const content = fs34.readFileSync(filePath, "utf8");
|
|
40106
40165
|
if (content.includes(MARKER_START)) {
|
|
40107
40166
|
const pattern = new RegExp(
|
|
40108
40167
|
`${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}`
|
|
40109
40168
|
);
|
|
40110
|
-
|
|
40111
|
-
|
|
40169
|
+
fs34.writeFileSync(filePath, content.replace(pattern, block));
|
|
40170
|
+
fs34.chmodSync(filePath, 493);
|
|
40112
40171
|
return "updated";
|
|
40113
40172
|
}
|
|
40114
40173
|
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
40115
|
-
|
|
40174
|
+
fs34.writeFileSync(filePath, `${content}${suffix}
|
|
40116
40175
|
${block}
|
|
40117
40176
|
`);
|
|
40118
|
-
|
|
40177
|
+
fs34.chmodSync(filePath, 493);
|
|
40119
40178
|
return "appended";
|
|
40120
40179
|
}
|
|
40121
40180
|
function removeMarkedBlock(filePath) {
|
|
40122
|
-
if (!
|
|
40123
|
-
const content =
|
|
40181
|
+
if (!fs34.existsSync(filePath)) return false;
|
|
40182
|
+
const content = fs34.readFileSync(filePath, "utf8");
|
|
40124
40183
|
if (!content.includes(MARKER_START)) return false;
|
|
40125
40184
|
const pattern = new RegExp(
|
|
40126
40185
|
`\\n?${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}\\n?`
|
|
40127
40186
|
);
|
|
40128
40187
|
const stripped = content.replace(pattern, "\n");
|
|
40129
40188
|
if (stripped.replace(/^#!\/bin\/sh\n?/, "").trim() === "") {
|
|
40130
|
-
|
|
40189
|
+
fs34.rmSync(filePath);
|
|
40131
40190
|
} else {
|
|
40132
|
-
|
|
40191
|
+
fs34.writeFileSync(filePath, stripped);
|
|
40133
40192
|
}
|
|
40134
40193
|
return true;
|
|
40135
40194
|
}
|
|
@@ -40151,14 +40210,14 @@ Or re-run with --force to write into that directory anyway.`
|
|
|
40151
40210
|
);
|
|
40152
40211
|
}
|
|
40153
40212
|
const hooksDir = resolveHooksDir(checkout);
|
|
40154
|
-
|
|
40213
|
+
fs34.mkdirSync(hooksDir, { recursive: true });
|
|
40155
40214
|
const invocation = options.harInvocation ?? defaultHarInvocation();
|
|
40156
|
-
|
|
40215
|
+
fs34.writeFileSync(
|
|
40157
40216
|
path34.join(hooksDir, "har-pre-commit"),
|
|
40158
40217
|
buildHookScript(invocation, "check", "har: binary not found; skipping commit gate (reinstall with har hooks install)"),
|
|
40159
40218
|
{ mode: 493 }
|
|
40160
40219
|
);
|
|
40161
|
-
|
|
40220
|
+
fs34.writeFileSync(
|
|
40162
40221
|
path34.join(hooksDir, "har-post-commit"),
|
|
40163
40222
|
buildHookScript(invocation, "record-commit", "har: binary not found; skipping commit association"),
|
|
40164
40223
|
{ mode: 493 }
|
|
@@ -40177,8 +40236,8 @@ function uninstallHooks(repoPath) {
|
|
|
40177
40236
|
removed = removeMarkedBlock(path34.join(hooksDir, "post-commit")) || removed;
|
|
40178
40237
|
for (const file of ["har-pre-commit", "har-post-commit"]) {
|
|
40179
40238
|
const full = path34.join(hooksDir, file);
|
|
40180
|
-
if (
|
|
40181
|
-
|
|
40239
|
+
if (fs34.existsSync(full)) {
|
|
40240
|
+
fs34.rmSync(full);
|
|
40182
40241
|
removed = true;
|
|
40183
40242
|
}
|
|
40184
40243
|
}
|
|
@@ -40214,14 +40273,14 @@ function getHooksStatus(repoPath) {
|
|
|
40214
40273
|
const gate = getCommitGateConfig(checkout);
|
|
40215
40274
|
const hasBlock = (name) => {
|
|
40216
40275
|
const file = path34.join(hooksDir, name);
|
|
40217
|
-
return
|
|
40276
|
+
return fs34.existsSync(file) && fs34.readFileSync(file, "utf8").includes(MARKER_START);
|
|
40218
40277
|
};
|
|
40219
40278
|
return {
|
|
40220
40279
|
checkout,
|
|
40221
40280
|
hooksDir,
|
|
40222
40281
|
configuredHooksPath: getConfiguredHooksPath(checkout),
|
|
40223
|
-
preCommitInstalled: hasBlock("pre-commit") &&
|
|
40224
|
-
postCommitInstalled: hasBlock("post-commit") &&
|
|
40282
|
+
preCommitInstalled: hasBlock("pre-commit") && fs34.existsSync(path34.join(hooksDir, "har-pre-commit")),
|
|
40283
|
+
postCommitInstalled: hasBlock("post-commit") && fs34.existsSync(path34.join(hooksDir, "har-post-commit")),
|
|
40225
40284
|
gate,
|
|
40226
40285
|
effectiveMode: resolveEffectiveMode(checkout, gate)
|
|
40227
40286
|
};
|
|
@@ -40232,7 +40291,7 @@ function checkCommitGate(cwd) {
|
|
|
40232
40291
|
}
|
|
40233
40292
|
const checkout = resolveCheckoutRoot(cwd);
|
|
40234
40293
|
if (!checkout) return { exitCode: 0, messages: [] };
|
|
40235
|
-
if (!
|
|
40294
|
+
if (!fs34.existsSync(path34.join(checkout, ".har", "stages.json"))) {
|
|
40236
40295
|
return { exitCode: 0, messages: [] };
|
|
40237
40296
|
}
|
|
40238
40297
|
const gate = getCommitGateConfig(checkout);
|
|
@@ -40308,11 +40367,11 @@ async function recordCommitAssociation(cwd) {
|
|
|
40308
40367
|
return { attached: false };
|
|
40309
40368
|
}
|
|
40310
40369
|
}
|
|
40311
|
-
var
|
|
40370
|
+
var fs34, os10, path34, MARKER_START, MARKER_END, PRE_COMMIT_BLOCK, POST_COMMIT_BLOCK;
|
|
40312
40371
|
var init_hooks = __esm({
|
|
40313
40372
|
"src/core/hooks.ts"() {
|
|
40314
40373
|
"use strict";
|
|
40315
|
-
|
|
40374
|
+
fs34 = __toESM(require("fs"));
|
|
40316
40375
|
os10 = __toESM(require("os"));
|
|
40317
40376
|
path34 = __toESM(require("path"));
|
|
40318
40377
|
init_shell();
|
|
@@ -40813,9 +40872,9 @@ var init_slot_database = __esm({
|
|
|
40813
40872
|
// src/runtime/hooks.ts
|
|
40814
40873
|
function readHookHarnessEnv(harnessDir) {
|
|
40815
40874
|
const envPath = path37.join(harnessDir, "harness.env");
|
|
40816
|
-
if (!
|
|
40875
|
+
if (!fs35.existsSync(envPath)) return {};
|
|
40817
40876
|
try {
|
|
40818
|
-
return parseHarnessEnvSource(
|
|
40877
|
+
return parseHarnessEnvSource(fs35.readFileSync(envPath, "utf8")).values;
|
|
40819
40878
|
} catch {
|
|
40820
40879
|
return {};
|
|
40821
40880
|
}
|
|
@@ -40844,7 +40903,7 @@ function hookDisplayPath(hook) {
|
|
|
40844
40903
|
}
|
|
40845
40904
|
function runLifecycleHook(hook, context) {
|
|
40846
40905
|
const file = lifecycleHookPath(context.harnessDir, hook);
|
|
40847
|
-
if (!
|
|
40906
|
+
if (!fs35.existsSync(file)) return { ran: false, code: 0 };
|
|
40848
40907
|
context.log?.(`Running ${hookDisplayPath(hook)}...`);
|
|
40849
40908
|
const env3 = hookEnv(hook, context);
|
|
40850
40909
|
const cwd = context.workDir ?? path37.dirname(context.harnessDir);
|
|
@@ -40862,11 +40921,11 @@ function runLifecycleHook(hook, context) {
|
|
|
40862
40921
|
function postHookFailureMode(env3) {
|
|
40863
40922
|
return env3.HARNESS_HOOK_POST_FAILURE === "fail" ? "fail" : "warn";
|
|
40864
40923
|
}
|
|
40865
|
-
var
|
|
40924
|
+
var fs35, path37, import_child_process12, LIFECYCLE_HOOKS, HOOK_CONTRACT_VERSION, HOOKS_DIR;
|
|
40866
40925
|
var init_hooks2 = __esm({
|
|
40867
40926
|
"src/runtime/hooks.ts"() {
|
|
40868
40927
|
"use strict";
|
|
40869
|
-
|
|
40928
|
+
fs35 = __toESM(require("fs"));
|
|
40870
40929
|
path37 = __toESM(require("path"));
|
|
40871
40930
|
import_child_process12 = require("child_process");
|
|
40872
40931
|
init_schema2();
|
|
@@ -41009,7 +41068,7 @@ function detectProcessManager(repoPath) {
|
|
|
41009
41068
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
41010
41069
|
const manifest = readManifest(harnessRoot);
|
|
41011
41070
|
if (manifest?.profile === "ios") return "simulator";
|
|
41012
|
-
if (
|
|
41071
|
+
if (fs36.existsSync(path38.join(getHarnessDir(harnessRoot), "simulator.sh"))) return "simulator";
|
|
41013
41072
|
return "none";
|
|
41014
41073
|
}
|
|
41015
41074
|
function heredocEnvFile(envFile, agentId, workDir, worktreeDir) {
|
|
@@ -41021,8 +41080,8 @@ function heredocEnvFile(envFile, agentId, workDir, worktreeDir) {
|
|
|
41021
41080
|
"NODE_ENV=test",
|
|
41022
41081
|
""
|
|
41023
41082
|
].join("\n");
|
|
41024
|
-
|
|
41025
|
-
|
|
41083
|
+
fs36.mkdirSync(path38.dirname(envFile), { recursive: true });
|
|
41084
|
+
fs36.writeFileSync(envFile, content);
|
|
41026
41085
|
}
|
|
41027
41086
|
async function launchSession(options) {
|
|
41028
41087
|
const repoRoot = resolveHarnessRoot(options.repoPath);
|
|
@@ -41283,7 +41342,7 @@ async function launchSession(options) {
|
|
|
41283
41342
|
throw new Error("simulator acquisition failed");
|
|
41284
41343
|
}
|
|
41285
41344
|
({ udid: simUdid, name: simName } = sim);
|
|
41286
|
-
|
|
41345
|
+
fs36.appendFileSync(
|
|
41287
41346
|
session.envFile,
|
|
41288
41347
|
[
|
|
41289
41348
|
`HARNESS_SIMULATOR_UDID=${quoteEnvValue(simUdid)}`,
|
|
@@ -41391,20 +41450,20 @@ function seedExtraExcludePattern(repoRoot, pattern, exec) {
|
|
|
41391
41450
|
if (commonDir.code !== 0) return;
|
|
41392
41451
|
const resolved = path38.isAbsolute(commonDir.stdout.trim()) ? commonDir.stdout.trim() : path38.resolve(repoRoot, commonDir.stdout.trim());
|
|
41393
41452
|
const excludeFile = path38.join(resolved, "info", "exclude");
|
|
41394
|
-
if (!
|
|
41395
|
-
const existing =
|
|
41453
|
+
if (!fs36.existsSync(path38.dirname(excludeFile))) return;
|
|
41454
|
+
const existing = fs36.existsSync(excludeFile) ? fs36.readFileSync(excludeFile, "utf8") : "";
|
|
41396
41455
|
if (existing.split("\n").includes(pattern)) return;
|
|
41397
|
-
|
|
41456
|
+
fs36.appendFileSync(excludeFile, `${pattern}
|
|
41398
41457
|
`);
|
|
41399
41458
|
}
|
|
41400
41459
|
function repoRooted(requested, resolved) {
|
|
41401
41460
|
return path38.resolve(requested) === resolved ? requested : resolved;
|
|
41402
41461
|
}
|
|
41403
|
-
var
|
|
41462
|
+
var fs36, path38, stderrLine;
|
|
41404
41463
|
var init_launch = __esm({
|
|
41405
41464
|
"src/runtime/launch.ts"() {
|
|
41406
41465
|
"use strict";
|
|
41407
|
-
|
|
41466
|
+
fs36 = __toESM(require("fs"));
|
|
41408
41467
|
path38 = __toESM(require("path"));
|
|
41409
41468
|
init_env();
|
|
41410
41469
|
init_manifest();
|
|
@@ -41484,7 +41543,7 @@ async function teardownSession(options) {
|
|
|
41484
41543
|
];
|
|
41485
41544
|
for (const dir of [repoRoot, workDir]) {
|
|
41486
41545
|
if (!dir) continue;
|
|
41487
|
-
for (const file of generated(dir))
|
|
41546
|
+
for (const file of generated(dir)) fs37.rmSync(file, { force: true });
|
|
41488
41547
|
}
|
|
41489
41548
|
const removed = removeSessionWorktree({
|
|
41490
41549
|
repoRoot,
|
|
@@ -41528,11 +41587,11 @@ async function teardownSession(options) {
|
|
|
41528
41587
|
out(`\u2713 Agent ${agentId} torn down`);
|
|
41529
41588
|
return { code: 0 };
|
|
41530
41589
|
}
|
|
41531
|
-
var
|
|
41590
|
+
var fs37, path39, os11;
|
|
41532
41591
|
var init_teardown = __esm({
|
|
41533
41592
|
"src/runtime/teardown.ts"() {
|
|
41534
41593
|
"use strict";
|
|
41535
|
-
|
|
41594
|
+
fs37 = __toESM(require("fs"));
|
|
41536
41595
|
path39 = __toESM(require("path"));
|
|
41537
41596
|
os11 = __toESM(require("os"));
|
|
41538
41597
|
init_env();
|
|
@@ -41554,7 +41613,7 @@ var init_teardown = __esm({
|
|
|
41554
41613
|
// src/runtime/verify.ts
|
|
41555
41614
|
function resolveVerifyRunner(harnessDir) {
|
|
41556
41615
|
const installed = path40.join(harnessDir, "lib", "verify-runner.mjs");
|
|
41557
|
-
if (
|
|
41616
|
+
if (fs38.existsSync(installed)) return installed;
|
|
41558
41617
|
return path40.join(
|
|
41559
41618
|
resolveTemplatesDir(),
|
|
41560
41619
|
"runtime-bundles",
|
|
@@ -41615,11 +41674,11 @@ exec node ${JSON.stringify(resolveVerifyRunner(harnessDir))} --agent ${agentId}$
|
|
|
41615
41674
|
env: baseEnv
|
|
41616
41675
|
};
|
|
41617
41676
|
}
|
|
41618
|
-
var
|
|
41677
|
+
var fs38, path40, XC_TARGET_FLAGS_FUNCTION, XC_BLOCK, API_PORT_BLOCK, VerifyPlanError;
|
|
41619
41678
|
var init_verify = __esm({
|
|
41620
41679
|
"src/runtime/verify.ts"() {
|
|
41621
41680
|
"use strict";
|
|
41622
|
-
|
|
41681
|
+
fs38 = __toESM(require("fs"));
|
|
41623
41682
|
path40 = __toESM(require("path"));
|
|
41624
41683
|
init_paths();
|
|
41625
41684
|
init_manifest();
|
|
@@ -41949,13 +42008,13 @@ function resolveStageScriptPath(repoPath, stage) {
|
|
|
41949
42008
|
return path41.join(harnessDir, scriptName);
|
|
41950
42009
|
}
|
|
41951
42010
|
const stageScript = path41.join(harnessDir, "stages", `${stage.id}.sh`);
|
|
41952
|
-
if (
|
|
42011
|
+
if (fs39.existsSync(stageScript)) {
|
|
41953
42012
|
return stageScript;
|
|
41954
42013
|
}
|
|
41955
42014
|
const fallback = stage.kind === "inspect" ? "agent-cli.sh" : RUNTIME_SCRIPT_FOR_KIND[stage.kind];
|
|
41956
42015
|
if (fallback) {
|
|
41957
42016
|
const fallbackPath = path41.join(harnessDir, fallback);
|
|
41958
|
-
if (
|
|
42017
|
+
if (fs39.existsSync(fallbackPath)) return fallbackPath;
|
|
41959
42018
|
}
|
|
41960
42019
|
throw new Error(
|
|
41961
42020
|
`Stage "${stage.id}" has no runnable script. Add script to stages.json, create .har/stages/${stage.id}.sh, or run verification via har_run_verification.`
|
|
@@ -42036,8 +42095,8 @@ function inspectOp(stage) {
|
|
|
42036
42095
|
}
|
|
42037
42096
|
function harnessScriptIsLegacy(repoPath, scriptName) {
|
|
42038
42097
|
const file = path41.join(getHarnessDir(resolveHarnessRoot(repoPath)), scriptName);
|
|
42039
|
-
if (!
|
|
42040
|
-
return !
|
|
42098
|
+
if (!fs39.existsSync(file)) return false;
|
|
42099
|
+
return !fs39.readFileSync(file, "utf8").includes("exec har env");
|
|
42041
42100
|
}
|
|
42042
42101
|
function warnLegacyRuntimeScript(repoPath, scriptName) {
|
|
42043
42102
|
const key = `${path41.resolve(repoPath)}:${scriptName}`;
|
|
@@ -42149,11 +42208,11 @@ async function runPackageRuntimeStage(repoPath, stage, options, capture) {
|
|
|
42149
42208
|
}
|
|
42150
42209
|
return void 0;
|
|
42151
42210
|
}
|
|
42152
|
-
var
|
|
42211
|
+
var fs39, path41, RUNTIME_SCRIPT_FOR_KIND, warnedLegacyScripts, LocalScriptExecutor, localScriptExecutor;
|
|
42153
42212
|
var init_local_executor = __esm({
|
|
42154
42213
|
"src/core/local-executor.ts"() {
|
|
42155
42214
|
"use strict";
|
|
42156
|
-
|
|
42215
|
+
fs39 = __toESM(require("fs"));
|
|
42157
42216
|
path41 = __toESM(require("path"));
|
|
42158
42217
|
init_manifest();
|
|
42159
42218
|
init_env();
|
|
@@ -42211,10 +42270,10 @@ var init_local_executor = __esm({
|
|
|
42211
42270
|
const harnessDir = getHarnessDir(repoPath);
|
|
42212
42271
|
const artifactsDirName = getArtifactsDir(repoPath);
|
|
42213
42272
|
const artifactsDir = path41.join(harnessDir, artifactsDirName);
|
|
42214
|
-
if (!
|
|
42273
|
+
if (!fs39.existsSync(artifactsDir)) return [];
|
|
42215
42274
|
const entries = [];
|
|
42216
42275
|
const walk = (dir, prefix) => {
|
|
42217
|
-
for (const entry of
|
|
42276
|
+
for (const entry of fs39.readdirSync(dir, { withFileTypes: true })) {
|
|
42218
42277
|
const full = path41.join(dir, entry.name);
|
|
42219
42278
|
const relative6 = path41.join(prefix, entry.name);
|
|
42220
42279
|
if (entry.isDirectory()) {
|
|
@@ -42222,7 +42281,7 @@ var init_local_executor = __esm({
|
|
|
42222
42281
|
continue;
|
|
42223
42282
|
}
|
|
42224
42283
|
if (filter2?.stageId && !relative6.includes(filter2.stageId)) continue;
|
|
42225
|
-
const stat =
|
|
42284
|
+
const stat = fs39.statSync(full);
|
|
42226
42285
|
entries.push({
|
|
42227
42286
|
path: full,
|
|
42228
42287
|
relativePath: relative6,
|
|
@@ -42281,11 +42340,11 @@ function gitPrefix2(cwd) {
|
|
|
42281
42340
|
}
|
|
42282
42341
|
function discoverSessionWorktreePath(harnessRoot, agentId) {
|
|
42283
42342
|
const worktreesRoot = path42.join(os12.homedir(), "worktrees");
|
|
42284
|
-
if (!
|
|
42343
|
+
if (!fs40.existsSync(worktreesRoot)) return void 0;
|
|
42285
42344
|
const suffix = `-har-agent-${agentId}-`;
|
|
42286
42345
|
const relPrefix = gitPrefix2(harnessRoot);
|
|
42287
|
-
const matches =
|
|
42288
|
-
(candidate) => sameGitCheckout3(harnessRoot, candidate) &&
|
|
42346
|
+
const matches = fs40.readdirSync(worktreesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.includes(suffix)).map((entry) => path42.join(worktreesRoot, entry.name)).filter(
|
|
42347
|
+
(candidate) => sameGitCheckout3(harnessRoot, candidate) && fs40.existsSync(path42.join(candidate, relPrefix, `.env.agent.${agentId}`))
|
|
42289
42348
|
);
|
|
42290
42349
|
return matches.sort()[0];
|
|
42291
42350
|
}
|
|
@@ -42293,7 +42352,7 @@ function resolveAgentEnvFile(harnessRoot, agentId) {
|
|
|
42293
42352
|
const session = readSlotRegistry(harnessRoot, agentId);
|
|
42294
42353
|
if (session?.workDir) {
|
|
42295
42354
|
const inWorkDir = path42.join(session.workDir, `.env.agent.${agentId}`);
|
|
42296
|
-
if (
|
|
42355
|
+
if (fs40.existsSync(inWorkDir)) return inWorkDir;
|
|
42297
42356
|
}
|
|
42298
42357
|
const env3 = readHarnessEnv(harnessRoot);
|
|
42299
42358
|
const projectName = env3.HARNESS_PROJECT_NAME ?? path42.basename(harnessRoot);
|
|
@@ -42302,16 +42361,16 @@ function resolveAgentEnvFile(harnessRoot, agentId) {
|
|
|
42302
42361
|
path42.join(harnessRoot, `.env.agent.${agentId}`),
|
|
42303
42362
|
path42.join(os12.homedir(), "worktrees", `${projectName}-agent-${agentId}`, relPrefix, `.env.agent.${agentId}`)
|
|
42304
42363
|
]) {
|
|
42305
|
-
if (
|
|
42364
|
+
if (fs40.existsSync(candidate)) return candidate;
|
|
42306
42365
|
}
|
|
42307
42366
|
const worktreesRoot = path42.join(os12.homedir(), "worktrees");
|
|
42308
|
-
if (!
|
|
42367
|
+
if (!fs40.existsSync(worktreesRoot)) return void 0;
|
|
42309
42368
|
const suffix = `-har-agent-${agentId}-`;
|
|
42310
|
-
for (const name of
|
|
42369
|
+
for (const name of fs40.readdirSync(worktreesRoot).sort()) {
|
|
42311
42370
|
if (!name.includes(suffix)) continue;
|
|
42312
42371
|
const candidateDir = path42.join(worktreesRoot, name);
|
|
42313
42372
|
const candidate = path42.join(candidateDir, relPrefix, `.env.agent.${agentId}`);
|
|
42314
|
-
if (!
|
|
42373
|
+
if (!fs40.existsSync(candidate)) continue;
|
|
42315
42374
|
if (!sameGitCheckout3(harnessRoot, candidateDir)) continue;
|
|
42316
42375
|
return candidate;
|
|
42317
42376
|
}
|
|
@@ -42319,7 +42378,7 @@ function resolveAgentEnvFile(harnessRoot, agentId) {
|
|
|
42319
42378
|
}
|
|
42320
42379
|
function parseEnvFilePorts(envFile) {
|
|
42321
42380
|
const values = {};
|
|
42322
|
-
for (const line of
|
|
42381
|
+
for (const line of fs40.readFileSync(envFile, "utf8").split("\n")) {
|
|
42323
42382
|
const match = line.match(/^(?:export\s+)?([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
42324
42383
|
if (!match) continue;
|
|
42325
42384
|
values[match[1]] = match[2].replace(/^["']|["']$/g, "");
|
|
@@ -42347,8 +42406,8 @@ function loadAgentPorts(harnessRoot, agentId) {
|
|
|
42347
42406
|
const allocated = allocateAppPorts(harnessRoot, agentId);
|
|
42348
42407
|
const infraEnv = path42.join(getHarnessDir(harnessRoot), "state", "infra.env");
|
|
42349
42408
|
const infraState = {};
|
|
42350
|
-
if (
|
|
42351
|
-
for (const line of
|
|
42409
|
+
if (fs40.existsSync(infraEnv)) {
|
|
42410
|
+
for (const line of fs40.readFileSync(infraEnv, "utf8").split("\n")) {
|
|
42352
42411
|
const match = line.match(/^(?:export\s+)?([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
42353
42412
|
if (match) infraState[match[1]] = match[2].replace(/^["']|["']$/g, "");
|
|
42354
42413
|
}
|
|
@@ -42437,11 +42496,11 @@ function collectSlotStatus(harnessRoot, agentId, runs, pm2Procs, untrackedPaths)
|
|
|
42437
42496
|
"worktrees",
|
|
42438
42497
|
`${projectName}-agent-${agentId}`
|
|
42439
42498
|
);
|
|
42440
|
-
const worktreePath = session?.worktreePath &&
|
|
42499
|
+
const worktreePath = session?.worktreePath && fs40.existsSync(session.worktreePath) ? session.worktreePath : fs40.existsSync(legacyWorktreePath) ? legacyWorktreePath : discoverSessionWorktreePath(harnessRoot, agentId);
|
|
42441
42500
|
const workDir = resolveAgentWorkDir(harnessRoot, agentId);
|
|
42442
|
-
const envInWorkDir = workDir ?
|
|
42443
|
-
const envInRoot =
|
|
42444
|
-
const envInWorktree = worktreePath ?
|
|
42501
|
+
const envInWorkDir = workDir ? fs40.existsSync(path42.join(workDir, `.env.agent.${agentId}`)) : false;
|
|
42502
|
+
const envInRoot = fs40.existsSync(path42.join(harnessRoot, `.env.agent.${agentId}`));
|
|
42503
|
+
const envInWorktree = worktreePath ? fs40.existsSync(path42.join(worktreePath, `.env.agent.${agentId}`)) : false;
|
|
42445
42504
|
const active = session !== void 0 && session.status !== "completed" || envInWorkDir || envInRoot || envInWorktree;
|
|
42446
42505
|
const latest = latestRunForAgent(runs, agentId);
|
|
42447
42506
|
const verifyRun = runs.find((r) => r.agentId === agentId && r.stageId === "verify");
|
|
@@ -42549,11 +42608,11 @@ function collectEnvironmentStatus(repoPath) {
|
|
|
42549
42608
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
42550
42609
|
};
|
|
42551
42610
|
}
|
|
42552
|
-
var
|
|
42611
|
+
var fs40, os12, path42, import_child_process14, BYPASS_WARNING_MS;
|
|
42553
42612
|
var init_slot_status = __esm({
|
|
42554
42613
|
"src/core/slot-status.ts"() {
|
|
42555
42614
|
"use strict";
|
|
42556
|
-
|
|
42615
|
+
fs40 = __toESM(require("fs"));
|
|
42557
42616
|
os12 = __toESM(require("os"));
|
|
42558
42617
|
path42 = __toESM(require("path"));
|
|
42559
42618
|
import_child_process14 = require("child_process");
|
|
@@ -43196,8 +43255,8 @@ function encodeClaudeProjectDir(cwd) {
|
|
|
43196
43255
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
43197
43256
|
}
|
|
43198
43257
|
function readJsonlRecords(filePath) {
|
|
43199
|
-
if (!
|
|
43200
|
-
const lines =
|
|
43258
|
+
if (!fs41.existsSync(filePath)) return [];
|
|
43259
|
+
const lines = fs41.readFileSync(filePath, "utf8").split(/\r?\n/);
|
|
43201
43260
|
const out = [];
|
|
43202
43261
|
for (const line of lines) {
|
|
43203
43262
|
const trimmed = line.trim();
|
|
@@ -43289,18 +43348,18 @@ function findMatchingClaudeTranscripts(slot) {
|
|
|
43289
43348
|
const fallbackTargets = slot.includeRepoPathFallback && slot.repoPath && !primaryTargets.includes(slot.repoPath) ? [slot.repoPath] : [];
|
|
43290
43349
|
if (primaryTargets.length === 0 && fallbackTargets.length === 0) return [];
|
|
43291
43350
|
const root = claudeProjectsRoot();
|
|
43292
|
-
if (!
|
|
43351
|
+
if (!fs41.existsSync(root)) return [];
|
|
43293
43352
|
const primary = [];
|
|
43294
43353
|
const fallback = [];
|
|
43295
|
-
for (const entry of
|
|
43354
|
+
for (const entry of fs41.readdirSync(root, { withFileTypes: true })) {
|
|
43296
43355
|
if (!entry.isDirectory()) continue;
|
|
43297
43356
|
const projectDir = path44.join(root, entry.name);
|
|
43298
43357
|
const primaryEncoded = primaryTargets.some((t) => entry.name === encodeClaudeProjectDir(t));
|
|
43299
43358
|
const fallbackEncoded = fallbackTargets.some((t) => entry.name === encodeClaudeProjectDir(t));
|
|
43300
|
-
for (const file of
|
|
43359
|
+
for (const file of fs41.readdirSync(projectDir)) {
|
|
43301
43360
|
if (!file.endsWith(".jsonl")) continue;
|
|
43302
43361
|
const filePath = path44.join(projectDir, file);
|
|
43303
|
-
const stat =
|
|
43362
|
+
const stat = fs41.statSync(filePath);
|
|
43304
43363
|
const records = readJsonlRecords(filePath);
|
|
43305
43364
|
let primaryHit = primaryEncoded;
|
|
43306
43365
|
let fallbackHit = fallbackEncoded;
|
|
@@ -43443,11 +43502,11 @@ function harvestClaudeEvents(slot) {
|
|
|
43443
43502
|
).flatMap((entry) => entry.match.records);
|
|
43444
43503
|
return capHarvestedEvents(extractPromptEvents(records, sessionKey, slot));
|
|
43445
43504
|
}
|
|
43446
|
-
var
|
|
43505
|
+
var fs41, os14, path44, MAX_HARVESTED_SESSION_EVENTS;
|
|
43447
43506
|
var init_claude = __esm({
|
|
43448
43507
|
"src/core/usage-harvest/claude.ts"() {
|
|
43449
43508
|
"use strict";
|
|
43450
|
-
|
|
43509
|
+
fs41 = __toESM(require("fs"));
|
|
43451
43510
|
os14 = __toESM(require("os"));
|
|
43452
43511
|
path44 = __toESM(require("path"));
|
|
43453
43512
|
init_schema2();
|
|
@@ -43464,8 +43523,8 @@ function codexSessionsRoot() {
|
|
|
43464
43523
|
return process.env.HAR_CODEX_SESSIONS_DIR ? path45.resolve(process.env.HAR_CODEX_SESSIONS_DIR) : path45.join(os15.homedir(), ".codex", "sessions");
|
|
43465
43524
|
}
|
|
43466
43525
|
function walkJsonlFiles(dir, out = []) {
|
|
43467
|
-
if (!
|
|
43468
|
-
for (const entry of
|
|
43526
|
+
if (!fs42.existsSync(dir)) return out;
|
|
43527
|
+
for (const entry of fs42.readdirSync(dir, { withFileTypes: true })) {
|
|
43469
43528
|
const full = path45.join(dir, entry.name);
|
|
43470
43529
|
if (entry.isDirectory()) walkJsonlFiles(full, out);
|
|
43471
43530
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) out.push(full);
|
|
@@ -43473,7 +43532,7 @@ function walkJsonlFiles(dir, out = []) {
|
|
|
43473
43532
|
return out;
|
|
43474
43533
|
}
|
|
43475
43534
|
function readJsonl(filePath) {
|
|
43476
|
-
const lines =
|
|
43535
|
+
const lines = fs42.readFileSync(filePath, "utf8").split(/\r?\n/);
|
|
43477
43536
|
const out = [];
|
|
43478
43537
|
for (const line of lines) {
|
|
43479
43538
|
const trimmed = line.trim();
|
|
@@ -43540,7 +43599,7 @@ function harvestCodexUsage(slot) {
|
|
|
43540
43599
|
const extracted = extractCodexTokens(records);
|
|
43541
43600
|
if (!extracted.cwd) continue;
|
|
43542
43601
|
if (extracted.tokensInput + extracted.tokensOutput + extracted.tokensCacheRead === 0) continue;
|
|
43543
|
-
const mtime =
|
|
43602
|
+
const mtime = fs42.statSync(file).mtimeMs;
|
|
43544
43603
|
if (workspaceMatchesTarget(extracted.cwd, primaryTargets)) {
|
|
43545
43604
|
if (mtime >= bestPrimaryMtime) {
|
|
43546
43605
|
bestPrimaryMtime = mtime;
|
|
@@ -43576,11 +43635,11 @@ function harvestCodexUsage(slot) {
|
|
|
43576
43635
|
lastSeenAt: best.seen?.lastAt ?? now
|
|
43577
43636
|
};
|
|
43578
43637
|
}
|
|
43579
|
-
var
|
|
43638
|
+
var fs42, os15, path45;
|
|
43580
43639
|
var init_codex = __esm({
|
|
43581
43640
|
"src/core/usage-harvest/codex.ts"() {
|
|
43582
43641
|
"use strict";
|
|
43583
|
-
|
|
43642
|
+
fs42 = __toESM(require("fs"));
|
|
43584
43643
|
os15 = __toESM(require("os"));
|
|
43585
43644
|
path45 = __toESM(require("path"));
|
|
43586
43645
|
init_schema2();
|
|
@@ -43639,8 +43698,8 @@ function getStatePath() {
|
|
|
43639
43698
|
function readState() {
|
|
43640
43699
|
const statePath = getStatePath();
|
|
43641
43700
|
try {
|
|
43642
|
-
if (!
|
|
43643
|
-
const parsed = JSON.parse(
|
|
43701
|
+
if (!fs43.existsSync(statePath)) return { states: [] };
|
|
43702
|
+
const parsed = JSON.parse(fs43.readFileSync(statePath, "utf8"));
|
|
43644
43703
|
return Array.isArray(parsed.states) ? parsed : { states: [] };
|
|
43645
43704
|
} catch {
|
|
43646
43705
|
return { states: [] };
|
|
@@ -43648,8 +43707,8 @@ function readState() {
|
|
|
43648
43707
|
}
|
|
43649
43708
|
function writeState(state) {
|
|
43650
43709
|
const statePath = getStatePath();
|
|
43651
|
-
|
|
43652
|
-
|
|
43710
|
+
fs43.mkdirSync(path46.dirname(statePath), { recursive: true });
|
|
43711
|
+
fs43.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n");
|
|
43653
43712
|
}
|
|
43654
43713
|
function readPortalWatermark(repoPath, portalUrl) {
|
|
43655
43714
|
const canonical = canonicalizeControlRepoPath(repoPath);
|
|
@@ -43714,11 +43773,11 @@ function selectSince(rows, since, getTimestamp) {
|
|
|
43714
43773
|
}
|
|
43715
43774
|
return { selected, maxSyncedAt };
|
|
43716
43775
|
}
|
|
43717
|
-
var
|
|
43776
|
+
var fs43, os16, path46;
|
|
43718
43777
|
var init_portal_watermark = __esm({
|
|
43719
43778
|
"src/core/portal-watermark.ts"() {
|
|
43720
43779
|
"use strict";
|
|
43721
|
-
|
|
43780
|
+
fs43 = __toESM(require("fs"));
|
|
43722
43781
|
os16 = __toESM(require("os"));
|
|
43723
43782
|
path46 = __toESM(require("path"));
|
|
43724
43783
|
init_control_repo_path();
|
|
@@ -44427,10 +44486,26 @@ async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, por
|
|
|
44427
44486
|
};
|
|
44428
44487
|
}
|
|
44429
44488
|
}
|
|
44489
|
+
function collectEnvironmentStatusForSync(canonicalPath, sourcePaths) {
|
|
44490
|
+
const collected = /* @__PURE__ */ new Map();
|
|
44491
|
+
const groups = [];
|
|
44492
|
+
for (const source of sourcePaths) {
|
|
44493
|
+
const key = path48.resolve(source);
|
|
44494
|
+
let status = collected.get(key);
|
|
44495
|
+
if (!status) {
|
|
44496
|
+
status = collectEnvironmentStatus(source);
|
|
44497
|
+
collected.set(key, status);
|
|
44498
|
+
}
|
|
44499
|
+
groups.push(status.slots);
|
|
44500
|
+
}
|
|
44501
|
+
const canonicalKey = path48.resolve(canonicalPath);
|
|
44502
|
+
const canonical = collected.get(canonicalKey) ?? collectEnvironmentStatus(canonicalPath);
|
|
44503
|
+
return { ...canonical, slots: mergeSlotStatuses(groups) };
|
|
44504
|
+
}
|
|
44430
44505
|
async function buildPortalPayload(repoPath, sourcePaths, controlApiUrl, since, full = false, portal) {
|
|
44431
44506
|
const rawRunsBySource = collectRunsBySource(sourcePaths);
|
|
44432
44507
|
const runs = mergeRunsBySource(rawRunsBySource);
|
|
44433
|
-
const status =
|
|
44508
|
+
const status = collectEnvironmentStatusForSync(repoPath, sourcePaths);
|
|
44434
44509
|
const manifest = readManifest(repoPath);
|
|
44435
44510
|
const stagesRegistry = readStageRegistry(repoPath);
|
|
44436
44511
|
const validations = collectValidationsForSync(sourcePaths);
|
|
@@ -44787,7 +44862,7 @@ async function syncRepoWithControl(options) {
|
|
|
44787
44862
|
}
|
|
44788
44863
|
const sourcePaths = resolveSyncSourcePaths(repoPath, workspacePath);
|
|
44789
44864
|
const runs = collectRunsForSync(sourcePaths);
|
|
44790
|
-
const status =
|
|
44865
|
+
const status = collectEnvironmentStatusForSync(repoPath, sourcePaths);
|
|
44791
44866
|
const cloudWork = collectWorkUnitsForSync(sourcePaths);
|
|
44792
44867
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
44793
44868
|
const response = await fetch(`${process.env.HAR_CLOUD_API_URL}/api/sync`, {
|
|
@@ -44862,7 +44937,7 @@ async function syncRepoRunsAndSlots(apiUrl, repoId, repoPath, workspacePath, dry
|
|
|
44862
44937
|
},
|
|
44863
44938
|
sourcePaths
|
|
44864
44939
|
);
|
|
44865
|
-
const status =
|
|
44940
|
+
const status = collectEnvironmentStatusForSync(repoPath, sourcePaths);
|
|
44866
44941
|
const slotsBody = SyncSlotsInputSchema.parse({
|
|
44867
44942
|
slots: status.slots,
|
|
44868
44943
|
generatedAt: status.generatedAt
|
|
@@ -52696,10 +52771,10 @@ var require_lib2 = __commonJS({
|
|
|
52696
52771
|
exports2.analyse = analyse;
|
|
52697
52772
|
var detectFile = (filepath, opts = {}) => new Promise((resolve70, reject) => {
|
|
52698
52773
|
let fd;
|
|
52699
|
-
const
|
|
52774
|
+
const fs82 = (0, node_1.default)();
|
|
52700
52775
|
const handler = (err, buffer) => {
|
|
52701
52776
|
if (fd) {
|
|
52702
|
-
|
|
52777
|
+
fs82.closeSync(fd);
|
|
52703
52778
|
}
|
|
52704
52779
|
if (err) {
|
|
52705
52780
|
reject(err);
|
|
@@ -52711,9 +52786,9 @@ var require_lib2 = __commonJS({
|
|
|
52711
52786
|
};
|
|
52712
52787
|
const sampleSize = (opts === null || opts === void 0 ? void 0 : opts.sampleSize) || 0;
|
|
52713
52788
|
if (sampleSize > 0) {
|
|
52714
|
-
fd =
|
|
52789
|
+
fd = fs82.openSync(filepath, "r");
|
|
52715
52790
|
let sample = Buffer.allocUnsafe(sampleSize);
|
|
52716
|
-
|
|
52791
|
+
fs82.read(fd, sample, 0, sampleSize, opts.offset, (err, bytesRead) => {
|
|
52717
52792
|
if (err) {
|
|
52718
52793
|
handler(err, null);
|
|
52719
52794
|
} else {
|
|
@@ -52725,22 +52800,22 @@ var require_lib2 = __commonJS({
|
|
|
52725
52800
|
});
|
|
52726
52801
|
return;
|
|
52727
52802
|
}
|
|
52728
|
-
|
|
52803
|
+
fs82.readFile(filepath, handler);
|
|
52729
52804
|
});
|
|
52730
52805
|
exports2.detectFile = detectFile;
|
|
52731
52806
|
var detectFileSync = (filepath, opts = {}) => {
|
|
52732
|
-
const
|
|
52807
|
+
const fs82 = (0, node_1.default)();
|
|
52733
52808
|
if (opts && opts.sampleSize) {
|
|
52734
|
-
const fd =
|
|
52809
|
+
const fd = fs82.openSync(filepath, "r");
|
|
52735
52810
|
let sample = Buffer.allocUnsafe(opts.sampleSize);
|
|
52736
|
-
const bytesRead =
|
|
52811
|
+
const bytesRead = fs82.readSync(fd, sample, 0, opts.sampleSize, opts.offset);
|
|
52737
52812
|
if (bytesRead < opts.sampleSize) {
|
|
52738
52813
|
sample = sample.subarray(0, bytesRead);
|
|
52739
52814
|
}
|
|
52740
|
-
|
|
52815
|
+
fs82.closeSync(fd);
|
|
52741
52816
|
return (0, exports2.detect)(sample);
|
|
52742
52817
|
}
|
|
52743
|
-
return (0, exports2.detect)(
|
|
52818
|
+
return (0, exports2.detect)(fs82.readFileSync(filepath));
|
|
52744
52819
|
};
|
|
52745
52820
|
exports2.detectFileSync = detectFileSync;
|
|
52746
52821
|
exports2.default = {
|
|
@@ -66095,7 +66170,7 @@ function installedPackageVersion(hooksHome) {
|
|
|
66095
66170
|
"otel-hook",
|
|
66096
66171
|
"package.json"
|
|
66097
66172
|
);
|
|
66098
|
-
const pkg = JSON.parse(
|
|
66173
|
+
const pkg = JSON.parse(fs70.readFileSync(pkgPath, "utf8"));
|
|
66099
66174
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
66100
66175
|
} catch {
|
|
66101
66176
|
return null;
|
|
@@ -66146,15 +66221,15 @@ function buildOtelHooksConfig(options) {
|
|
|
66146
66221
|
};
|
|
66147
66222
|
}
|
|
66148
66223
|
function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
|
|
66149
|
-
|
|
66224
|
+
fs70.mkdirSync(hooksHome, { recursive: true });
|
|
66150
66225
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
66151
|
-
|
|
66226
|
+
fs70.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
|
|
66152
66227
|
`);
|
|
66153
66228
|
return configPath;
|
|
66154
66229
|
}
|
|
66155
66230
|
function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
|
|
66156
|
-
|
|
66157
|
-
|
|
66231
|
+
fs70.mkdirSync(hooksHome, { recursive: true });
|
|
66232
|
+
fs70.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
|
|
66158
66233
|
const wrapperPath = getOtelHooksWrapperPath(hooksHome);
|
|
66159
66234
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
66160
66235
|
const stateDir = getOtelHooksStateDir(hooksHome);
|
|
@@ -66177,9 +66252,9 @@ set -uo pipefail
|
|
|
66177
66252
|
"$@" || true
|
|
66178
66253
|
exit 0
|
|
66179
66254
|
`;
|
|
66180
|
-
|
|
66255
|
+
fs70.writeFileSync(wrapperPath, script, { mode: 493 });
|
|
66181
66256
|
try {
|
|
66182
|
-
|
|
66257
|
+
fs70.chmodSync(wrapperPath, 493);
|
|
66183
66258
|
} catch {
|
|
66184
66259
|
}
|
|
66185
66260
|
return wrapperPath;
|
|
@@ -66192,7 +66267,7 @@ function commandExists3(command2) {
|
|
|
66192
66267
|
}
|
|
66193
66268
|
function resolveOtelHookCommand(hooksHome) {
|
|
66194
66269
|
const local = localOtelHookBin(hooksHome);
|
|
66195
|
-
if (
|
|
66270
|
+
if (fs70.existsSync(local)) return local;
|
|
66196
66271
|
return null;
|
|
66197
66272
|
}
|
|
66198
66273
|
function resolveHooksInstaller(hooksHome) {
|
|
@@ -66207,7 +66282,7 @@ function resolveHooksInstaller(hooksHome) {
|
|
|
66207
66282
|
return candidates.find((candidate) => commandExists3(candidate.command)) ?? null;
|
|
66208
66283
|
}
|
|
66209
66284
|
function tryInstallPackage(hooksHome) {
|
|
66210
|
-
|
|
66285
|
+
fs70.mkdirSync(hooksHome, { recursive: true });
|
|
66211
66286
|
const installer = resolveHooksInstaller(hooksHome);
|
|
66212
66287
|
if (!installer) {
|
|
66213
66288
|
return {
|
|
@@ -66220,7 +66295,7 @@ function tryInstallPackage(hooksHome) {
|
|
|
66220
66295
|
encoding: "utf8",
|
|
66221
66296
|
timeout: 18e4
|
|
66222
66297
|
});
|
|
66223
|
-
if (result.status === 0 &&
|
|
66298
|
+
if (result.status === 0 && fs70.existsSync(localOtelHookBin(hooksHome))) {
|
|
66224
66299
|
return { ok: true, detail: described };
|
|
66225
66300
|
}
|
|
66226
66301
|
return {
|
|
@@ -66252,8 +66327,8 @@ function removeLegacyPythonArtifacts(hooksHome) {
|
|
|
66252
66327
|
];
|
|
66253
66328
|
for (const target of legacyPaths) {
|
|
66254
66329
|
try {
|
|
66255
|
-
if (
|
|
66256
|
-
|
|
66330
|
+
if (fs70.existsSync(target)) {
|
|
66331
|
+
fs70.rmSync(target, { recursive: true, force: true });
|
|
66257
66332
|
}
|
|
66258
66333
|
} catch {
|
|
66259
66334
|
}
|
|
@@ -66301,10 +66376,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
|
|
|
66301
66376
|
};
|
|
66302
66377
|
}
|
|
66303
66378
|
function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
66304
|
-
if (!
|
|
66379
|
+
if (!fs70.existsSync(filePath)) return false;
|
|
66305
66380
|
let raw;
|
|
66306
66381
|
try {
|
|
66307
|
-
raw =
|
|
66382
|
+
raw = fs70.readFileSync(filePath, "utf8");
|
|
66308
66383
|
} catch {
|
|
66309
66384
|
return false;
|
|
66310
66385
|
}
|
|
@@ -66351,15 +66426,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
|
66351
66426
|
return changed;
|
|
66352
66427
|
};
|
|
66353
66428
|
if (!walk(parsed)) return false;
|
|
66354
|
-
|
|
66429
|
+
fs70.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
66355
66430
|
`);
|
|
66356
66431
|
return true;
|
|
66357
66432
|
}
|
|
66358
66433
|
function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
66359
|
-
if (!
|
|
66434
|
+
if (!fs70.existsSync(filePath)) return false;
|
|
66360
66435
|
let raw;
|
|
66361
66436
|
try {
|
|
66362
|
-
raw =
|
|
66437
|
+
raw = fs70.readFileSync(filePath, "utf8");
|
|
66363
66438
|
} catch {
|
|
66364
66439
|
return false;
|
|
66365
66440
|
}
|
|
@@ -66394,7 +66469,7 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
|
66394
66469
|
}
|
|
66395
66470
|
}
|
|
66396
66471
|
if (!changed) return false;
|
|
66397
|
-
|
|
66472
|
+
fs70.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
66398
66473
|
`);
|
|
66399
66474
|
return true;
|
|
66400
66475
|
}
|
|
@@ -66424,7 +66499,7 @@ function ensureOtelHooks(options) {
|
|
|
66424
66499
|
const hooksHome = getOtelHooksHome();
|
|
66425
66500
|
const errors = [];
|
|
66426
66501
|
const providersSetup = [];
|
|
66427
|
-
|
|
66502
|
+
fs70.mkdirSync(hooksHome, { recursive: true });
|
|
66428
66503
|
let otelHookCommand = resolveOtelHookCommand(hooksHome);
|
|
66429
66504
|
const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
|
|
66430
66505
|
if (needsInstall) {
|
|
@@ -66518,12 +66593,12 @@ function ensureOtelHooks(options) {
|
|
|
66518
66593
|
function disableOtelHooksExport() {
|
|
66519
66594
|
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
66520
66595
|
}
|
|
66521
|
-
var import_child_process19,
|
|
66596
|
+
var import_child_process19, fs70, os22, path79, OTEL_HOOKS_PACKAGE, HOOK_TIMEOUT_SECONDS, HOOK_EXPORT_TIMEOUT_MS, HOOK_FLUSH_TIMEOUT_MS, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
|
|
66522
66597
|
var init_otel_hooks = __esm({
|
|
66523
66598
|
"src/core/otel-hooks.ts"() {
|
|
66524
66599
|
"use strict";
|
|
66525
66600
|
import_child_process19 = require("child_process");
|
|
66526
|
-
|
|
66601
|
+
fs70 = __toESM(require("fs"));
|
|
66527
66602
|
os22 = __toESM(require("os"));
|
|
66528
66603
|
path79 = __toESM(require("path"));
|
|
66529
66604
|
init_control_config();
|
|
@@ -73395,12 +73470,12 @@ var require_dist = __commonJS({
|
|
|
73395
73470
|
throw new Error(`Unknown format "${name}"`);
|
|
73396
73471
|
return f2;
|
|
73397
73472
|
};
|
|
73398
|
-
function addFormats(ajv, list,
|
|
73473
|
+
function addFormats(ajv, list, fs82, exportName) {
|
|
73399
73474
|
var _a2;
|
|
73400
73475
|
var _b2;
|
|
73401
73476
|
(_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
73402
73477
|
for (const f2 of list)
|
|
73403
|
-
ajv.addFormat(f2,
|
|
73478
|
+
ajv.addFormat(f2, fs82[f2]);
|
|
73404
73479
|
}
|
|
73405
73480
|
module2.exports = exports2 = formatsPlugin;
|
|
73406
73481
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -78267,7 +78342,7 @@ init_sync_context();
|
|
|
78267
78342
|
var path51 = __toESM(require("path"));
|
|
78268
78343
|
|
|
78269
78344
|
// src/harness/agent-skills.ts
|
|
78270
|
-
var
|
|
78345
|
+
var fs44 = __toESM(require("fs"));
|
|
78271
78346
|
var os17 = __toESM(require("os"));
|
|
78272
78347
|
var path50 = __toESM(require("path"));
|
|
78273
78348
|
var readline = __toESM(require("readline"));
|
|
@@ -78279,17 +78354,17 @@ var AGENT_SKILL_TARGETS = ["claude", "cursor", "codex"];
|
|
|
78279
78354
|
var MANAGED_HEADER = "<!-- managed by har \u2014 regenerated by `har agents install` / `har env maintain`; edit at your own risk -->";
|
|
78280
78355
|
function agentSkillsTemplateDir() {
|
|
78281
78356
|
const dir = path50.join(resolveTemplatesDir(), "agent-skills");
|
|
78282
|
-
if (!
|
|
78357
|
+
if (!fs44.existsSync(dir)) {
|
|
78283
78358
|
throw new Error("Agent skills templates not found (templates/agent-skills). Run npm run build.");
|
|
78284
78359
|
}
|
|
78285
78360
|
return dir;
|
|
78286
78361
|
}
|
|
78287
78362
|
function readSkillsManifest() {
|
|
78288
78363
|
const manifestPath = path50.join(agentSkillsTemplateDir(), "skills.manifest.json");
|
|
78289
|
-
return JSON.parse(
|
|
78364
|
+
return JSON.parse(fs44.readFileSync(manifestPath, "utf8"));
|
|
78290
78365
|
}
|
|
78291
78366
|
function readSkillBody(entry) {
|
|
78292
|
-
return
|
|
78367
|
+
return fs44.readFileSync(path50.join(agentSkillsTemplateDir(), entry.body), "utf8");
|
|
78293
78368
|
}
|
|
78294
78369
|
function renderYamlValue(value) {
|
|
78295
78370
|
if (typeof value === "string") return JSON.stringify(value);
|
|
@@ -78353,7 +78428,7 @@ function resolveScaffoldPath(repoPath, file) {
|
|
|
78353
78428
|
return path50.join(repoPath, file.relPath);
|
|
78354
78429
|
}
|
|
78355
78430
|
function isHarManaged(filePath) {
|
|
78356
|
-
return
|
|
78431
|
+
return fs44.readFileSync(filePath, "utf8").includes(MANAGED_HEADER);
|
|
78357
78432
|
}
|
|
78358
78433
|
function scaffoldAgentSkills(repoPath, agents, options = {}) {
|
|
78359
78434
|
const written = [];
|
|
@@ -78361,7 +78436,7 @@ function scaffoldAgentSkills(repoPath, agents, options = {}) {
|
|
|
78361
78436
|
const records = [];
|
|
78362
78437
|
for (const file of renderSkillFiles(agents)) {
|
|
78363
78438
|
const destPath = resolveScaffoldPath(repoPath, file);
|
|
78364
|
-
if (
|
|
78439
|
+
if (fs44.existsSync(destPath) && !options.force && !isHarManaged(destPath)) {
|
|
78365
78440
|
warn(`Skipped ${file.relPath} \u2014 exists with user modifications (use --force to overwrite)`);
|
|
78366
78441
|
skipped.push(file.relPath);
|
|
78367
78442
|
continue;
|
|
@@ -78395,16 +78470,16 @@ function removeAgentSkills(repoPath, agents) {
|
|
|
78395
78470
|
const removed = [];
|
|
78396
78471
|
for (const file of renderSkillFiles(agents)) {
|
|
78397
78472
|
const destPath = resolveScaffoldPath(repoPath, file);
|
|
78398
|
-
if (!
|
|
78473
|
+
if (!fs44.existsSync(destPath)) continue;
|
|
78399
78474
|
if (!isHarManaged(destPath)) {
|
|
78400
78475
|
warn(`Kept ${file.relPath} \u2014 has user modifications`);
|
|
78401
78476
|
continue;
|
|
78402
78477
|
}
|
|
78403
|
-
|
|
78478
|
+
fs44.rmSync(destPath);
|
|
78404
78479
|
removed.push(file.relPath);
|
|
78405
78480
|
const parent = path50.dirname(destPath);
|
|
78406
|
-
if (
|
|
78407
|
-
|
|
78481
|
+
if (fs44.existsSync(parent) && fs44.readdirSync(parent).length === 0) {
|
|
78482
|
+
fs44.rmdirSync(parent);
|
|
78408
78483
|
}
|
|
78409
78484
|
}
|
|
78410
78485
|
const manifest = readManifest(repoPath);
|
|
@@ -78423,9 +78498,9 @@ function detectAgentTargets(repoPath) {
|
|
|
78423
78498
|
const manifest = readManifest(repoPath);
|
|
78424
78499
|
const scaffolded = new Set((manifest?.scaffoldedAgentFiles ?? []).map((entry) => entry.agent));
|
|
78425
78500
|
const detected = new Set(scaffolded);
|
|
78426
|
-
if (
|
|
78427
|
-
if (
|
|
78428
|
-
if (
|
|
78501
|
+
if (fs44.existsSync(path50.join(repoPath, ".claude"))) detected.add("claude");
|
|
78502
|
+
if (fs44.existsSync(path50.join(repoPath, ".cursor"))) detected.add("cursor");
|
|
78503
|
+
if (fs44.existsSync(path50.join(os17.homedir(), ".codex"))) detected.add("codex");
|
|
78429
78504
|
return AGENT_SKILL_TARGETS.filter((agent) => detected.has(agent));
|
|
78430
78505
|
}
|
|
78431
78506
|
function parseAgentTargets(raw) {
|
|
@@ -78558,7 +78633,7 @@ function handleRemove(argv) {
|
|
|
78558
78633
|
}
|
|
78559
78634
|
|
|
78560
78635
|
// src/cli/commands/env.ts
|
|
78561
|
-
var
|
|
78636
|
+
var fs73 = __toESM(require("fs"));
|
|
78562
78637
|
var path83 = __toESM(require("path"));
|
|
78563
78638
|
|
|
78564
78639
|
// src/cli/finish-command.ts
|
|
@@ -78569,17 +78644,17 @@ async function finishCommand(code) {
|
|
|
78569
78644
|
}
|
|
78570
78645
|
|
|
78571
78646
|
// src/core/harness.ts
|
|
78572
|
-
var
|
|
78647
|
+
var fs67 = __toESM(require("fs"));
|
|
78573
78648
|
var path75 = __toESM(require("path"));
|
|
78574
78649
|
|
|
78575
78650
|
// src/harness/generator.ts
|
|
78576
|
-
var
|
|
78651
|
+
var fs50 = __toESM(require("fs"));
|
|
78577
78652
|
var path57 = __toESM(require("path"));
|
|
78578
78653
|
init_file_ops();
|
|
78579
78654
|
init_logging();
|
|
78580
78655
|
|
|
78581
78656
|
// src/core/gitignore.ts
|
|
78582
|
-
var
|
|
78657
|
+
var fs45 = __toESM(require("fs"));
|
|
78583
78658
|
var path52 = __toESM(require("path"));
|
|
78584
78659
|
var HARNESS_ROOT_GITIGNORE_PATTERNS = [
|
|
78585
78660
|
".env.agent.*",
|
|
@@ -78587,7 +78662,7 @@ var HARNESS_ROOT_GITIGNORE_PATTERNS = [
|
|
|
78587
78662
|
];
|
|
78588
78663
|
function ensureRootGitignorePatterns(checkoutDir) {
|
|
78589
78664
|
const gitignorePath = path52.join(checkoutDir, ".gitignore");
|
|
78590
|
-
const content =
|
|
78665
|
+
const content = fs45.existsSync(gitignorePath) ? fs45.readFileSync(gitignorePath, "utf8") : "";
|
|
78591
78666
|
const lines = content.split("\n").map((line) => line.trim());
|
|
78592
78667
|
const missing = HARNESS_ROOT_GITIGNORE_PATTERNS.filter((pattern) => !lines.includes(pattern));
|
|
78593
78668
|
if (missing.length === 0) return;
|
|
@@ -78596,11 +78671,11 @@ function ensureRootGitignorePatterns(checkoutDir) {
|
|
|
78596
78671
|
const block = lines.some((line) => line.includes("HAR agent slot artifacts")) || header2.length === 0 ? `${missing.join("\n")}
|
|
78597
78672
|
` : `${header2}${missing.join("\n")}
|
|
78598
78673
|
`;
|
|
78599
|
-
|
|
78674
|
+
fs45.writeFileSync(gitignorePath, `${content}${suffix}${block}`);
|
|
78600
78675
|
}
|
|
78601
78676
|
|
|
78602
78677
|
// src/harness/gitignore-template.ts
|
|
78603
|
-
var
|
|
78678
|
+
var fs46 = __toESM(require("fs"));
|
|
78604
78679
|
var path53 = __toESM(require("path"));
|
|
78605
78680
|
var HARNESS_GITIGNORE_TEMPLATE = "gitignore.template";
|
|
78606
78681
|
var HARNESS_GITIGNORE_FILE = ".gitignore";
|
|
@@ -78612,22 +78687,22 @@ function templateFileForHarness(harnessFile) {
|
|
|
78612
78687
|
}
|
|
78613
78688
|
function resolveGitignoreTemplateSource(boilerplateDir) {
|
|
78614
78689
|
const primary = path53.join(boilerplateDir, HARNESS_GITIGNORE_TEMPLATE);
|
|
78615
|
-
if (
|
|
78690
|
+
if (fs46.existsSync(primary)) return primary;
|
|
78616
78691
|
const legacy = path53.join(boilerplateDir, HARNESS_GITIGNORE_FILE);
|
|
78617
|
-
if (
|
|
78692
|
+
if (fs46.existsSync(legacy)) return legacy;
|
|
78618
78693
|
return null;
|
|
78619
78694
|
}
|
|
78620
78695
|
function writeHarnessGitignore(harnessDir, boilerplateDir) {
|
|
78621
78696
|
const src = resolveGitignoreTemplateSource(boilerplateDir);
|
|
78622
78697
|
if (!src) return;
|
|
78623
|
-
|
|
78698
|
+
fs46.writeFileSync(path53.join(harnessDir, HARNESS_GITIGNORE_FILE), fs46.readFileSync(src, "utf8"));
|
|
78624
78699
|
}
|
|
78625
78700
|
function isExpectedHarnessOnlyFile(harnessFile, templateFiles) {
|
|
78626
78701
|
return harnessFile === HARNESS_GITIGNORE_FILE && templateFiles.includes(HARNESS_GITIGNORE_TEMPLATE);
|
|
78627
78702
|
}
|
|
78628
78703
|
|
|
78629
78704
|
// src/harness/drift.ts
|
|
78630
|
-
var
|
|
78705
|
+
var fs47 = __toESM(require("fs"));
|
|
78631
78706
|
var path54 = __toESM(require("path"));
|
|
78632
78707
|
init_env();
|
|
78633
78708
|
init_manifest();
|
|
@@ -78757,7 +78832,7 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
78757
78832
|
for (const file of templateFiles) {
|
|
78758
78833
|
const harnessFile = harnessFileForTemplate(file);
|
|
78759
78834
|
const harnessPath = path54.join(harnessDir, harnessFile);
|
|
78760
|
-
if (userOwnedFiles.has(harnessFile) &&
|
|
78835
|
+
if (userOwnedFiles.has(harnessFile) && fs47.existsSync(harnessPath)) {
|
|
78761
78836
|
ownedByUser.push(harnessFile);
|
|
78762
78837
|
continue;
|
|
78763
78838
|
}
|
|
@@ -78765,11 +78840,11 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
78765
78840
|
readComposedTemplateContent(composed.get(file)),
|
|
78766
78841
|
projectName
|
|
78767
78842
|
);
|
|
78768
|
-
if (!
|
|
78843
|
+
if (!fs47.existsSync(harnessPath)) {
|
|
78769
78844
|
missing.push(harnessFile);
|
|
78770
78845
|
continue;
|
|
78771
78846
|
}
|
|
78772
|
-
const installedChecksum = computeFileChecksum(
|
|
78847
|
+
const installedChecksum = computeFileChecksum(fs47.readFileSync(harnessPath, "utf8"));
|
|
78773
78848
|
const templateChecksum = computeFileChecksum(templateContent);
|
|
78774
78849
|
const recordedFile = fileBaseline?.[harnessFile];
|
|
78775
78850
|
const recordedTemplate = templateBaseline?.[harnessFile];
|
|
@@ -78782,10 +78857,10 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
78782
78857
|
else if (status === "upstream-updated") upstreamUpdated.push(harnessFile);
|
|
78783
78858
|
else conflict.push(harnessFile);
|
|
78784
78859
|
}
|
|
78785
|
-
if (
|
|
78786
|
-
for (const file of
|
|
78860
|
+
if (fs47.existsSync(harnessDir)) {
|
|
78861
|
+
for (const file of fs47.readdirSync(harnessDir)) {
|
|
78787
78862
|
const full = path54.join(harnessDir, file);
|
|
78788
|
-
if (!
|
|
78863
|
+
if (!fs47.statSync(full).isFile()) continue;
|
|
78789
78864
|
if (file === "manifest.json" || file === "plugins.json" || file.startsWith("ADAPT-PROMPT") || file.startsWith("MIGRATE-PROMPT")) {
|
|
78790
78865
|
continue;
|
|
78791
78866
|
}
|
|
@@ -78819,7 +78894,7 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
78819
78894
|
init_manifest();
|
|
78820
78895
|
|
|
78821
78896
|
// src/harness/plugin-ledger.ts
|
|
78822
|
-
var
|
|
78897
|
+
var fs48 = __toESM(require("fs"));
|
|
78823
78898
|
var path55 = __toESM(require("path"));
|
|
78824
78899
|
init_zod();
|
|
78825
78900
|
init_file_ops();
|
|
@@ -78847,9 +78922,9 @@ function getPluginLedgerPath(repoPath) {
|
|
|
78847
78922
|
}
|
|
78848
78923
|
function readPluginLedger(repoPath) {
|
|
78849
78924
|
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
78850
|
-
if (!
|
|
78925
|
+
if (!fs48.existsSync(ledgerPath)) return null;
|
|
78851
78926
|
try {
|
|
78852
|
-
const raw = JSON.parse(
|
|
78927
|
+
const raw = JSON.parse(fs48.readFileSync(ledgerPath, "utf8"));
|
|
78853
78928
|
const parsed = PluginLedgerSchema.safeParse(raw);
|
|
78854
78929
|
return parsed.success ? parsed.data : null;
|
|
78855
78930
|
} catch {
|
|
@@ -78859,8 +78934,8 @@ function readPluginLedger(repoPath) {
|
|
|
78859
78934
|
function writePluginLedger(repoPath, ledger) {
|
|
78860
78935
|
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
78861
78936
|
const harnessDir = path55.dirname(ledgerPath);
|
|
78862
|
-
if (!
|
|
78863
|
-
|
|
78937
|
+
if (!fs48.existsSync(harnessDir)) {
|
|
78938
|
+
fs48.mkdirSync(harnessDir, { recursive: true });
|
|
78864
78939
|
}
|
|
78865
78940
|
writeFileSafe(ledgerPath, `${JSON.stringify(ledger, null, 2)}
|
|
78866
78941
|
`);
|
|
@@ -78900,7 +78975,7 @@ init_schema2();
|
|
|
78900
78975
|
init_stages();
|
|
78901
78976
|
|
|
78902
78977
|
// src/harness/lifecycle-shims.ts
|
|
78903
|
-
var
|
|
78978
|
+
var fs49 = __toESM(require("fs"));
|
|
78904
78979
|
var path56 = __toESM(require("path"));
|
|
78905
78980
|
init_manifest();
|
|
78906
78981
|
init_stages();
|
|
@@ -78933,10 +79008,10 @@ function retireLifecycleShims(repoPath) {
|
|
|
78933
79008
|
const pruned = [];
|
|
78934
79009
|
for (const shim3 of LIFECYCLE_SHIM_FILES) {
|
|
78935
79010
|
const file = path56.join(harnessDir, shim3);
|
|
78936
|
-
if (!
|
|
78937
|
-
const content =
|
|
79011
|
+
if (!fs49.existsSync(file) || !fs49.statSync(file).isFile()) continue;
|
|
79012
|
+
const content = fs49.readFileSync(file, "utf8");
|
|
78938
79013
|
if (!isManagedShimContent(content)) continue;
|
|
78939
|
-
|
|
79014
|
+
fs49.rmSync(file);
|
|
78940
79015
|
pruned.push(shim3);
|
|
78941
79016
|
}
|
|
78942
79017
|
const stagesRewritten = stripLifecycleShimCommands(repoPath);
|
|
@@ -78972,21 +79047,21 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
|
78972
79047
|
const profile = options.profile ?? "default";
|
|
78973
79048
|
const profileManifest = readProfileManifest(profile);
|
|
78974
79049
|
const bundleIds = profileManifest.bundles.map((b2) => b2.id);
|
|
78975
|
-
if (
|
|
79050
|
+
if (fs50.existsSync(harnessDir) && !options.force) {
|
|
78976
79051
|
throw new Error(
|
|
78977
79052
|
'.har/ already exists. Use --force to overwrite or run "har env maintain" to update in place.'
|
|
78978
79053
|
);
|
|
78979
79054
|
}
|
|
78980
|
-
if (options.force &&
|
|
78981
|
-
|
|
79055
|
+
if (options.force && fs50.existsSync(harnessDir)) {
|
|
79056
|
+
fs50.rmSync(harnessDir, { recursive: true, force: true });
|
|
78982
79057
|
}
|
|
78983
|
-
|
|
79058
|
+
fs50.mkdirSync(harnessDir, { recursive: true });
|
|
78984
79059
|
for (const bundle of profileManifest.bundles) {
|
|
78985
79060
|
const bundleDir = resolveProfileBundleDir(bundle);
|
|
78986
79061
|
copyDirRecursive(bundleDir, harnessDir);
|
|
78987
79062
|
}
|
|
78988
79063
|
for (const docName of Object.keys(profileManifest.docs)) {
|
|
78989
|
-
|
|
79064
|
+
fs50.writeFileSync(path57.join(harnessDir, docName), renderProfileDoc(profile, docName));
|
|
78990
79065
|
}
|
|
78991
79066
|
const gitignoreSource = composeProfileTemplateMap(profile).get(HARNESS_GITIGNORE_TEMPLATE);
|
|
78992
79067
|
if (gitignoreSource) {
|
|
@@ -78995,10 +79070,10 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
|
78995
79070
|
syncAgentSlotsToHarnessEnv(repoPath);
|
|
78996
79071
|
retireLifecycleShims(repoPath);
|
|
78997
79072
|
const harnessEnvPath = path57.join(harnessDir, "harness.env");
|
|
78998
|
-
if (
|
|
78999
|
-
let content =
|
|
79073
|
+
if (fs50.existsSync(harnessEnvPath)) {
|
|
79074
|
+
let content = fs50.readFileSync(harnessEnvPath, "utf8");
|
|
79000
79075
|
content = substituteTemplateTokens(content, projectName);
|
|
79001
|
-
|
|
79076
|
+
fs50.writeFileSync(harnessEnvPath, content);
|
|
79002
79077
|
const validation2 = validateHarnessEnvSource(content);
|
|
79003
79078
|
if (!validation2.ok) {
|
|
79004
79079
|
const details = validation2.issues.filter((i) => i.severity === "error").map((i) => i.line !== void 0 ? `line ${i.line}: ${i.message}` : i.message).join("\n ");
|
|
@@ -79036,14 +79111,14 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
|
|
|
79036
79111
|
}
|
|
79037
79112
|
|
|
79038
79113
|
// src/harness/agent-md.ts
|
|
79039
|
-
var
|
|
79114
|
+
var fs52 = __toESM(require("fs"));
|
|
79040
79115
|
var path60 = __toESM(require("path"));
|
|
79041
79116
|
init_file_ops();
|
|
79042
79117
|
init_logging();
|
|
79043
79118
|
init_manifest();
|
|
79044
79119
|
|
|
79045
79120
|
// src/harness/instruction-files.ts
|
|
79046
|
-
var
|
|
79121
|
+
var fs51 = __toESM(require("fs"));
|
|
79047
79122
|
var os19 = __toESM(require("os"));
|
|
79048
79123
|
var path59 = __toESM(require("path"));
|
|
79049
79124
|
|
|
@@ -81795,12 +81870,12 @@ function outsideContentShrinkMessage(beforeLines, afterLines) {
|
|
|
81795
81870
|
}
|
|
81796
81871
|
function detectInstructionFiles(repoPath) {
|
|
81797
81872
|
return {
|
|
81798
|
-
agentsMd:
|
|
81799
|
-
agentMd:
|
|
81800
|
-
claudeMd:
|
|
81801
|
-
cursorDir:
|
|
81802
|
-
claudeDir:
|
|
81803
|
-
codexHome:
|
|
81873
|
+
agentsMd: fs51.existsSync(path59.join(repoPath, AGENTS_MD)),
|
|
81874
|
+
agentMd: fs51.existsSync(path59.join(repoPath, LEGACY_AGENT_MD)),
|
|
81875
|
+
claudeMd: fs51.existsSync(path59.join(repoPath, CLAUDE_MD)),
|
|
81876
|
+
cursorDir: fs51.existsSync(path59.join(repoPath, ".cursor")),
|
|
81877
|
+
claudeDir: fs51.existsSync(path59.join(repoPath, ".claude")),
|
|
81878
|
+
codexHome: fs51.existsSync(path59.join(os19.homedir(), ".codex"))
|
|
81804
81879
|
};
|
|
81805
81880
|
}
|
|
81806
81881
|
function formatDetectionReport(detection) {
|
|
@@ -81865,7 +81940,7 @@ function loadHarAgentsSectionFromTemplate(options = {}) {
|
|
|
81865
81940
|
if (!templatePath) {
|
|
81866
81941
|
throw new Error("AGENTS.md.template not found. Run npm run build.");
|
|
81867
81942
|
}
|
|
81868
|
-
const content =
|
|
81943
|
+
const content = fs51.readFileSync(templatePath, "utf8");
|
|
81869
81944
|
const start = content.indexOf(HAR_SECTION_START);
|
|
81870
81945
|
const end = content.indexOf(HAR_SECTION_END);
|
|
81871
81946
|
if (start === -1 || end === -1 || end < start) {
|
|
@@ -81883,7 +81958,7 @@ function loadAgentsMdTemplate() {
|
|
|
81883
81958
|
if (!templatePath) {
|
|
81884
81959
|
throw new Error("AGENTS.md.template not found. Run npm run build.");
|
|
81885
81960
|
}
|
|
81886
|
-
return
|
|
81961
|
+
return fs51.readFileSync(templatePath, "utf8");
|
|
81887
81962
|
}
|
|
81888
81963
|
function upsertMarkedBlock2(content, block, startMarker, endMarker) {
|
|
81889
81964
|
const existingBlock = findLastCompleteMarkedBlock(content, startMarker, endMarker);
|
|
@@ -81919,11 +81994,11 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
|
81919
81994
|
const dest = path59.join(repoPath, AGENTS_MD);
|
|
81920
81995
|
const ejected = readManifest(repoPath)?.ejected === true;
|
|
81921
81996
|
const section = loadHarAgentsSectionFromTemplate({ ejected });
|
|
81922
|
-
if (!
|
|
81997
|
+
if (!fs51.existsSync(dest)) {
|
|
81923
81998
|
writeFileSafe(dest, loadAgentsMdTemplate());
|
|
81924
81999
|
return "created";
|
|
81925
82000
|
}
|
|
81926
|
-
const existing =
|
|
82001
|
+
const existing = fs51.readFileSync(dest, "utf8");
|
|
81927
82002
|
const sanitized = stripClaudePointerFromAgentsMd(existing);
|
|
81928
82003
|
const { content, action } = upsertMarkedBlock2(
|
|
81929
82004
|
sanitized,
|
|
@@ -81950,13 +82025,13 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
|
81950
82025
|
function migrateLegacyAgentMd(repoPath) {
|
|
81951
82026
|
const legacyPath = path59.join(repoPath, LEGACY_AGENT_MD);
|
|
81952
82027
|
const agentsPath = path59.join(repoPath, AGENTS_MD);
|
|
81953
|
-
if (!
|
|
81954
|
-
const legacy =
|
|
81955
|
-
if (!
|
|
82028
|
+
if (!fs51.existsSync(legacyPath)) return false;
|
|
82029
|
+
const legacy = fs51.readFileSync(legacyPath, "utf8");
|
|
82030
|
+
if (!fs51.existsSync(agentsPath)) {
|
|
81956
82031
|
writeFileSafe(agentsPath, legacy);
|
|
81957
82032
|
upsertAgentsMdHarSection(repoPath);
|
|
81958
82033
|
} else {
|
|
81959
|
-
const agents =
|
|
82034
|
+
const agents = fs51.readFileSync(agentsPath, "utf8");
|
|
81960
82035
|
const legacyTrimmed = legacy.trim();
|
|
81961
82036
|
if (legacyTrimmed.length > 0 && !agents.includes(legacyTrimmed)) {
|
|
81962
82037
|
const suffix = agents.endsWith("\n") ? "" : "\n";
|
|
@@ -81966,7 +82041,7 @@ ${legacyTrimmed}
|
|
|
81966
82041
|
}
|
|
81967
82042
|
upsertAgentsMdHarSection(repoPath);
|
|
81968
82043
|
}
|
|
81969
|
-
|
|
82044
|
+
fs51.unlinkSync(legacyPath);
|
|
81970
82045
|
info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
|
|
81971
82046
|
return true;
|
|
81972
82047
|
}
|
|
@@ -81976,7 +82051,7 @@ function loadClaudeMdTemplate() {
|
|
|
81976
82051
|
if (!templatePath) {
|
|
81977
82052
|
throw new Error("CLAUDE.md.template not found. Run npm run build.");
|
|
81978
82053
|
}
|
|
81979
|
-
return
|
|
82054
|
+
return fs51.readFileSync(templatePath, "utf8");
|
|
81980
82055
|
}
|
|
81981
82056
|
function isHarOwnedClaudeMd(content) {
|
|
81982
82057
|
const trimmed = content.trim();
|
|
@@ -81990,11 +82065,11 @@ function hasAgentsImport(content) {
|
|
|
81990
82065
|
function ensureClaudeMdPointer(repoPath, options = {}) {
|
|
81991
82066
|
const dest = path59.join(repoPath, CLAUDE_MD);
|
|
81992
82067
|
const thin = loadClaudeMdTemplate();
|
|
81993
|
-
if (!
|
|
82068
|
+
if (!fs51.existsSync(dest)) {
|
|
81994
82069
|
writeFileSafe(dest, thin);
|
|
81995
82070
|
return "created";
|
|
81996
82071
|
}
|
|
81997
|
-
const existing =
|
|
82072
|
+
const existing = fs51.readFileSync(dest, "utf8");
|
|
81998
82073
|
if (isHarOwnedClaudeMd(existing) || options.force) {
|
|
81999
82074
|
if (existing.trim() === CLAUDE_MD_IMPORT) return "skipped";
|
|
82000
82075
|
writeFileSafe(dest, thin);
|
|
@@ -82132,15 +82207,15 @@ function readAgentMdProposal(repoPath) {
|
|
|
82132
82207
|
const metaPath = path60.join(harnessDir, AGENTS_MD_PROPOSAL_META);
|
|
82133
82208
|
const legacyProposalPath = path60.join(harnessDir, AGENT_MD_PROPOSAL);
|
|
82134
82209
|
const legacyMetaPath = path60.join(harnessDir, AGENT_MD_PROPOSAL_META);
|
|
82135
|
-
const resolvedProposal =
|
|
82210
|
+
const resolvedProposal = fs52.existsSync(proposalPath) ? proposalPath : fs52.existsSync(legacyProposalPath) ? legacyProposalPath : null;
|
|
82136
82211
|
if (!resolvedProposal) return null;
|
|
82137
82212
|
const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
|
|
82138
|
-
const content =
|
|
82213
|
+
const content = fs52.readFileSync(resolvedProposal, "utf8");
|
|
82139
82214
|
let rationale = "";
|
|
82140
82215
|
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
82141
|
-
if (
|
|
82216
|
+
if (fs52.existsSync(resolvedMeta)) {
|
|
82142
82217
|
try {
|
|
82143
|
-
const meta = JSON.parse(
|
|
82218
|
+
const meta = JSON.parse(fs52.readFileSync(resolvedMeta, "utf8"));
|
|
82144
82219
|
rationale = meta.rationale ?? "";
|
|
82145
82220
|
createdAt = meta.createdAt ?? createdAt;
|
|
82146
82221
|
} catch {
|
|
@@ -82158,7 +82233,7 @@ function clearAgentMdProposal(repoPath) {
|
|
|
82158
82233
|
AGENT_MD_PROPOSAL_META
|
|
82159
82234
|
]) {
|
|
82160
82235
|
const p = path60.join(harnessDir, file);
|
|
82161
|
-
if (
|
|
82236
|
+
if (fs52.existsSync(p)) fs52.unlinkSync(p);
|
|
82162
82237
|
}
|
|
82163
82238
|
}
|
|
82164
82239
|
function wouldProposalShrinkExisting(existing, proposal) {
|
|
@@ -82172,8 +82247,8 @@ function applyAgentMdProposalMerge(repoPath, options = {}) {
|
|
|
82172
82247
|
const proposal = readAgentMdProposal(repoPath);
|
|
82173
82248
|
if (!proposal) return false;
|
|
82174
82249
|
const agentsMdPath = path60.join(repoPath, AGENTS_MD);
|
|
82175
|
-
if (
|
|
82176
|
-
const existing =
|
|
82250
|
+
if (fs52.existsSync(agentsMdPath)) {
|
|
82251
|
+
const existing = fs52.readFileSync(agentsMdPath, "utf8");
|
|
82177
82252
|
if (wouldProposalShrinkExisting(existing, proposal.content)) {
|
|
82178
82253
|
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.`;
|
|
82179
82254
|
if (options.rejectSignificantShrink) {
|
|
@@ -82196,7 +82271,7 @@ function finalizeAgentsMdInstructionFiles(repoPath) {
|
|
|
82196
82271
|
}
|
|
82197
82272
|
|
|
82198
82273
|
// src/harness/validator.ts
|
|
82199
|
-
var
|
|
82274
|
+
var fs54 = __toESM(require("fs"));
|
|
82200
82275
|
var path62 = __toESM(require("path"));
|
|
82201
82276
|
init_shell();
|
|
82202
82277
|
init_env();
|
|
@@ -82204,7 +82279,7 @@ init_manifest();
|
|
|
82204
82279
|
init_stages();
|
|
82205
82280
|
|
|
82206
82281
|
// src/harness/verification.ts
|
|
82207
|
-
var
|
|
82282
|
+
var fs53 = __toESM(require("fs"));
|
|
82208
82283
|
var path61 = __toESM(require("path"));
|
|
82209
82284
|
init_env();
|
|
82210
82285
|
init_provision();
|
|
@@ -82233,7 +82308,7 @@ function nodeSmokeCommand(repoPath) {
|
|
|
82233
82308
|
const pkgPath = path61.join(repoPath, "package.json");
|
|
82234
82309
|
let scripts = {};
|
|
82235
82310
|
try {
|
|
82236
|
-
scripts = JSON.parse(
|
|
82311
|
+
scripts = JSON.parse(fs53.readFileSync(pkgPath, "utf8")).scripts ?? {};
|
|
82237
82312
|
} catch {
|
|
82238
82313
|
scripts = {};
|
|
82239
82314
|
}
|
|
@@ -82264,7 +82339,7 @@ function nodeSmokeCommand(repoPath) {
|
|
|
82264
82339
|
function nodeScriptOrSkip(repoPath, script) {
|
|
82265
82340
|
const pkgPath = path61.join(repoPath, "package.json");
|
|
82266
82341
|
try {
|
|
82267
|
-
const scripts = JSON.parse(
|
|
82342
|
+
const scripts = JSON.parse(fs53.readFileSync(pkgPath, "utf8")).scripts ?? {};
|
|
82268
82343
|
if (scripts[script]) {
|
|
82269
82344
|
return script === "test" ? "${NPM_BIN:-npm} test" : `\${NPM_BIN:-npm} run ${script}`;
|
|
82270
82345
|
}
|
|
@@ -82389,7 +82464,7 @@ function ensureEcosystemVerificationStages(repoPath) {
|
|
|
82389
82464
|
const skipped = /* @__PURE__ */ new Set();
|
|
82390
82465
|
for (const stage of defaults.stages) {
|
|
82391
82466
|
if (stages.some((s) => s.id === stage.id)) continue;
|
|
82392
|
-
if (stage.script && !
|
|
82467
|
+
if (stage.script && !fs53.existsSync(path61.join(harnessDir, stage.script))) {
|
|
82393
82468
|
skipped.add(stage.id);
|
|
82394
82469
|
continue;
|
|
82395
82470
|
}
|
|
@@ -82447,7 +82522,7 @@ var SHELL_SCRIPTS = [
|
|
|
82447
82522
|
function validateHarness(repoPath) {
|
|
82448
82523
|
const harnessDir = getHarnessDir(repoPath);
|
|
82449
82524
|
const issues = [];
|
|
82450
|
-
if (!
|
|
82525
|
+
if (!fs54.existsSync(harnessDir)) {
|
|
82451
82526
|
return {
|
|
82452
82527
|
pass: false,
|
|
82453
82528
|
issues: [{ file: ".har", message: "Harness directory not found", severity: "error" }]
|
|
@@ -82455,14 +82530,14 @@ function validateHarness(repoPath) {
|
|
|
82455
82530
|
}
|
|
82456
82531
|
for (const file of getRequiredFiles(repoPath)) {
|
|
82457
82532
|
const filePath = path62.join(harnessDir, file);
|
|
82458
|
-
if (!
|
|
82533
|
+
if (!fs54.existsSync(filePath)) {
|
|
82459
82534
|
issues.push({ file, message: "Required file missing", severity: "error" });
|
|
82460
82535
|
}
|
|
82461
82536
|
}
|
|
82462
82537
|
for (const script of SHELL_SCRIPTS) {
|
|
82463
82538
|
const scriptPath = path62.join(harnessDir, script);
|
|
82464
|
-
if (!
|
|
82465
|
-
const stat =
|
|
82539
|
+
if (!fs54.existsSync(scriptPath)) continue;
|
|
82540
|
+
const stat = fs54.statSync(scriptPath);
|
|
82466
82541
|
if (!(stat.mode & 73)) {
|
|
82467
82542
|
issues.push({ file: script, message: "Script is not executable", severity: "warning" });
|
|
82468
82543
|
}
|
|
@@ -82478,8 +82553,8 @@ function validateHarness(repoPath) {
|
|
|
82478
82553
|
const manifest = readManifest(repoPath);
|
|
82479
82554
|
const profile = manifest?.profile ?? "default";
|
|
82480
82555
|
const ecosystemPath = path62.join(harnessDir, "ecosystem.agent.template.cjs");
|
|
82481
|
-
if (profile !== "cli" &&
|
|
82482
|
-
const content =
|
|
82556
|
+
if (profile !== "cli" && fs54.existsSync(ecosystemPath)) {
|
|
82557
|
+
const content = fs54.readFileSync(ecosystemPath, "utf8");
|
|
82483
82558
|
if (!content.includes("module.exports")) {
|
|
82484
82559
|
issues.push({
|
|
82485
82560
|
file: "ecosystem.agent.template.cjs",
|
|
@@ -82489,8 +82564,8 @@ function validateHarness(repoPath) {
|
|
|
82489
82564
|
}
|
|
82490
82565
|
}
|
|
82491
82566
|
const harnessEnvPath = path62.join(harnessDir, "harness.env");
|
|
82492
|
-
if (
|
|
82493
|
-
const content =
|
|
82567
|
+
if (fs54.existsSync(harnessEnvPath)) {
|
|
82568
|
+
const content = fs54.readFileSync(harnessEnvPath, "utf8");
|
|
82494
82569
|
if (content.includes("TODO: set migrate command")) {
|
|
82495
82570
|
issues.push({ file: "harness.env", message: "Migrate command still has TODO", severity: "warning" });
|
|
82496
82571
|
}
|
|
@@ -82507,16 +82582,16 @@ function validateHarness(repoPath) {
|
|
|
82507
82582
|
}
|
|
82508
82583
|
}
|
|
82509
82584
|
const verifyPath = path62.join(harnessDir, "verify.sh");
|
|
82510
|
-
if (
|
|
82511
|
-
const content =
|
|
82585
|
+
if (fs54.existsSync(verifyPath)) {
|
|
82586
|
+
const content = fs54.readFileSync(verifyPath, "utf8");
|
|
82512
82587
|
if (content.includes("echo 'TODO:")) {
|
|
82513
82588
|
issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
|
|
82514
82589
|
}
|
|
82515
82590
|
}
|
|
82516
82591
|
const stagesPath = path62.join(harnessDir, "stages.json");
|
|
82517
|
-
if (
|
|
82592
|
+
if (fs54.existsSync(stagesPath)) {
|
|
82518
82593
|
try {
|
|
82519
|
-
JSON.parse(
|
|
82594
|
+
JSON.parse(fs54.readFileSync(stagesPath, "utf8"));
|
|
82520
82595
|
const registry2 = readStageRegistry(repoPath);
|
|
82521
82596
|
if (registry2.stages.length === 0) {
|
|
82522
82597
|
issues.push({ file: "stages.json", message: "No harness stages declared", severity: "warning" });
|
|
@@ -82539,8 +82614,8 @@ function validateHarness(repoPath) {
|
|
|
82539
82614
|
issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
|
|
82540
82615
|
}
|
|
82541
82616
|
const readmePath = path62.join(harnessDir, "README.md");
|
|
82542
|
-
if (
|
|
82543
|
-
const content =
|
|
82617
|
+
if (fs54.existsSync(readmePath)) {
|
|
82618
|
+
const content = fs54.readFileSync(readmePath, "utf8");
|
|
82544
82619
|
if (!content.includes(".har")) {
|
|
82545
82620
|
issues.push({ file: "README.md", message: "README should document .har/ paths", severity: "warning" });
|
|
82546
82621
|
}
|
|
@@ -82555,7 +82630,7 @@ async function smokeTestHarness(repoPath) {
|
|
|
82555
82630
|
const harnessDir = getHarnessDir(repoPath);
|
|
82556
82631
|
const issues = [];
|
|
82557
82632
|
const setupScript = path62.join(harnessDir, "setup-infra.sh");
|
|
82558
|
-
if (
|
|
82633
|
+
if (fs54.existsSync(setupScript)) {
|
|
82559
82634
|
const result = run(`bash "${setupScript}"`, { cwd: repoPath });
|
|
82560
82635
|
if (result.code !== 0) {
|
|
82561
82636
|
issues.push({
|
|
@@ -82570,7 +82645,7 @@ async function smokeTestHarness(repoPath) {
|
|
|
82570
82645
|
}
|
|
82571
82646
|
|
|
82572
82647
|
// src/harness/maintain-bundle.ts
|
|
82573
|
-
var
|
|
82648
|
+
var fs60 = __toESM(require("fs"));
|
|
82574
82649
|
var os21 = __toESM(require("os"));
|
|
82575
82650
|
var path67 = __toESM(require("path"));
|
|
82576
82651
|
init_file_ops();
|
|
@@ -82578,34 +82653,34 @@ init_shell();
|
|
|
82578
82653
|
init_manifest();
|
|
82579
82654
|
|
|
82580
82655
|
// src/harness/plugin-drift.ts
|
|
82581
|
-
var
|
|
82656
|
+
var fs59 = __toESM(require("fs"));
|
|
82582
82657
|
var path66 = __toESM(require("path"));
|
|
82583
82658
|
init_manifest();
|
|
82584
82659
|
|
|
82585
82660
|
// src/harness/plugins.ts
|
|
82586
|
-
var
|
|
82661
|
+
var fs58 = __toESM(require("fs"));
|
|
82587
82662
|
var path65 = __toESM(require("path"));
|
|
82588
82663
|
init_zod();
|
|
82589
82664
|
init_logging();
|
|
82590
82665
|
init_paths();
|
|
82591
82666
|
|
|
82592
82667
|
// src/harness/parser.ts
|
|
82593
|
-
var
|
|
82668
|
+
var fs55 = __toESM(require("fs"));
|
|
82594
82669
|
init_manifest();
|
|
82595
82670
|
function harnessExists(repoPath) {
|
|
82596
|
-
return
|
|
82671
|
+
return fs55.existsSync(`${repoPath}/.har/stages.json`);
|
|
82597
82672
|
}
|
|
82598
82673
|
|
|
82599
82674
|
// src/harness/bundle-resolve.ts
|
|
82600
82675
|
var import_child_process16 = require("child_process");
|
|
82601
|
-
var
|
|
82676
|
+
var fs56 = __toESM(require("fs"));
|
|
82602
82677
|
var os20 = __toESM(require("os"));
|
|
82603
82678
|
var path63 = __toESM(require("path"));
|
|
82604
82679
|
init_paths();
|
|
82605
82680
|
function findManifestPath(dir, config2) {
|
|
82606
82681
|
for (const name of config2.manifestFiles) {
|
|
82607
82682
|
const candidate = path63.join(dir, name);
|
|
82608
|
-
if (
|
|
82683
|
+
if (fs56.existsSync(candidate)) return candidate;
|
|
82609
82684
|
}
|
|
82610
82685
|
return null;
|
|
82611
82686
|
}
|
|
@@ -82614,9 +82689,9 @@ function hasManifest(dir, config2) {
|
|
|
82614
82689
|
}
|
|
82615
82690
|
function readPackageVersion(dir) {
|
|
82616
82691
|
const pkgPath = path63.join(dir, "package.json");
|
|
82617
|
-
if (!
|
|
82692
|
+
if (!fs56.existsSync(pkgPath)) return void 0;
|
|
82618
82693
|
try {
|
|
82619
|
-
const pkg = JSON.parse(
|
|
82694
|
+
const pkg = JSON.parse(fs56.readFileSync(pkgPath, "utf8"));
|
|
82620
82695
|
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
82621
82696
|
} catch {
|
|
82622
82697
|
return void 0;
|
|
@@ -82626,7 +82701,7 @@ function readManifestId(dir, config2) {
|
|
|
82626
82701
|
const manifestPath = findManifestPath(dir, config2);
|
|
82627
82702
|
if (!manifestPath) return void 0;
|
|
82628
82703
|
try {
|
|
82629
|
-
const raw = JSON.parse(
|
|
82704
|
+
const raw = JSON.parse(fs56.readFileSync(manifestPath, "utf8"));
|
|
82630
82705
|
return typeof raw.id === "string" ? raw.id : void 0;
|
|
82631
82706
|
} catch {
|
|
82632
82707
|
return void 0;
|
|
@@ -82649,7 +82724,7 @@ function expandHome(p) {
|
|
|
82649
82724
|
return p;
|
|
82650
82725
|
}
|
|
82651
82726
|
function makeTempDir(prefix) {
|
|
82652
|
-
return
|
|
82727
|
+
return fs56.mkdtempSync(path63.join(os20.tmpdir(), prefix));
|
|
82653
82728
|
}
|
|
82654
82729
|
function manifestNames(config2) {
|
|
82655
82730
|
return config2.manifestFiles.join(" or ");
|
|
@@ -82668,7 +82743,7 @@ function isLocalBundleDir(dir, repoPath, config2) {
|
|
|
82668
82743
|
function resolvePathSpec(spec, repoPath, config2) {
|
|
82669
82744
|
const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
|
|
82670
82745
|
const dir = path63.resolve(expandHome(raw));
|
|
82671
|
-
if (!
|
|
82746
|
+
if (!fs56.existsSync(dir) || !fs56.statSync(dir).isDirectory()) {
|
|
82672
82747
|
throw new Error(`${config2.label} path not found: ${spec}`);
|
|
82673
82748
|
}
|
|
82674
82749
|
if (!hasManifest(dir, config2)) {
|
|
@@ -82692,19 +82767,19 @@ function resolveNpmSpec(spec, config2) {
|
|
|
82692
82767
|
stdio: ["ignore", "pipe", "pipe"],
|
|
82693
82768
|
timeout: 12e4
|
|
82694
82769
|
});
|
|
82695
|
-
const tarballs =
|
|
82770
|
+
const tarballs = fs56.readdirSync(tmp).filter((f2) => f2.endsWith(".tgz"));
|
|
82696
82771
|
if (tarballs.length === 0) {
|
|
82697
82772
|
throw new Error(`npm pack produced no tarball for ${spec}`);
|
|
82698
82773
|
}
|
|
82699
82774
|
const extractDir = path63.join(tmp, "extract");
|
|
82700
|
-
|
|
82775
|
+
fs56.mkdirSync(extractDir);
|
|
82701
82776
|
(0, import_child_process16.execFileSync)("tar", ["-xzf", path63.join(tmp, tarballs[0]), "-C", extractDir], {
|
|
82702
82777
|
encoding: "utf8",
|
|
82703
82778
|
stdio: ["ignore", "pipe", "pipe"]
|
|
82704
82779
|
});
|
|
82705
82780
|
let dir = path63.join(extractDir, "package");
|
|
82706
82781
|
if (!hasManifest(dir, config2)) {
|
|
82707
|
-
const nested =
|
|
82782
|
+
const nested = fs56.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path63.join(extractDir, e.name)).find((d) => hasManifest(d, config2));
|
|
82708
82783
|
if (!nested) {
|
|
82709
82784
|
throw new Error(
|
|
82710
82785
|
`npm package ${spec} has no ${manifestNames(config2)} (not a HAR ${config2.label} bundle)`
|
|
@@ -82722,7 +82797,7 @@ function resolveNpmSpec(spec, config2) {
|
|
|
82722
82797
|
};
|
|
82723
82798
|
} catch (err) {
|
|
82724
82799
|
for (const d of cleanupDirs) {
|
|
82725
|
-
|
|
82800
|
+
fs56.rmSync(d, { recursive: true, force: true });
|
|
82726
82801
|
}
|
|
82727
82802
|
const message = err instanceof Error ? err.message : String(err);
|
|
82728
82803
|
throw new Error(`Failed to install ${config2.label} from npm (${spec}): ${message}`);
|
|
@@ -82751,8 +82826,8 @@ function resolveGitSpec(spec, config2) {
|
|
|
82751
82826
|
let dir = cloneDir;
|
|
82752
82827
|
if (!hasManifest(dir, config2)) {
|
|
82753
82828
|
const nestedRoot = path63.join(cloneDir, config2.gitNestedDir);
|
|
82754
|
-
if (
|
|
82755
|
-
const child =
|
|
82829
|
+
if (fs56.existsSync(nestedRoot)) {
|
|
82830
|
+
const child = fs56.readdirSync(nestedRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path63.join(nestedRoot, e.name)).find((d) => hasManifest(d, config2));
|
|
82756
82831
|
if (child) dir = child;
|
|
82757
82832
|
}
|
|
82758
82833
|
}
|
|
@@ -82771,7 +82846,7 @@ function resolveGitSpec(spec, config2) {
|
|
|
82771
82846
|
};
|
|
82772
82847
|
} catch (err) {
|
|
82773
82848
|
for (const d of cleanupDirs) {
|
|
82774
|
-
|
|
82849
|
+
fs56.rmSync(d, { recursive: true, force: true });
|
|
82775
82850
|
}
|
|
82776
82851
|
const message = err instanceof Error ? err.message : String(err);
|
|
82777
82852
|
throw new Error(`Failed to install ${config2.label} from git (${spec}): ${message}`);
|
|
@@ -82828,17 +82903,17 @@ function resolveBundleSource(spec, repoPath, config2) {
|
|
|
82828
82903
|
}
|
|
82829
82904
|
function listTemplateBundleIds(config2) {
|
|
82830
82905
|
const root = path63.join(resolveTemplatesDir(), config2.templatesSubdir);
|
|
82831
|
-
if (!
|
|
82832
|
-
return
|
|
82906
|
+
if (!fs56.existsSync(root)) return [];
|
|
82907
|
+
return fs56.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path63.join(root, name), config2)).sort();
|
|
82833
82908
|
}
|
|
82834
82909
|
function listLocalBundleIds(repoPath, config2) {
|
|
82835
82910
|
const root = path63.resolve(repoPath, config2.localDir);
|
|
82836
|
-
if (!
|
|
82837
|
-
return
|
|
82911
|
+
if (!fs56.existsSync(root)) return [];
|
|
82912
|
+
return fs56.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path63.join(root, name), config2)).sort();
|
|
82838
82913
|
}
|
|
82839
82914
|
function cleanupResolvedBundle(source) {
|
|
82840
82915
|
for (const dir of source.cleanupDirs) {
|
|
82841
|
-
|
|
82916
|
+
fs56.rmSync(dir, { recursive: true, force: true });
|
|
82842
82917
|
}
|
|
82843
82918
|
}
|
|
82844
82919
|
|
|
@@ -82880,7 +82955,7 @@ function cleanupResolvedPlugin(source) {
|
|
|
82880
82955
|
}
|
|
82881
82956
|
|
|
82882
82957
|
// src/harness/plugin-prompt.ts
|
|
82883
|
-
var
|
|
82958
|
+
var fs57 = __toESM(require("fs"));
|
|
82884
82959
|
var path64 = __toESM(require("path"));
|
|
82885
82960
|
init_paths();
|
|
82886
82961
|
init_file_ops();
|
|
@@ -82897,7 +82972,7 @@ function loadTemplate() {
|
|
|
82897
82972
|
"Plugin adaptation prompt template not found: adaptation-prompt-plugin.md. Run npm run build."
|
|
82898
82973
|
);
|
|
82899
82974
|
}
|
|
82900
|
-
return
|
|
82975
|
+
return fs57.readFileSync(filePath, "utf8");
|
|
82901
82976
|
}
|
|
82902
82977
|
function resolveInstallCommand(repoPath) {
|
|
82903
82978
|
const env3 = readHarnessEnv(repoPath);
|
|
@@ -82978,7 +83053,7 @@ function primaryStageId(manifest) {
|
|
|
82978
83053
|
}
|
|
82979
83054
|
function resolveBundledPluginDir(pluginId) {
|
|
82980
83055
|
const dir = path65.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
82981
|
-
if (!
|
|
83056
|
+
if (!fs58.existsSync(dir)) {
|
|
82982
83057
|
throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
|
|
82983
83058
|
}
|
|
82984
83059
|
return dir;
|
|
@@ -82988,7 +83063,7 @@ function readPluginManifestFromDir(pluginDir, expectedId) {
|
|
|
82988
83063
|
if (!manifestPath) {
|
|
82989
83064
|
throw new Error(`No template.manifest.json in ${pluginDir}`);
|
|
82990
83065
|
}
|
|
82991
|
-
const raw = JSON.parse(
|
|
83066
|
+
const raw = JSON.parse(fs58.readFileSync(manifestPath, "utf8"));
|
|
82992
83067
|
if (raw.kind === LINE_BUNDLE_KIND || path65.basename(manifestPath) === "line.manifest.json") {
|
|
82993
83068
|
throw new Error(
|
|
82994
83069
|
`${path65.basename(manifestPath)} declares "kind": "line" \u2014 this is a factory line bundle, not a verification plugin. Install it with: har line add <spec>`
|
|
@@ -83008,39 +83083,39 @@ function readPluginManifest(pluginId) {
|
|
|
83008
83083
|
}
|
|
83009
83084
|
function ensureParentDir(filePath) {
|
|
83010
83085
|
const parent = path65.dirname(filePath);
|
|
83011
|
-
if (!
|
|
83012
|
-
|
|
83086
|
+
if (!fs58.existsSync(parent)) {
|
|
83087
|
+
fs58.mkdirSync(parent, { recursive: true });
|
|
83013
83088
|
}
|
|
83014
83089
|
}
|
|
83015
83090
|
function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
83016
83091
|
const srcPath = path65.join(pluginDir, file.src);
|
|
83017
83092
|
const destPath = path65.join(repoPath, file.dest);
|
|
83018
|
-
if (!
|
|
83093
|
+
if (!fs58.existsSync(srcPath)) {
|
|
83019
83094
|
throw new Error(`Plugin file missing: ${file.src}`);
|
|
83020
83095
|
}
|
|
83021
|
-
if (
|
|
83096
|
+
if (fs58.existsSync(destPath) && !force) {
|
|
83022
83097
|
throw new Error(
|
|
83023
83098
|
`File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
|
|
83024
83099
|
);
|
|
83025
83100
|
}
|
|
83026
83101
|
ensureParentDir(destPath);
|
|
83027
|
-
|
|
83102
|
+
fs58.copyFileSync(srcPath, destPath);
|
|
83028
83103
|
if (file.executable) {
|
|
83029
|
-
|
|
83104
|
+
fs58.chmodSync(destPath, 493);
|
|
83030
83105
|
}
|
|
83031
83106
|
return { written: true, path: file.dest };
|
|
83032
83107
|
}
|
|
83033
83108
|
function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
83034
83109
|
const packagePath = path65.join(repoPath, "package.json");
|
|
83035
|
-
if (!
|
|
83110
|
+
if (!fs58.existsSync(packagePath)) {
|
|
83036
83111
|
throw new Error("No package.json in repo root. Add one before applying this plugin.");
|
|
83037
83112
|
}
|
|
83038
83113
|
const fragmentPath = path65.join(pluginDir, fragmentRelPath);
|
|
83039
|
-
if (!
|
|
83114
|
+
if (!fs58.existsSync(fragmentPath)) {
|
|
83040
83115
|
throw new Error(`Package fragment missing: ${fragmentRelPath}`);
|
|
83041
83116
|
}
|
|
83042
|
-
const pkg = JSON.parse(
|
|
83043
|
-
const fragment = JSON.parse(
|
|
83117
|
+
const pkg = JSON.parse(fs58.readFileSync(packagePath, "utf8"));
|
|
83118
|
+
const fragment = JSON.parse(fs58.readFileSync(fragmentPath, "utf8"));
|
|
83044
83119
|
for (const section of ["scripts", "devDependencies"]) {
|
|
83045
83120
|
const existing = pkg[section] ?? {};
|
|
83046
83121
|
const incoming = fragment[section] ?? {};
|
|
@@ -83053,7 +83128,7 @@ function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
|
83053
83128
|
}
|
|
83054
83129
|
pkg[section] = existing;
|
|
83055
83130
|
}
|
|
83056
|
-
|
|
83131
|
+
fs58.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
|
|
83057
83132
|
}
|
|
83058
83133
|
function patchStageRegistry(repoPath, stages, verificationStageIds, force) {
|
|
83059
83134
|
const registry2 = readStageRegistry(repoPath);
|
|
@@ -83090,7 +83165,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
|
|
|
83090
83165
|
const registry2 = readStageRegistry(repoPath);
|
|
83091
83166
|
for (const stageId of stageIds) {
|
|
83092
83167
|
const scriptPath = path65.join(repoPath, ".har", "stages", `${stageId}.sh`);
|
|
83093
|
-
if (
|
|
83168
|
+
if (fs58.existsSync(scriptPath)) {
|
|
83094
83169
|
throw new Error(
|
|
83095
83170
|
`Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
|
|
83096
83171
|
);
|
|
@@ -83123,7 +83198,7 @@ function applyPluginFromDir(repoPath, pluginDir, options, meta) {
|
|
|
83123
83198
|
if (file.skipFlag === "skipCi" && options.skipCi) {
|
|
83124
83199
|
continue;
|
|
83125
83200
|
}
|
|
83126
|
-
if (
|
|
83201
|
+
if (fs58.existsSync(path65.join(resolved, file.dest)) && !force) {
|
|
83127
83202
|
warnings.push(`Skipped optional file (exists): ${file.dest}`);
|
|
83128
83203
|
continue;
|
|
83129
83204
|
}
|
|
@@ -83205,7 +83280,7 @@ function detectInstalledPlugins(repoPath) {
|
|
|
83205
83280
|
return ledger.plugins.map((p) => p.id).sort();
|
|
83206
83281
|
}
|
|
83207
83282
|
const registryPath = path66.join(resolved, ".har", "stages.json");
|
|
83208
|
-
if (!
|
|
83283
|
+
if (!fs59.existsSync(registryPath)) return [];
|
|
83209
83284
|
const registry2 = readStageRegistry(resolved);
|
|
83210
83285
|
const stageIds = new Set(registry2.stages.map((stage) => stage.id));
|
|
83211
83286
|
const installed = [];
|
|
@@ -83227,13 +83302,13 @@ function resolvePluginBaseline(repoPath, pluginId) {
|
|
|
83227
83302
|
const entry = ledger?.plugins.find((p) => p.id === pluginId);
|
|
83228
83303
|
if (entry?.source === "local") {
|
|
83229
83304
|
const localDir = path66.join(resolved, LOCAL_PLUGINS_DIR, pluginId);
|
|
83230
|
-
if (
|
|
83305
|
+
if (fs59.existsSync(path66.join(localDir, "template.manifest.json"))) {
|
|
83231
83306
|
return { kind: "local", dir: localDir, manifest: readPluginManifestFromDir(localDir) };
|
|
83232
83307
|
}
|
|
83233
83308
|
return null;
|
|
83234
83309
|
}
|
|
83235
83310
|
const bundled = path66.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
83236
|
-
if (
|
|
83311
|
+
if (fs59.existsSync(path66.join(bundled, "template.manifest.json"))) {
|
|
83237
83312
|
return { kind: "bundled", dir: bundled, manifest: readPluginManifestFromDir(bundled) };
|
|
83238
83313
|
}
|
|
83239
83314
|
return null;
|
|
@@ -83246,14 +83321,14 @@ function requireBaseline(repoPath, pluginId) {
|
|
|
83246
83321
|
return baseline;
|
|
83247
83322
|
}
|
|
83248
83323
|
function readBaselineFile(baseline, srcRel) {
|
|
83249
|
-
return
|
|
83324
|
+
return fs59.readFileSync(path66.join(baseline.dir, srcRel), "utf8");
|
|
83250
83325
|
}
|
|
83251
83326
|
function listPluginDestPaths(baseline, repoPath) {
|
|
83252
83327
|
const manifest = baseline.manifest;
|
|
83253
83328
|
const paths = manifest.files.map((file) => file.dest);
|
|
83254
83329
|
if (manifest.optionalFiles) {
|
|
83255
83330
|
for (const file of manifest.optionalFiles) {
|
|
83256
|
-
if (
|
|
83331
|
+
if (fs59.existsSync(path66.join(repoPath, file.dest))) {
|
|
83257
83332
|
paths.push(file.dest);
|
|
83258
83333
|
}
|
|
83259
83334
|
}
|
|
@@ -83313,8 +83388,8 @@ function readTemplatePluginFile(repoPath, pluginId, dest) {
|
|
|
83313
83388
|
}
|
|
83314
83389
|
function readInstalledPluginFile(repoPath, pluginId, dest) {
|
|
83315
83390
|
const installedPath = path66.join(path66.resolve(repoPath), dest);
|
|
83316
|
-
if (!
|
|
83317
|
-
const content =
|
|
83391
|
+
if (!fs59.existsSync(installedPath)) return null;
|
|
83392
|
+
const content = fs59.readFileSync(installedPath, "utf8");
|
|
83318
83393
|
const baseline = requireBaseline(repoPath, pluginId);
|
|
83319
83394
|
const fragmentRel = baseline.manifest.merge?.[dest];
|
|
83320
83395
|
if (fragmentRel) {
|
|
@@ -83356,7 +83431,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
83356
83431
|
if (dest === "package.json") {
|
|
83357
83432
|
const fragmentRel = manifest.merge?.[dest];
|
|
83358
83433
|
const installedPath = path66.join(resolved, dest);
|
|
83359
|
-
const installedRaw =
|
|
83434
|
+
const installedRaw = fs59.readFileSync(installedPath, "utf8");
|
|
83360
83435
|
if (fragmentRel && pluginKeysMatch(installedRaw, readBaselineFile(baseline, fragmentRel))) {
|
|
83361
83436
|
unchanged.push(dest);
|
|
83362
83437
|
} else if (computeFileChecksum(installedContent) === computeFileChecksum(templateContent)) {
|
|
@@ -83456,12 +83531,12 @@ function actionHint(file, kind) {
|
|
|
83456
83531
|
return `Upstream template updated since your last finalize \u2014 read maintain/diffs/${file}.diff and apply into .har/${file}.`;
|
|
83457
83532
|
}
|
|
83458
83533
|
function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
|
|
83459
|
-
const tmpDir =
|
|
83534
|
+
const tmpDir = fs60.mkdtempSync(path67.join(os21.tmpdir(), "har-maintain-diff-"));
|
|
83460
83535
|
try {
|
|
83461
83536
|
const installedPath = path67.join(tmpDir, "installed");
|
|
83462
83537
|
const templatePath = path67.join(tmpDir, "template");
|
|
83463
|
-
|
|
83464
|
-
|
|
83538
|
+
fs60.writeFileSync(installedPath, installedContent);
|
|
83539
|
+
fs60.writeFileSync(templatePath, templateContent);
|
|
83465
83540
|
const result = run(`diff -u "${installedPath}" "${templatePath}"`);
|
|
83466
83541
|
const body = result.stdout.trim();
|
|
83467
83542
|
if (!body) return "";
|
|
@@ -83470,7 +83545,7 @@ function createUnifiedDiff(installedContent, templateContent, installedLabel, te
|
|
|
83470
83545
|
${body.split("\n").slice(2).join("\n")}
|
|
83471
83546
|
`;
|
|
83472
83547
|
} finally {
|
|
83473
|
-
|
|
83548
|
+
fs60.rmSync(tmpDir, { recursive: true, force: true });
|
|
83474
83549
|
}
|
|
83475
83550
|
}
|
|
83476
83551
|
function buildActions(repoPath, profile, drift) {
|
|
@@ -83494,7 +83569,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
83494
83569
|
file,
|
|
83495
83570
|
kind,
|
|
83496
83571
|
template: `maintain/templates/${file}`,
|
|
83497
|
-
installed:
|
|
83572
|
+
installed: fs60.existsSync(installedPath) ? `maintain/installed/${file}` : void 0,
|
|
83498
83573
|
diff: `maintain/diffs/${file}.diff`,
|
|
83499
83574
|
hint: actionHint(file, kind)
|
|
83500
83575
|
});
|
|
@@ -83666,8 +83741,8 @@ function buildReadme(report) {
|
|
|
83666
83741
|
function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
83667
83742
|
const harnessDir = getHarnessDir(repoPath);
|
|
83668
83743
|
const bundleDir = path67.join(harnessDir, MAINTAIN_DIR);
|
|
83669
|
-
if (
|
|
83670
|
-
|
|
83744
|
+
if (fs60.existsSync(bundleDir)) {
|
|
83745
|
+
fs60.rmSync(bundleDir, { recursive: true, force: true });
|
|
83671
83746
|
}
|
|
83672
83747
|
const dirs = [
|
|
83673
83748
|
bundleDir,
|
|
@@ -83677,15 +83752,15 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
83677
83752
|
path67.join(bundleDir, "stale")
|
|
83678
83753
|
];
|
|
83679
83754
|
for (const dir of dirs) {
|
|
83680
|
-
|
|
83755
|
+
fs60.mkdirSync(dir, { recursive: true });
|
|
83681
83756
|
}
|
|
83682
83757
|
const affectedFiles = [...drift.missing, ...drift.upstreamUpdated, ...drift.conflict];
|
|
83683
83758
|
for (const file of affectedFiles) {
|
|
83684
83759
|
const templateContent = readBundledTemplateContent(repoPath, profile, file);
|
|
83685
83760
|
writeFileSafe(path67.join(bundleDir, "templates", file), templateContent);
|
|
83686
83761
|
const harnessPath = path67.join(harnessDir, file);
|
|
83687
|
-
if (
|
|
83688
|
-
const installedContent =
|
|
83762
|
+
if (fs60.existsSync(harnessPath)) {
|
|
83763
|
+
const installedContent = fs60.readFileSync(harnessPath, "utf8");
|
|
83689
83764
|
writeFileSafe(path67.join(bundleDir, "installed", file), installedContent);
|
|
83690
83765
|
const diff = createUnifiedDiff(
|
|
83691
83766
|
installedContent,
|
|
@@ -83719,8 +83794,8 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
83719
83794
|
}
|
|
83720
83795
|
function ensureParentDir2(filePath) {
|
|
83721
83796
|
const parent = path67.dirname(filePath);
|
|
83722
|
-
if (!
|
|
83723
|
-
|
|
83797
|
+
if (!fs60.existsSync(parent)) {
|
|
83798
|
+
fs60.mkdirSync(parent, { recursive: true });
|
|
83724
83799
|
}
|
|
83725
83800
|
}
|
|
83726
83801
|
function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
@@ -83731,7 +83806,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
|
83731
83806
|
const installedDir = path67.join(pluginRoot, "installed");
|
|
83732
83807
|
const diffsDir = path67.join(pluginRoot, "diffs");
|
|
83733
83808
|
for (const dir of [templatesDir, installedDir, diffsDir]) {
|
|
83734
|
-
|
|
83809
|
+
fs60.mkdirSync(dir, { recursive: true });
|
|
83735
83810
|
}
|
|
83736
83811
|
const templateContent = readTemplatePluginFile(repoPath, action.pluginId, action.file);
|
|
83737
83812
|
if (templateContent === null) continue;
|
|
@@ -83787,8 +83862,8 @@ function buildMaintainBundle(repoPath, validation2, drift) {
|
|
|
83787
83862
|
}
|
|
83788
83863
|
function removeMaintainBundle(repoPath) {
|
|
83789
83864
|
const bundleDir = path67.join(getHarnessDir(repoPath), MAINTAIN_DIR);
|
|
83790
|
-
if (
|
|
83791
|
-
|
|
83865
|
+
if (fs60.existsSync(bundleDir)) {
|
|
83866
|
+
fs60.rmSync(bundleDir, { recursive: true, force: true });
|
|
83792
83867
|
}
|
|
83793
83868
|
}
|
|
83794
83869
|
function formatMaintainBundlePromptSection(report) {
|
|
@@ -83897,7 +83972,7 @@ init_manifest();
|
|
|
83897
83972
|
init_stages();
|
|
83898
83973
|
|
|
83899
83974
|
// src/harness/doctor.ts
|
|
83900
|
-
var
|
|
83975
|
+
var fs65 = __toESM(require("fs"));
|
|
83901
83976
|
var path73 = __toESM(require("path"));
|
|
83902
83977
|
init_package_version();
|
|
83903
83978
|
init_slot_registry();
|
|
@@ -83914,7 +83989,7 @@ function compareSemver(a, b2) {
|
|
|
83914
83989
|
}
|
|
83915
83990
|
|
|
83916
83991
|
// src/harness/eject.ts
|
|
83917
|
-
var
|
|
83992
|
+
var fs61 = __toESM(require("fs"));
|
|
83918
83993
|
var path68 = __toESM(require("path"));
|
|
83919
83994
|
init_package_version();
|
|
83920
83995
|
init_manifest();
|
|
@@ -83922,7 +83997,7 @@ var EJECTED_RUNTIME_DIR = "runtime";
|
|
|
83922
83997
|
var EJECTED_RUNTIME_BUNDLE = "har.cjs";
|
|
83923
83998
|
function resolveRuntimeBundleSource() {
|
|
83924
83999
|
if (process.env.HAR_EJECT_RUNTIME_SOURCE) {
|
|
83925
|
-
return
|
|
84000
|
+
return fs61.existsSync(process.env.HAR_EJECT_RUNTIME_SOURCE) ? process.env.HAR_EJECT_RUNTIME_SOURCE : null;
|
|
83926
84001
|
}
|
|
83927
84002
|
const candidates = [
|
|
83928
84003
|
// Bundled CLI: __dirname is dist/ and index.js is the self-contained runtime.
|
|
@@ -83931,7 +84006,7 @@ function resolveRuntimeBundleSource() {
|
|
|
83931
84006
|
path68.resolve(__dirname, "..", "..", "dist", "index.js")
|
|
83932
84007
|
];
|
|
83933
84008
|
for (const candidate of candidates) {
|
|
83934
|
-
if (
|
|
84009
|
+
if (fs61.existsSync(candidate)) return candidate;
|
|
83935
84010
|
}
|
|
83936
84011
|
return null;
|
|
83937
84012
|
}
|
|
@@ -83973,11 +84048,11 @@ function ejectHarness(repoPath) {
|
|
|
83973
84048
|
}
|
|
83974
84049
|
const version2 = getHarPackageVersion();
|
|
83975
84050
|
const runtimeDir = path68.join(harnessDir, EJECTED_RUNTIME_DIR);
|
|
83976
|
-
|
|
84051
|
+
fs61.mkdirSync(runtimeDir, { recursive: true });
|
|
83977
84052
|
const runtimeFile = path68.join(runtimeDir, EJECTED_RUNTIME_BUNDLE);
|
|
83978
|
-
|
|
83979
|
-
|
|
83980
|
-
|
|
84053
|
+
fs61.copyFileSync(bundleSource, runtimeFile);
|
|
84054
|
+
fs61.chmodSync(runtimeFile, 493);
|
|
84055
|
+
fs61.writeFileSync(path68.join(runtimeDir, "README.md"), RUNTIME_README(version2));
|
|
83981
84056
|
retireLifecycleShims(resolved);
|
|
83982
84057
|
writeManifest(resolved, {
|
|
83983
84058
|
...manifest,
|
|
@@ -83998,7 +84073,7 @@ function adoptHarness(repoPath) {
|
|
|
83998
84073
|
if (!manifest.ejected) {
|
|
83999
84074
|
throw new Error("Harness is not ejected \u2014 the packaged runtime is already in use.");
|
|
84000
84075
|
}
|
|
84001
|
-
|
|
84076
|
+
fs61.rmSync(path68.join(harnessDir, EJECTED_RUNTIME_DIR), { recursive: true, force: true });
|
|
84002
84077
|
const retired = retireLifecycleShims(resolved);
|
|
84003
84078
|
const rest = { ...manifest };
|
|
84004
84079
|
delete rest.ejected;
|
|
@@ -84016,7 +84091,7 @@ init_env();
|
|
|
84016
84091
|
init_manifest();
|
|
84017
84092
|
|
|
84018
84093
|
// src/harness/line-ledger.ts
|
|
84019
|
-
var
|
|
84094
|
+
var fs62 = __toESM(require("fs"));
|
|
84020
84095
|
var path69 = __toESM(require("path"));
|
|
84021
84096
|
init_file_ops();
|
|
84022
84097
|
init_manifest();
|
|
@@ -84026,9 +84101,9 @@ function getLineLedgerPath(repoPath) {
|
|
|
84026
84101
|
}
|
|
84027
84102
|
function readLineLedger(repoPath) {
|
|
84028
84103
|
const ledgerPath = getLineLedgerPath(repoPath);
|
|
84029
|
-
if (!
|
|
84104
|
+
if (!fs62.existsSync(ledgerPath)) return null;
|
|
84030
84105
|
try {
|
|
84031
|
-
const parsed = LineLedgerSchema.safeParse(JSON.parse(
|
|
84106
|
+
const parsed = LineLedgerSchema.safeParse(JSON.parse(fs62.readFileSync(ledgerPath, "utf8")));
|
|
84032
84107
|
return parsed.success ? parsed.data : null;
|
|
84033
84108
|
} catch {
|
|
84034
84109
|
return null;
|
|
@@ -84037,8 +84112,8 @@ function readLineLedger(repoPath) {
|
|
|
84037
84112
|
function writeLineLedger(repoPath, ledger) {
|
|
84038
84113
|
const ledgerPath = getLineLedgerPath(repoPath);
|
|
84039
84114
|
const harnessDir = path69.dirname(ledgerPath);
|
|
84040
|
-
if (!
|
|
84041
|
-
|
|
84115
|
+
if (!fs62.existsSync(harnessDir)) {
|
|
84116
|
+
fs62.mkdirSync(harnessDir, { recursive: true });
|
|
84042
84117
|
}
|
|
84043
84118
|
writeFileSafe(ledgerPath, `${JSON.stringify(ledger, null, 2)}
|
|
84044
84119
|
`);
|
|
@@ -84054,7 +84129,7 @@ function upsertLineLedgerEntry(repoPath, entry) {
|
|
|
84054
84129
|
}
|
|
84055
84130
|
|
|
84056
84131
|
// src/harness/lines.ts
|
|
84057
|
-
var
|
|
84132
|
+
var fs63 = __toESM(require("fs"));
|
|
84058
84133
|
var path71 = __toESM(require("path"));
|
|
84059
84134
|
init_logging();
|
|
84060
84135
|
|
|
@@ -84198,7 +84273,7 @@ function readLineManifestFromDir(bundleDir, expectedId) {
|
|
|
84198
84273
|
if (!manifestPath) {
|
|
84199
84274
|
throw new Error(`No ${LINE_MANIFEST_FILES.join(" or ")} in ${bundleDir}`);
|
|
84200
84275
|
}
|
|
84201
|
-
const raw = JSON.parse(
|
|
84276
|
+
const raw = JSON.parse(fs63.readFileSync(manifestPath, "utf8"));
|
|
84202
84277
|
if (raw.kind !== LINE_BUNDLE_KIND) {
|
|
84203
84278
|
throw new Error(
|
|
84204
84279
|
`${path71.basename(manifestPath)} is not a factory line bundle (missing "kind": "line"). Verification plugins install with: har env add-plugin <spec>`
|
|
@@ -84215,10 +84290,10 @@ function readLineManifestFromDir(bundleDir, expectedId) {
|
|
|
84215
84290
|
}
|
|
84216
84291
|
function readLineProgramFromDir(bundleDir, manifest) {
|
|
84217
84292
|
const programPath = path71.join(bundleDir, manifest.program);
|
|
84218
|
-
if (!
|
|
84293
|
+
if (!fs63.existsSync(programPath)) {
|
|
84219
84294
|
throw new Error(`Line program missing: ${manifest.program} (referenced by line.manifest.json)`);
|
|
84220
84295
|
}
|
|
84221
|
-
const parsed = LineProgramSchema.safeParse(JSON.parse(
|
|
84296
|
+
const parsed = LineProgramSchema.safeParse(JSON.parse(fs63.readFileSync(programPath, "utf8")));
|
|
84222
84297
|
if (!parsed.success) {
|
|
84223
84298
|
throw new Error(`Invalid line program (${manifest.program}): ${parsed.error.message}`);
|
|
84224
84299
|
}
|
|
@@ -84231,31 +84306,31 @@ function readLineProgramFromDir(bundleDir, manifest) {
|
|
|
84231
84306
|
}
|
|
84232
84307
|
function readInstalledLineProgram(repoPath, lineId) {
|
|
84233
84308
|
const programPath = path71.join(path71.resolve(repoPath), lineProgramPathRel(lineId));
|
|
84234
|
-
if (!
|
|
84235
|
-
const parsed = LineProgramSchema.safeParse(JSON.parse(
|
|
84309
|
+
if (!fs63.existsSync(programPath)) return null;
|
|
84310
|
+
const parsed = LineProgramSchema.safeParse(JSON.parse(fs63.readFileSync(programPath, "utf8")));
|
|
84236
84311
|
return parsed.success ? parsed.data : null;
|
|
84237
84312
|
}
|
|
84238
84313
|
function ensureParentDir3(filePath) {
|
|
84239
|
-
|
|
84314
|
+
fs63.mkdirSync(path71.dirname(filePath), { recursive: true });
|
|
84240
84315
|
}
|
|
84241
84316
|
function copyBundleFile(bundleDir, file, repoPath, force) {
|
|
84242
84317
|
const srcPath = path71.join(bundleDir, file.src);
|
|
84243
84318
|
const destPath = path71.join(repoPath, file.dest);
|
|
84244
|
-
if (!
|
|
84319
|
+
if (!fs63.existsSync(srcPath)) {
|
|
84245
84320
|
throw new Error(`Line file missing: ${file.src}`);
|
|
84246
84321
|
}
|
|
84247
84322
|
if (path71.resolve(srcPath) === path71.resolve(destPath)) {
|
|
84248
84323
|
return file.dest;
|
|
84249
84324
|
}
|
|
84250
|
-
if (
|
|
84325
|
+
if (fs63.existsSync(destPath) && !force) {
|
|
84251
84326
|
throw new Error(
|
|
84252
84327
|
`File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
|
|
84253
84328
|
);
|
|
84254
84329
|
}
|
|
84255
84330
|
ensureParentDir3(destPath);
|
|
84256
|
-
|
|
84331
|
+
fs63.copyFileSync(srcPath, destPath);
|
|
84257
84332
|
if (file.executable) {
|
|
84258
|
-
|
|
84333
|
+
fs63.chmodSync(destPath, 493);
|
|
84259
84334
|
}
|
|
84260
84335
|
return file.dest;
|
|
84261
84336
|
}
|
|
@@ -84314,20 +84389,20 @@ function applyLineFromDir(repoPath, bundleDir, options, meta) {
|
|
|
84314
84389
|
const programDest = path71.join(resolved, lineProgramPathRel(manifest.id));
|
|
84315
84390
|
const programSrc = path71.join(bundleDir, manifest.program);
|
|
84316
84391
|
if (path71.resolve(programSrc) !== path71.resolve(programDest)) {
|
|
84317
|
-
if (
|
|
84392
|
+
if (fs63.existsSync(programDest) && !force) {
|
|
84318
84393
|
throw new Error(
|
|
84319
84394
|
`Line already installed: ${lineProgramPathRel(manifest.id)}. Use --force to replace.`
|
|
84320
84395
|
);
|
|
84321
84396
|
}
|
|
84322
84397
|
ensureParentDir3(programDest);
|
|
84323
|
-
|
|
84398
|
+
fs63.copyFileSync(programSrc, programDest);
|
|
84324
84399
|
}
|
|
84325
84400
|
filesWritten.push(lineProgramPathRel(manifest.id));
|
|
84326
84401
|
const manifestDest = path71.join(resolved, lineDirRel(manifest.id), "line.manifest.json");
|
|
84327
84402
|
const manifestSrc = findManifestPath(bundleDir, LINE_BUNDLE_CONFIG);
|
|
84328
84403
|
if (path71.resolve(manifestSrc) !== path71.resolve(manifestDest)) {
|
|
84329
84404
|
ensureParentDir3(manifestDest);
|
|
84330
|
-
|
|
84405
|
+
fs63.copyFileSync(manifestSrc, manifestDest);
|
|
84331
84406
|
filesWritten.push(`${lineDirRel(manifest.id)}/line.manifest.json`);
|
|
84332
84407
|
}
|
|
84333
84408
|
registerStagesOnly(resolved, stages, force);
|
|
@@ -84408,7 +84483,7 @@ init_stages();
|
|
|
84408
84483
|
init_hooks2();
|
|
84409
84484
|
|
|
84410
84485
|
// src/harness/migrations.ts
|
|
84411
|
-
var
|
|
84486
|
+
var fs64 = __toESM(require("fs"));
|
|
84412
84487
|
var path72 = __toESM(require("path"));
|
|
84413
84488
|
init_schema2();
|
|
84414
84489
|
init_manifest();
|
|
@@ -84459,24 +84534,24 @@ function harnessEnvIsPre10(content) {
|
|
|
84459
84534
|
}
|
|
84460
84535
|
function scriptIsVendored(harnessDir, script) {
|
|
84461
84536
|
const file = path72.join(harnessDir, script);
|
|
84462
|
-
if (!
|
|
84463
|
-
const content =
|
|
84537
|
+
if (!fs64.existsSync(file)) return false;
|
|
84538
|
+
const content = fs64.readFileSync(file, "utf8");
|
|
84464
84539
|
return !content.includes("exec har env") && !content.includes("runtime/har.cjs");
|
|
84465
84540
|
}
|
|
84466
84541
|
function isPre10Harness(repoPath) {
|
|
84467
84542
|
const resolved = path72.resolve(repoPath);
|
|
84468
84543
|
const harnessDir = getHarnessDir(resolved);
|
|
84469
|
-
if (!
|
|
84544
|
+
if (!fs64.existsSync(harnessDir)) return false;
|
|
84470
84545
|
const manifest = readManifest(resolved);
|
|
84471
84546
|
if (manifest?.ejected) return false;
|
|
84472
84547
|
for (const file of LEGACY_MACHINERY_FILES) {
|
|
84473
|
-
if (
|
|
84548
|
+
if (fs64.existsSync(path72.join(harnessDir, file))) return true;
|
|
84474
84549
|
}
|
|
84475
84550
|
for (const script of MANAGED_SHIM_FILES) {
|
|
84476
84551
|
if (scriptIsVendored(harnessDir, script)) return true;
|
|
84477
84552
|
}
|
|
84478
84553
|
const envPath = path72.join(harnessDir, "harness.env");
|
|
84479
|
-
if (
|
|
84554
|
+
if (fs64.existsSync(envPath) && harnessEnvIsPre10(fs64.readFileSync(envPath, "utf8"))) {
|
|
84480
84555
|
return true;
|
|
84481
84556
|
}
|
|
84482
84557
|
return false;
|
|
@@ -84621,7 +84696,7 @@ function buildPre10Plan(repoPath) {
|
|
|
84621
84696
|
const deleteLifecycleScripts = [];
|
|
84622
84697
|
const residue = [];
|
|
84623
84698
|
for (const script of MANAGED_SHIM_FILES) {
|
|
84624
|
-
if (!
|
|
84699
|
+
if (!fs64.existsSync(path72.join(harnessDir, script))) continue;
|
|
84625
84700
|
deleteLifecycleScripts.push(script);
|
|
84626
84701
|
if (scriptIsVendored(harnessDir, script)) {
|
|
84627
84702
|
const target = SCRIPT_RESIDUE_TARGET[script] ?? "review";
|
|
@@ -84636,16 +84711,16 @@ function buildPre10Plan(repoPath) {
|
|
|
84636
84711
|
const survivingScripts = [];
|
|
84637
84712
|
for (const dir of ["stages", "hooks"]) {
|
|
84638
84713
|
const full = path72.join(harnessDir, dir);
|
|
84639
|
-
if (!
|
|
84640
|
-
for (const entry of
|
|
84714
|
+
if (!fs64.existsSync(full)) continue;
|
|
84715
|
+
for (const entry of fs64.readdirSync(full)) {
|
|
84641
84716
|
if (entry.endsWith(".sh") || entry.endsWith(".mjs")) survivingScripts.push(path72.join(dir, entry));
|
|
84642
84717
|
}
|
|
84643
84718
|
}
|
|
84644
|
-
for (const entry of
|
|
84719
|
+
for (const entry of fs64.readdirSync(harnessDir)) {
|
|
84645
84720
|
if (!entry.endsWith(".sh")) continue;
|
|
84646
84721
|
if (MANAGED_SHIM_FILES.includes(entry)) continue;
|
|
84647
84722
|
if (LEGACY_MACHINERY_FILES.includes(entry)) continue;
|
|
84648
|
-
if (!
|
|
84723
|
+
if (!fs64.statSync(path72.join(harnessDir, entry)).isFile()) continue;
|
|
84649
84724
|
survivingScripts.push(entry);
|
|
84650
84725
|
}
|
|
84651
84726
|
const referencedBy = (machineryFile) => {
|
|
@@ -84654,12 +84729,12 @@ function buildPre10Plan(repoPath) {
|
|
|
84654
84729
|
`(?:\\bsource\\b|\\bbash\\b|\\bexec\\b|(?:^|[;&|(])\\s*\\.\\s)[^\\n#]*${base}`
|
|
84655
84730
|
);
|
|
84656
84731
|
return survivingScripts.filter(
|
|
84657
|
-
(script) =>
|
|
84732
|
+
(script) => fs64.readFileSync(path72.join(harnessDir, script), "utf8").split("\n").some((line) => !/^\s*#/.test(line) && loadRe.test(line))
|
|
84658
84733
|
);
|
|
84659
84734
|
};
|
|
84660
84735
|
const retireDocs = [];
|
|
84661
84736
|
for (const doc of RETIRED_DOC_FILES) {
|
|
84662
|
-
if (!
|
|
84737
|
+
if (!fs64.existsSync(path72.join(harnessDir, doc))) continue;
|
|
84663
84738
|
retireDocs.push(doc);
|
|
84664
84739
|
residue.push({
|
|
84665
84740
|
source: doc,
|
|
@@ -84673,7 +84748,7 @@ function buildPre10Plan(repoPath) {
|
|
|
84673
84748
|
const retainMachinery = [];
|
|
84674
84749
|
for (const file of LEGACY_MACHINERY_FILES) {
|
|
84675
84750
|
const full = path72.join(harnessDir, file);
|
|
84676
|
-
if (!
|
|
84751
|
+
if (!fs64.existsSync(full)) continue;
|
|
84677
84752
|
const refs = referencedBy(file);
|
|
84678
84753
|
if (refs.length > 0) {
|
|
84679
84754
|
retainMachinery.push(file);
|
|
@@ -84687,7 +84762,7 @@ function buildPre10Plan(repoPath) {
|
|
|
84687
84762
|
}
|
|
84688
84763
|
deleteMachinery.push(file);
|
|
84689
84764
|
const recorded = fileBaseline[file];
|
|
84690
|
-
const installed = computeFileChecksum(
|
|
84765
|
+
const installed = computeFileChecksum(fs64.readFileSync(full, "utf8"));
|
|
84691
84766
|
if (recorded !== void 0 && installed !== recorded) {
|
|
84692
84767
|
editedMachinery.push(file);
|
|
84693
84768
|
residue.push({
|
|
@@ -84700,8 +84775,8 @@ function buildPre10Plan(repoPath) {
|
|
|
84700
84775
|
}
|
|
84701
84776
|
let env3 = null;
|
|
84702
84777
|
const envPath = path72.join(harnessDir, "harness.env");
|
|
84703
|
-
if (
|
|
84704
|
-
const content =
|
|
84778
|
+
if (fs64.existsSync(envPath)) {
|
|
84779
|
+
const content = fs64.readFileSync(envPath, "utf8");
|
|
84705
84780
|
if (harnessEnvIsPre10(content) || migrateHarnessEnvContent(content).commentedKeys.length > 0) {
|
|
84706
84781
|
env3 = migrateHarnessEnvContent(content);
|
|
84707
84782
|
for (const fn of env3.customFunctions) {
|
|
@@ -84726,7 +84801,7 @@ function buildPre10Plan(repoPath) {
|
|
|
84726
84801
|
for (const file of composed.keys()) {
|
|
84727
84802
|
if (MANAGED_SHIM_FILES.includes(file)) continue;
|
|
84728
84803
|
if (file === "gitignore.template") continue;
|
|
84729
|
-
if (!
|
|
84804
|
+
if (!fs64.existsSync(path72.join(harnessDir, file))) installMissing.push(file);
|
|
84730
84805
|
}
|
|
84731
84806
|
let phantomVerificationIds = [];
|
|
84732
84807
|
try {
|
|
@@ -84761,13 +84836,13 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
84761
84836
|
const harnessDir = getHarnessDir(resolved);
|
|
84762
84837
|
const effective = plan ?? buildPre10Plan(resolved);
|
|
84763
84838
|
const backupDir = path72.join(harnessDir, MIGRATE_BACKUP_DIR);
|
|
84764
|
-
|
|
84839
|
+
fs64.mkdirSync(backupDir, { recursive: true });
|
|
84765
84840
|
const backup = (file) => {
|
|
84766
84841
|
const src = path72.join(harnessDir, file);
|
|
84767
|
-
if (!
|
|
84842
|
+
if (!fs64.existsSync(src)) return;
|
|
84768
84843
|
const dest = path72.join(backupDir, file);
|
|
84769
|
-
|
|
84770
|
-
|
|
84844
|
+
fs64.mkdirSync(path72.dirname(dest), { recursive: true });
|
|
84845
|
+
fs64.copyFileSync(src, dest);
|
|
84771
84846
|
};
|
|
84772
84847
|
const written = [];
|
|
84773
84848
|
const deleted = [];
|
|
@@ -84775,7 +84850,7 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
84775
84850
|
const composed = composeProfileTemplateMap(effective.profile);
|
|
84776
84851
|
for (const script of effective.deleteLifecycleScripts) {
|
|
84777
84852
|
backup(script);
|
|
84778
|
-
|
|
84853
|
+
fs64.rmSync(path72.join(harnessDir, script), { force: true });
|
|
84779
84854
|
deleted.push(script);
|
|
84780
84855
|
}
|
|
84781
84856
|
if (stripLifecycleShimCommands(resolved)) {
|
|
@@ -84783,26 +84858,26 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
84783
84858
|
}
|
|
84784
84859
|
for (const file of effective.deleteMachinery) {
|
|
84785
84860
|
backup(file);
|
|
84786
|
-
|
|
84861
|
+
fs64.rmSync(path72.join(harnessDir, file), { force: true });
|
|
84787
84862
|
deleted.push(file);
|
|
84788
84863
|
}
|
|
84789
84864
|
for (const doc of effective.retireDocs ?? []) {
|
|
84790
84865
|
backup(doc);
|
|
84791
84866
|
}
|
|
84792
84867
|
const libDir = path72.join(harnessDir, "lib");
|
|
84793
|
-
if (
|
|
84794
|
-
|
|
84868
|
+
if (fs64.existsSync(libDir) && fs64.readdirSync(libDir).length === 0) {
|
|
84869
|
+
fs64.rmdirSync(libDir);
|
|
84795
84870
|
deleted.push("lib/");
|
|
84796
84871
|
}
|
|
84797
84872
|
for (const file of effective.installMissing ?? []) {
|
|
84798
84873
|
const source = composed.get(file);
|
|
84799
84874
|
if (!source) continue;
|
|
84800
84875
|
const dest = path72.join(harnessDir, file);
|
|
84801
|
-
if (
|
|
84876
|
+
if (fs64.existsSync(dest)) continue;
|
|
84802
84877
|
const rendered = substituteTemplateTokens(readComposedTemplateContent(source), projectName);
|
|
84803
|
-
|
|
84804
|
-
|
|
84805
|
-
if (/\.(sh|mjs)$/.test(file))
|
|
84878
|
+
fs64.mkdirSync(path72.dirname(dest), { recursive: true });
|
|
84879
|
+
fs64.writeFileSync(dest, rendered);
|
|
84880
|
+
if (/\.(sh|mjs)$/.test(file)) fs64.chmodSync(dest, 493);
|
|
84806
84881
|
written.push(file);
|
|
84807
84882
|
}
|
|
84808
84883
|
if (effective.phantomVerificationIds.length > 0) {
|
|
@@ -84817,7 +84892,7 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
84817
84892
|
}
|
|
84818
84893
|
if (effective.env) {
|
|
84819
84894
|
backup("harness.env");
|
|
84820
|
-
|
|
84895
|
+
fs64.writeFileSync(path72.join(harnessDir, "harness.env"), effective.env.content);
|
|
84821
84896
|
written.push("harness.env");
|
|
84822
84897
|
}
|
|
84823
84898
|
const manifest = readManifest(resolved);
|
|
@@ -84832,7 +84907,7 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
84832
84907
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
84833
84908
|
});
|
|
84834
84909
|
}
|
|
84835
|
-
|
|
84910
|
+
fs64.writeFileSync(
|
|
84836
84911
|
path72.join(harnessDir, MIGRATE_PLAN_FILE),
|
|
84837
84912
|
JSON.stringify({ ...effective, appliedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n"
|
|
84838
84913
|
);
|
|
@@ -84855,25 +84930,25 @@ function pendingMigrations(repoPath) {
|
|
|
84855
84930
|
function writeMigrationPlan(repoPath, plan) {
|
|
84856
84931
|
const harnessDir = getHarnessDir(path72.resolve(repoPath));
|
|
84857
84932
|
const planPath = path72.join(harnessDir, MIGRATE_PLAN_FILE);
|
|
84858
|
-
|
|
84859
|
-
|
|
84933
|
+
fs64.mkdirSync(path72.dirname(planPath), { recursive: true });
|
|
84934
|
+
fs64.writeFileSync(planPath, JSON.stringify(plan, null, 2) + "\n");
|
|
84860
84935
|
return planPath;
|
|
84861
84936
|
}
|
|
84862
84937
|
function removeMigrationArtifacts(repoPath) {
|
|
84863
84938
|
const harnessDir = getHarnessDir(path72.resolve(repoPath));
|
|
84864
|
-
|
|
84865
|
-
|
|
84939
|
+
fs64.rmSync(path72.join(harnessDir, MIGRATE_DIR), { recursive: true, force: true });
|
|
84940
|
+
fs64.rmSync(path72.join(harnessDir, "MIGRATE-PROMPT.md"), { force: true });
|
|
84866
84941
|
}
|
|
84867
84942
|
|
|
84868
84943
|
// src/harness/doctor.ts
|
|
84869
84944
|
function listHarnessShellScripts(harnessDir) {
|
|
84870
84945
|
const out = [];
|
|
84871
84946
|
const push = (dir, prefix) => {
|
|
84872
|
-
if (!
|
|
84873
|
-
for (const entry of
|
|
84947
|
+
if (!fs65.existsSync(dir)) return;
|
|
84948
|
+
for (const entry of fs65.readdirSync(dir).sort()) {
|
|
84874
84949
|
if (!entry.endsWith(".sh")) continue;
|
|
84875
84950
|
const full = path73.join(dir, entry);
|
|
84876
|
-
if (!
|
|
84951
|
+
if (!fs65.statSync(full).isFile()) continue;
|
|
84877
84952
|
out.push(prefix ? `${prefix}/${entry}` : entry);
|
|
84878
84953
|
}
|
|
84879
84954
|
};
|
|
@@ -84900,8 +84975,8 @@ var PRE_1_0_FUNCTION_RE = /^\s*(har_infra_enabled|har_pg|har_node_[a-z_]+|har_pk
|
|
|
84900
84975
|
var LEGACY_TRIPLET_RE = /^export\s+HARNESS_[A-Z0-9_]+_PORT_(DEFAULT|SCAN_START|SCAN_END)=/m;
|
|
84901
84976
|
function detectContract(harnessDir) {
|
|
84902
84977
|
const envPath = path73.join(harnessDir, "harness.env");
|
|
84903
|
-
if (!
|
|
84904
|
-
const content =
|
|
84978
|
+
if (!fs65.existsSync(envPath)) return "none";
|
|
84979
|
+
const content = fs65.readFileSync(envPath, "utf8");
|
|
84905
84980
|
if (PRE_1_0_FUNCTION_RE.test(content) || LEGACY_TRIPLET_RE.test(content)) {
|
|
84906
84981
|
return "pre-1.0";
|
|
84907
84982
|
}
|
|
@@ -84934,7 +85009,7 @@ function runDoctor(repoPath) {
|
|
|
84934
85009
|
const harnessDir = getHarnessDir(repoPath);
|
|
84935
85010
|
const findings = [];
|
|
84936
85011
|
const skipped = /* @__PURE__ */ new Set();
|
|
84937
|
-
if (!
|
|
85012
|
+
if (!fs65.existsSync(harnessDir)) {
|
|
84938
85013
|
return {
|
|
84939
85014
|
ok: false,
|
|
84940
85015
|
contract: "none",
|
|
@@ -85004,8 +85079,8 @@ function runDoctor(repoPath) {
|
|
|
85004
85079
|
let registry2 = null;
|
|
85005
85080
|
try {
|
|
85006
85081
|
const stagesPath = path73.join(harnessDir, "stages.json");
|
|
85007
|
-
if (
|
|
85008
|
-
const raw = JSON.parse(
|
|
85082
|
+
if (fs65.existsSync(stagesPath)) {
|
|
85083
|
+
const raw = JSON.parse(fs65.readFileSync(stagesPath, "utf8"));
|
|
85009
85084
|
if (typeof raw !== "object" || raw === null || !Array.isArray(raw.stages)) {
|
|
85010
85085
|
throw new Error("stages.json has no `stages` array \u2014 the registry is structurally invalid");
|
|
85011
85086
|
}
|
|
@@ -85037,7 +85112,7 @@ function runDoctor(repoPath) {
|
|
|
85037
85112
|
const file = resolveStageFile(harnessDir, stage);
|
|
85038
85113
|
if (!file) continue;
|
|
85039
85114
|
const rel = path73.relative(harnessDir, file);
|
|
85040
|
-
if (!
|
|
85115
|
+
if (!fs65.existsSync(file)) {
|
|
85041
85116
|
findings.push({
|
|
85042
85117
|
check: "stage-files",
|
|
85043
85118
|
severity: contractSeverity,
|
|
@@ -85047,7 +85122,7 @@ function runDoctor(repoPath) {
|
|
|
85047
85122
|
});
|
|
85048
85123
|
continue;
|
|
85049
85124
|
}
|
|
85050
|
-
if (rel.endsWith(".sh") && !(
|
|
85125
|
+
if (rel.endsWith(".sh") && !(fs65.statSync(file).mode & 73)) {
|
|
85051
85126
|
findings.push({
|
|
85052
85127
|
check: "stage-files",
|
|
85053
85128
|
severity: "warning",
|
|
@@ -85070,7 +85145,7 @@ function runDoctor(repoPath) {
|
|
|
85070
85145
|
continue;
|
|
85071
85146
|
}
|
|
85072
85147
|
const file = resolveStageFile(harnessDir, stage);
|
|
85073
|
-
if (file && !
|
|
85148
|
+
if (file && !fs65.existsSync(file)) {
|
|
85074
85149
|
findings.push({
|
|
85075
85150
|
check: "lifecycle-stages",
|
|
85076
85151
|
severity: contractSeverity,
|
|
@@ -85123,7 +85198,7 @@ function runDoctor(repoPath) {
|
|
|
85123
85198
|
} else {
|
|
85124
85199
|
const runtimeRel = path73.join(EJECTED_RUNTIME_DIR, EJECTED_RUNTIME_BUNDLE);
|
|
85125
85200
|
const runtimePath = path73.join(harnessDir, runtimeRel);
|
|
85126
|
-
if (!
|
|
85201
|
+
if (!fs65.existsSync(runtimePath)) {
|
|
85127
85202
|
findings.push({
|
|
85128
85203
|
check: "ejected-runtime",
|
|
85129
85204
|
severity: "error",
|
|
@@ -85136,7 +85211,7 @@ function runDoctor(repoPath) {
|
|
|
85136
85211
|
for (const entry of listSlotRegistryEntries(repoPath)) {
|
|
85137
85212
|
if (entry.status === "completed") continue;
|
|
85138
85213
|
const dir = entry.worktreePath ?? entry.workDir;
|
|
85139
|
-
if (dir && !
|
|
85214
|
+
if (dir && !fs65.existsSync(dir)) {
|
|
85140
85215
|
findings.push({
|
|
85141
85216
|
check: "slot-registry",
|
|
85142
85217
|
severity: "warning",
|
|
@@ -85147,10 +85222,10 @@ function runDoctor(repoPath) {
|
|
|
85147
85222
|
}
|
|
85148
85223
|
}
|
|
85149
85224
|
const hooksDir = path73.join(harnessDir, "hooks");
|
|
85150
|
-
if (
|
|
85151
|
-
for (const file of
|
|
85225
|
+
if (fs65.existsSync(hooksDir)) {
|
|
85226
|
+
for (const file of fs65.readdirSync(hooksDir).sort()) {
|
|
85152
85227
|
const full = path73.join(hooksDir, file);
|
|
85153
|
-
if (!
|
|
85228
|
+
if (!fs65.statSync(full).isFile() || !file.endsWith(".sh")) continue;
|
|
85154
85229
|
if (!LIFECYCLE_HOOKS.includes(file.replace(/\.sh$/, ""))) {
|
|
85155
85230
|
findings.push({
|
|
85156
85231
|
check: "hooks",
|
|
@@ -85161,7 +85236,7 @@ function runDoctor(repoPath) {
|
|
|
85161
85236
|
});
|
|
85162
85237
|
continue;
|
|
85163
85238
|
}
|
|
85164
|
-
if (!(
|
|
85239
|
+
if (!(fs65.statSync(full).mode & 73)) {
|
|
85165
85240
|
findings.push({
|
|
85166
85241
|
check: "hooks",
|
|
85167
85242
|
severity: "warning",
|
|
@@ -85176,12 +85251,12 @@ function runDoctor(repoPath) {
|
|
|
85176
85251
|
const full = path73.join(harnessDir, rel);
|
|
85177
85252
|
let content;
|
|
85178
85253
|
try {
|
|
85179
|
-
content =
|
|
85254
|
+
content = fs65.readFileSync(full, "utf8");
|
|
85180
85255
|
} catch {
|
|
85181
85256
|
continue;
|
|
85182
85257
|
}
|
|
85183
85258
|
for (const machinery of LEGACY_MACHINERY_FILES) {
|
|
85184
|
-
if (
|
|
85259
|
+
if (fs65.existsSync(path73.join(harnessDir, machinery))) continue;
|
|
85185
85260
|
const base = machinery.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
85186
85261
|
const loadRe = new RegExp(
|
|
85187
85262
|
`(?:\\bsource\\b|\\bbash\\b|\\bexec\\b|(?:^|[;&|(])\\s*\\.\\s)[^\\n#]*${base}`
|
|
@@ -85285,7 +85360,7 @@ function summarizeDoctorReport(report) {
|
|
|
85285
85360
|
}
|
|
85286
85361
|
|
|
85287
85362
|
// src/harness/migrate-prompt.ts
|
|
85288
|
-
var
|
|
85363
|
+
var fs66 = __toESM(require("fs"));
|
|
85289
85364
|
var path74 = __toESM(require("path"));
|
|
85290
85365
|
init_paths();
|
|
85291
85366
|
init_file_ops();
|
|
@@ -85400,7 +85475,7 @@ function loadTemplate2() {
|
|
|
85400
85475
|
if (!filePath) {
|
|
85401
85476
|
throw new Error("Migration prompt template not found: migration-prompt.md. Run npm run build.");
|
|
85402
85477
|
}
|
|
85403
|
-
return
|
|
85478
|
+
return fs66.readFileSync(filePath, "utf8");
|
|
85404
85479
|
}
|
|
85405
85480
|
function buildMigrationPrompt(plan, applied) {
|
|
85406
85481
|
return loadTemplate2().replace("{{MIGRATION_SECTION}}", buildMigrationSection(plan, applied));
|
|
@@ -85414,8 +85489,8 @@ function writeMigrationPrompt(repoPath, content) {
|
|
|
85414
85489
|
// src/core/harness.ts
|
|
85415
85490
|
function listHarnessScripts(repoPath) {
|
|
85416
85491
|
const harnessDir = getHarnessDir(repoPath);
|
|
85417
|
-
if (!
|
|
85418
|
-
return
|
|
85492
|
+
if (!fs67.existsSync(harnessDir)) return [];
|
|
85493
|
+
return fs67.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
|
|
85419
85494
|
}
|
|
85420
85495
|
function describeProject(repoPath) {
|
|
85421
85496
|
const resolved = path75.resolve(repoPath);
|
|
@@ -85439,7 +85514,7 @@ function describeProject(repoPath) {
|
|
|
85439
85514
|
}
|
|
85440
85515
|
async function initHarness(options) {
|
|
85441
85516
|
const repoPath = path75.resolve(options.repoPath);
|
|
85442
|
-
if (!
|
|
85517
|
+
if (!fs67.existsSync(repoPath)) {
|
|
85443
85518
|
throw new Error(`Path not found: ${repoPath}`);
|
|
85444
85519
|
}
|
|
85445
85520
|
const scaffold = scaffoldHarnessBoilerplate(repoPath, {
|
|
@@ -85462,7 +85537,7 @@ async function initHarness(options) {
|
|
|
85462
85537
|
async function maintainHarness(options) {
|
|
85463
85538
|
const repoPath = path75.resolve(options.repoPath);
|
|
85464
85539
|
const harnessDir = getHarnessDir(repoPath);
|
|
85465
|
-
if (!
|
|
85540
|
+
if (!fs67.existsSync(harnessDir)) {
|
|
85466
85541
|
throw new Error('No .har/ found. Run "har onboard" first.');
|
|
85467
85542
|
}
|
|
85468
85543
|
let migration;
|
|
@@ -85540,7 +85615,7 @@ function addPlugin(repoPath, pluginId, options = {}) {
|
|
|
85540
85615
|
}
|
|
85541
85616
|
|
|
85542
85617
|
// src/harness/adaptation-prompt.ts
|
|
85543
|
-
var
|
|
85618
|
+
var fs68 = __toESM(require("fs"));
|
|
85544
85619
|
var path76 = __toESM(require("path"));
|
|
85545
85620
|
var readline5 = __toESM(require("readline"));
|
|
85546
85621
|
|
|
@@ -85632,7 +85707,7 @@ function loadTemplate3(name) {
|
|
|
85632
85707
|
if (!filePath) {
|
|
85633
85708
|
throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
|
|
85634
85709
|
}
|
|
85635
|
-
return
|
|
85710
|
+
return fs68.readFileSync(filePath, "utf8");
|
|
85636
85711
|
}
|
|
85637
85712
|
function applyProfilePlaceholders(content, profile) {
|
|
85638
85713
|
return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
|
|
@@ -85710,7 +85785,7 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
85710
85785
|
}
|
|
85711
85786
|
|
|
85712
85787
|
// src/harness/cursor-rule.ts
|
|
85713
|
-
var
|
|
85788
|
+
var fs69 = __toESM(require("fs"));
|
|
85714
85789
|
var path77 = __toESM(require("path"));
|
|
85715
85790
|
var readline6 = __toESM(require("readline"));
|
|
85716
85791
|
init_file_ops();
|
|
@@ -85721,17 +85796,17 @@ function getCursorRulePath(repoPath) {
|
|
|
85721
85796
|
return path77.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
85722
85797
|
}
|
|
85723
85798
|
function isCursorWorkspace(repoPath) {
|
|
85724
|
-
return
|
|
85799
|
+
return fs69.existsSync(path77.join(repoPath, ".cursor"));
|
|
85725
85800
|
}
|
|
85726
85801
|
function cursorRuleExists(repoPath) {
|
|
85727
|
-
return
|
|
85802
|
+
return fs69.existsSync(getCursorRulePath(repoPath));
|
|
85728
85803
|
}
|
|
85729
85804
|
function scaffoldCursorRule(repoPath) {
|
|
85730
85805
|
const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
|
|
85731
85806
|
if (!templatePath) {
|
|
85732
85807
|
throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
|
|
85733
85808
|
}
|
|
85734
|
-
const content =
|
|
85809
|
+
const content = fs69.readFileSync(templatePath, "utf8");
|
|
85735
85810
|
writeFileSafe(getCursorRulePath(repoPath), content);
|
|
85736
85811
|
}
|
|
85737
85812
|
async function handleCursorRule(options) {
|
|
@@ -86564,7 +86639,7 @@ init_work_units();
|
|
|
86564
86639
|
init_manifest();
|
|
86565
86640
|
|
|
86566
86641
|
// src/core/cleanup-service.ts
|
|
86567
|
-
var
|
|
86642
|
+
var fs71 = __toESM(require("fs"));
|
|
86568
86643
|
var os23 = __toESM(require("os"));
|
|
86569
86644
|
var path81 = __toESM(require("path"));
|
|
86570
86645
|
var import_child_process20 = require("child_process");
|
|
@@ -86663,7 +86738,7 @@ function classifySlotCandidate(repoPath, projectName, slot, options) {
|
|
|
86663
86738
|
return candidate;
|
|
86664
86739
|
}
|
|
86665
86740
|
function resolveRepoForWorktree(worktreePath) {
|
|
86666
|
-
if (!
|
|
86741
|
+
if (!fs71.existsSync(worktreePath)) return void 0;
|
|
86667
86742
|
const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
|
|
86668
86743
|
if (!commonDir) return void 0;
|
|
86669
86744
|
const gitRoot = path81.resolve(worktreePath, commonDir, "..");
|
|
@@ -86672,9 +86747,9 @@ function resolveRepoForWorktree(worktreePath) {
|
|
|
86672
86747
|
}
|
|
86673
86748
|
function discoverOrphanWorktrees(knownPaths) {
|
|
86674
86749
|
const worktreesRoot = getWorktreesRoot();
|
|
86675
|
-
if (!
|
|
86750
|
+
if (!fs71.existsSync(worktreesRoot)) return [];
|
|
86676
86751
|
const orphans = [];
|
|
86677
|
-
for (const entry of
|
|
86752
|
+
for (const entry of fs71.readdirSync(worktreesRoot, { withFileTypes: true })) {
|
|
86678
86753
|
if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
|
|
86679
86754
|
const worktreePath = path81.resolve(path81.join(worktreesRoot, entry.name));
|
|
86680
86755
|
if (knownPaths.has(worktreePath)) continue;
|
|
@@ -86701,7 +86776,7 @@ async function discoverCleanupCandidates(options = {}) {
|
|
|
86701
86776
|
const candidates = [];
|
|
86702
86777
|
const knownWorktreePaths = /* @__PURE__ */ new Set();
|
|
86703
86778
|
for (const repoPath of repoPaths) {
|
|
86704
|
-
if (!
|
|
86779
|
+
if (!fs71.existsSync(repoPath) || !readManifest(repoPath)) continue;
|
|
86705
86780
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
86706
86781
|
const canonicalRepo = canonicalizeControlRepoPath(harnessRoot);
|
|
86707
86782
|
const status = collectEnvironmentStatus(harnessRoot);
|
|
@@ -86814,7 +86889,7 @@ async function executeCleanupCandidates(candidates, options = {}) {
|
|
|
86814
86889
|
continue;
|
|
86815
86890
|
}
|
|
86816
86891
|
if (candidate.kind === "orphan_worktree" && candidate.worktreePath) {
|
|
86817
|
-
if (
|
|
86892
|
+
if (fs71.existsSync(candidate.worktreePath)) {
|
|
86818
86893
|
const repoRoot = candidate.repoPath !== getWorktreesRoot() ? candidate.repoPath : resolveRepoForWorktree(candidate.worktreePath);
|
|
86819
86894
|
if (repoRoot) {
|
|
86820
86895
|
try {
|
|
@@ -86825,8 +86900,8 @@ async function executeCleanupCandidates(candidates, options = {}) {
|
|
|
86825
86900
|
} catch {
|
|
86826
86901
|
}
|
|
86827
86902
|
}
|
|
86828
|
-
if (
|
|
86829
|
-
|
|
86903
|
+
if (fs71.existsSync(candidate.worktreePath)) {
|
|
86904
|
+
fs71.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
86830
86905
|
}
|
|
86831
86906
|
}
|
|
86832
86907
|
outcomes.push({ candidate, ok: true });
|
|
@@ -86972,7 +87047,7 @@ function warnIfDockerUnavailable(status = detectDockerStatus()) {
|
|
|
86972
87047
|
}
|
|
86973
87048
|
|
|
86974
87049
|
// src/core/onboarding-preferences.ts
|
|
86975
|
-
var
|
|
87050
|
+
var fs72 = __toESM(require("fs"));
|
|
86976
87051
|
var os24 = __toESM(require("os"));
|
|
86977
87052
|
var path82 = __toESM(require("path"));
|
|
86978
87053
|
init_schema2();
|
|
@@ -86985,8 +87060,8 @@ function getOnboardingPreferencesPath() {
|
|
|
86985
87060
|
function readOnboardingPreferences() {
|
|
86986
87061
|
const preferencePath = getOnboardingPreferencesPath();
|
|
86987
87062
|
try {
|
|
86988
|
-
if (!
|
|
86989
|
-
return OnboardingPreferencesSchema.parse(JSON.parse(
|
|
87063
|
+
if (!fs72.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
|
|
87064
|
+
return OnboardingPreferencesSchema.parse(JSON.parse(fs72.readFileSync(preferencePath, "utf8")));
|
|
86990
87065
|
} catch {
|
|
86991
87066
|
return OnboardingPreferencesSchema.parse({});
|
|
86992
87067
|
}
|
|
@@ -87011,8 +87086,8 @@ function writeOnboardingPreferences(overrides) {
|
|
|
87011
87086
|
};
|
|
87012
87087
|
const parsed = OnboardingPreferencesSchema.parse(preference);
|
|
87013
87088
|
const preferencePath = getOnboardingPreferencesPath();
|
|
87014
|
-
|
|
87015
|
-
|
|
87089
|
+
fs72.mkdirSync(path82.dirname(preferencePath), { recursive: true });
|
|
87090
|
+
fs72.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
|
|
87016
87091
|
`);
|
|
87017
87092
|
return parsed;
|
|
87018
87093
|
}
|
|
@@ -87640,7 +87715,7 @@ async function handleAddPlugin(argv) {
|
|
|
87640
87715
|
console.error(` Docs: ${result.docsPath}`);
|
|
87641
87716
|
console.error("");
|
|
87642
87717
|
info(`Adaptation prompt saved to ${result.adaptPromptPath}`);
|
|
87643
|
-
const promptContent =
|
|
87718
|
+
const promptContent = fs73.readFileSync(path83.join(repoPath, result.adaptPromptPath), "utf8");
|
|
87644
87719
|
await offerAdaptationPromptClipboard(promptContent, { fileLabel: result.adaptPromptPath });
|
|
87645
87720
|
} catch (err) {
|
|
87646
87721
|
error(err.message);
|
|
@@ -88185,7 +88260,7 @@ init_portal_targets();
|
|
|
88185
88260
|
init_control_config();
|
|
88186
88261
|
|
|
88187
88262
|
// src/core/portal-connect.ts
|
|
88188
|
-
var
|
|
88263
|
+
var fs74 = __toESM(require("fs"));
|
|
88189
88264
|
var path84 = __toESM(require("path"));
|
|
88190
88265
|
var import_crypto2 = require("crypto");
|
|
88191
88266
|
init_control_repo_path();
|
|
@@ -88356,7 +88431,7 @@ function remainingConnections(connections, usedAliases) {
|
|
|
88356
88431
|
init_portal_targets();
|
|
88357
88432
|
function attachRepoIfPresent(alias, repoPath) {
|
|
88358
88433
|
const resolved = path84.resolve(repoPath ?? ".");
|
|
88359
|
-
if (!
|
|
88434
|
+
if (!fs74.existsSync(resolved)) return null;
|
|
88360
88435
|
const canonical = canonicalizeControlRepoPath(resolved);
|
|
88361
88436
|
attachRepoPortalTarget(canonical, alias);
|
|
88362
88437
|
recordRepoForControlSync(canonical);
|
|
@@ -88424,7 +88499,7 @@ async function runPortalConnect(input) {
|
|
|
88424
88499
|
}
|
|
88425
88500
|
function listRegisteredReposForConnect(repoPath) {
|
|
88426
88501
|
const resolved = repoPath ? path84.resolve(repoPath) : null;
|
|
88427
|
-
const current = resolved &&
|
|
88502
|
+
const current = resolved && fs74.existsSync(resolved) ? canonicalizeControlRepoPath(resolved) : null;
|
|
88428
88503
|
return [.../* @__PURE__ */ new Set([...current ? [current] : [], ...listRegisteredRepos()])];
|
|
88429
88504
|
}
|
|
88430
88505
|
|
|
@@ -88740,7 +88815,7 @@ init_control_port();
|
|
|
88740
88815
|
init_control_sync();
|
|
88741
88816
|
|
|
88742
88817
|
// src/core/control-sync-selection.ts
|
|
88743
|
-
var
|
|
88818
|
+
var fs75 = __toESM(require("fs"));
|
|
88744
88819
|
var os25 = __toESM(require("os"));
|
|
88745
88820
|
var path85 = __toESM(require("path"));
|
|
88746
88821
|
init_control_repo_path();
|
|
@@ -88753,8 +88828,8 @@ function getSelectionPath() {
|
|
|
88753
88828
|
function readSyncSelection() {
|
|
88754
88829
|
const selectionPath = getSelectionPath();
|
|
88755
88830
|
try {
|
|
88756
|
-
if (!
|
|
88757
|
-
const parsed = JSON.parse(
|
|
88831
|
+
if (!fs75.existsSync(selectionPath)) return null;
|
|
88832
|
+
const parsed = JSON.parse(fs75.readFileSync(selectionPath, "utf8"));
|
|
88758
88833
|
if (!Array.isArray(parsed.repos)) return null;
|
|
88759
88834
|
return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
|
|
88760
88835
|
} catch {
|
|
@@ -88764,8 +88839,8 @@ function readSyncSelection() {
|
|
|
88764
88839
|
function writeSyncSelection(repos) {
|
|
88765
88840
|
const selectionPath = getSelectionPath();
|
|
88766
88841
|
const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
|
|
88767
|
-
|
|
88768
|
-
|
|
88842
|
+
fs75.mkdirSync(path85.dirname(selectionPath), { recursive: true });
|
|
88843
|
+
fs75.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
|
|
88769
88844
|
}
|
|
88770
88845
|
function resolveSyncSelection(input) {
|
|
88771
88846
|
const { discovered, stored, forceSelect, isTTY } = input;
|
|
@@ -88792,7 +88867,7 @@ function resolveSyncSelection(input) {
|
|
|
88792
88867
|
}
|
|
88793
88868
|
|
|
88794
88869
|
// src/core/control-unregister.ts
|
|
88795
|
-
var
|
|
88870
|
+
var fs76 = __toESM(require("fs"));
|
|
88796
88871
|
var path86 = __toESM(require("path"));
|
|
88797
88872
|
init_control_repo_path();
|
|
88798
88873
|
init_control_registry();
|
|
@@ -88805,7 +88880,7 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
88805
88880
|
const add = (partial2) => {
|
|
88806
88881
|
const resolved = path86.resolve(partial2.worktreePath);
|
|
88807
88882
|
if (!resolved || resolved === harnessRoot) return;
|
|
88808
|
-
const exists = partial2.exists ??
|
|
88883
|
+
const exists = partial2.exists ?? fs76.existsSync(resolved);
|
|
88809
88884
|
const prev = byPath.get(resolved);
|
|
88810
88885
|
if (prev) {
|
|
88811
88886
|
byPath.set(resolved, {
|
|
@@ -88919,28 +88994,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
|
|
|
88919
88994
|
trigger: "cli"
|
|
88920
88995
|
});
|
|
88921
88996
|
if (result.code !== 0) {
|
|
88922
|
-
if (
|
|
88923
|
-
|
|
88997
|
+
if (fs76.existsSync(candidate.worktreePath)) {
|
|
88998
|
+
fs76.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
88924
88999
|
}
|
|
88925
89000
|
}
|
|
88926
89001
|
outcomes.push({
|
|
88927
89002
|
path: candidate.worktreePath,
|
|
88928
89003
|
agentId: candidate.agentId,
|
|
88929
|
-
deleted: !
|
|
88930
|
-
error: result.code !== 0 &&
|
|
89004
|
+
deleted: !fs76.existsSync(candidate.worktreePath),
|
|
89005
|
+
error: result.code !== 0 && fs76.existsSync(candidate.worktreePath) ? result.stderr : void 0
|
|
88931
89006
|
});
|
|
88932
89007
|
} catch (err) {
|
|
88933
89008
|
const message = err instanceof Error ? err.message : String(err);
|
|
88934
89009
|
try {
|
|
88935
|
-
if (
|
|
88936
|
-
|
|
89010
|
+
if (fs76.existsSync(candidate.worktreePath)) {
|
|
89011
|
+
fs76.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
88937
89012
|
}
|
|
88938
89013
|
} catch {
|
|
88939
89014
|
}
|
|
88940
89015
|
outcomes.push({
|
|
88941
89016
|
path: candidate.worktreePath,
|
|
88942
89017
|
agentId: candidate.agentId,
|
|
88943
|
-
deleted: !
|
|
89018
|
+
deleted: !fs76.existsSync(candidate.worktreePath),
|
|
88944
89019
|
error: message
|
|
88945
89020
|
});
|
|
88946
89021
|
}
|
|
@@ -89003,13 +89078,13 @@ init_control_config();
|
|
|
89003
89078
|
init_control_registry();
|
|
89004
89079
|
|
|
89005
89080
|
// src/core/harness-scrub.ts
|
|
89006
|
-
var
|
|
89081
|
+
var fs77 = __toESM(require("fs"));
|
|
89007
89082
|
var path87 = __toESM(require("path"));
|
|
89008
89083
|
var HARNESS_SCRUB_DIRS = ["runs", "validations", "commit-bindings", "state", "slots"];
|
|
89009
89084
|
function scrubLocalHarnessDirs(repoPath) {
|
|
89010
89085
|
const results = [];
|
|
89011
89086
|
const resolved = path87.resolve(repoPath);
|
|
89012
|
-
if (!
|
|
89087
|
+
if (!fs77.existsSync(resolved)) {
|
|
89013
89088
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
89014
89089
|
results.push({
|
|
89015
89090
|
path: path87.join(resolved, ".har", directory),
|
|
@@ -89022,23 +89097,23 @@ function scrubLocalHarnessDirs(repoPath) {
|
|
|
89022
89097
|
}
|
|
89023
89098
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
89024
89099
|
const target = path87.join(resolved, ".har", directory);
|
|
89025
|
-
if (!
|
|
89100
|
+
if (!fs77.existsSync(target)) {
|
|
89026
89101
|
results.push({ path: target, directory, deleted: true });
|
|
89027
89102
|
continue;
|
|
89028
89103
|
}
|
|
89029
89104
|
try {
|
|
89030
|
-
|
|
89105
|
+
fs77.rmSync(target, { recursive: true, force: true });
|
|
89031
89106
|
results.push({
|
|
89032
89107
|
path: target,
|
|
89033
89108
|
directory,
|
|
89034
|
-
deleted: !
|
|
89035
|
-
error:
|
|
89109
|
+
deleted: !fs77.existsSync(target),
|
|
89110
|
+
error: fs77.existsSync(target) ? "failed to remove directory" : void 0
|
|
89036
89111
|
});
|
|
89037
89112
|
} catch (err) {
|
|
89038
89113
|
results.push({
|
|
89039
89114
|
path: target,
|
|
89040
89115
|
directory,
|
|
89041
|
-
deleted: !
|
|
89116
|
+
deleted: !fs77.existsSync(target),
|
|
89042
89117
|
error: err instanceof Error ? err.message : String(err)
|
|
89043
89118
|
});
|
|
89044
89119
|
}
|
|
@@ -89725,7 +89800,7 @@ var path90 = __toESM(require("path"));
|
|
|
89725
89800
|
init_hooks();
|
|
89726
89801
|
|
|
89727
89802
|
// src/core/claude-hooks.ts
|
|
89728
|
-
var
|
|
89803
|
+
var fs78 = __toESM(require("fs"));
|
|
89729
89804
|
var path89 = __toESM(require("path"));
|
|
89730
89805
|
init_paths();
|
|
89731
89806
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
@@ -89738,8 +89813,8 @@ function isHarGuardEntry(entry) {
|
|
|
89738
89813
|
);
|
|
89739
89814
|
}
|
|
89740
89815
|
function readSettings(settingsPath) {
|
|
89741
|
-
if (!
|
|
89742
|
-
const raw =
|
|
89816
|
+
if (!fs78.existsSync(settingsPath)) return {};
|
|
89817
|
+
const raw = fs78.readFileSync(settingsPath, "utf8").trim();
|
|
89743
89818
|
if (raw === "") return {};
|
|
89744
89819
|
const parsed = JSON.parse(raw);
|
|
89745
89820
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -89748,8 +89823,8 @@ function readSettings(settingsPath) {
|
|
|
89748
89823
|
return parsed;
|
|
89749
89824
|
}
|
|
89750
89825
|
function writeSettings(settingsPath, settings) {
|
|
89751
|
-
|
|
89752
|
-
|
|
89826
|
+
fs78.mkdirSync(path89.dirname(settingsPath), { recursive: true });
|
|
89827
|
+
fs78.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
89753
89828
|
}
|
|
89754
89829
|
function installClaudeGuard(repoPath) {
|
|
89755
89830
|
const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
|
|
@@ -89757,9 +89832,9 @@ function installClaudeGuard(repoPath) {
|
|
|
89757
89832
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
89758
89833
|
}
|
|
89759
89834
|
const guardScript = path89.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
89760
|
-
|
|
89761
|
-
|
|
89762
|
-
|
|
89835
|
+
fs78.mkdirSync(path89.dirname(guardScript), { recursive: true });
|
|
89836
|
+
fs78.copyFileSync(templatePath, guardScript);
|
|
89837
|
+
fs78.chmodSync(guardScript, 493);
|
|
89763
89838
|
const settingsPath = path89.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
89764
89839
|
const settings = readSettings(settingsPath);
|
|
89765
89840
|
const hooks = settings.hooks ?? {};
|
|
@@ -89775,14 +89850,14 @@ function installClaudeGuard(repoPath) {
|
|
|
89775
89850
|
function uninstallClaudeGuard(repoPath) {
|
|
89776
89851
|
let removed = false;
|
|
89777
89852
|
const guardScript = path89.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
89778
|
-
if (
|
|
89779
|
-
|
|
89853
|
+
if (fs78.existsSync(guardScript)) {
|
|
89854
|
+
fs78.rmSync(guardScript);
|
|
89780
89855
|
removed = true;
|
|
89781
89856
|
const parent = path89.dirname(guardScript);
|
|
89782
|
-
if (
|
|
89857
|
+
if (fs78.existsSync(parent) && fs78.readdirSync(parent).length === 0) fs78.rmdirSync(parent);
|
|
89783
89858
|
}
|
|
89784
89859
|
const settingsPath = path89.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
89785
|
-
if (
|
|
89860
|
+
if (fs78.existsSync(settingsPath)) {
|
|
89786
89861
|
const settings = readSettings(settingsPath);
|
|
89787
89862
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
89788
89863
|
if (preToolUse) {
|
|
@@ -89808,7 +89883,7 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
89808
89883
|
}
|
|
89809
89884
|
function claudeGuardInstalled(repoPath) {
|
|
89810
89885
|
const settingsPath = path89.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
89811
|
-
if (!
|
|
89886
|
+
if (!fs78.existsSync(settingsPath)) return false;
|
|
89812
89887
|
try {
|
|
89813
89888
|
const settings = readSettings(settingsPath);
|
|
89814
89889
|
return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
|
|
@@ -97050,13 +97125,13 @@ init_runs();
|
|
|
97050
97125
|
var path92 = __toESM(require("path"));
|
|
97051
97126
|
|
|
97052
97127
|
// src/harness/line-create.ts
|
|
97053
|
-
var
|
|
97128
|
+
var fs79 = __toESM(require("fs"));
|
|
97054
97129
|
var path91 = __toESM(require("path"));
|
|
97055
97130
|
init_paths();
|
|
97056
97131
|
init_schema2();
|
|
97057
97132
|
var LINE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
97058
97133
|
function renderSkeleton(templatePath, tokens) {
|
|
97059
|
-
let content =
|
|
97134
|
+
let content = fs79.readFileSync(templatePath, "utf8");
|
|
97060
97135
|
for (const [token, value] of Object.entries(tokens)) {
|
|
97061
97136
|
content = content.replace(new RegExp(token, "g"), value);
|
|
97062
97137
|
}
|
|
@@ -97075,7 +97150,7 @@ function createLine(repoPath, options) {
|
|
|
97075
97150
|
}
|
|
97076
97151
|
const lineDir = path91.join(resolved, LOCAL_LINES_DIR, id);
|
|
97077
97152
|
const lineDirRel2 = `${LOCAL_LINES_DIR}/${id}`;
|
|
97078
|
-
if (
|
|
97153
|
+
if (fs79.existsSync(lineDir) && !options.force) {
|
|
97079
97154
|
throw new Error(`Line already exists: ${lineDirRel2}/. Use --force to overwrite.`);
|
|
97080
97155
|
}
|
|
97081
97156
|
const stationIds = options.stations?.length ? options.stations : ["S1", "S2"];
|
|
@@ -97149,9 +97224,9 @@ function createLine(repoPath, options) {
|
|
|
97149
97224
|
const filesWritten = [];
|
|
97150
97225
|
const write = (rel, content, executable = false) => {
|
|
97151
97226
|
const abs = path91.join(lineDir, rel);
|
|
97152
|
-
|
|
97153
|
-
|
|
97154
|
-
if (executable)
|
|
97227
|
+
fs79.mkdirSync(path91.dirname(abs), { recursive: true });
|
|
97228
|
+
fs79.writeFileSync(abs, content);
|
|
97229
|
+
if (executable) fs79.chmodSync(abs, 493);
|
|
97155
97230
|
filesWritten.push(`${lineDirRel2}/${rel}`);
|
|
97156
97231
|
};
|
|
97157
97232
|
write("line.manifest.json", `${JSON.stringify(manifest, null, 2)}
|
|
@@ -99224,13 +99299,13 @@ var lineCommand = {
|
|
|
99224
99299
|
var path98 = __toESM(require("path"));
|
|
99225
99300
|
|
|
99226
99301
|
// src/harness/plugin-create.ts
|
|
99227
|
-
var
|
|
99302
|
+
var fs80 = __toESM(require("fs"));
|
|
99228
99303
|
var path97 = __toESM(require("path"));
|
|
99229
99304
|
init_paths();
|
|
99230
99305
|
init_schema2();
|
|
99231
99306
|
var PLUGIN_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
99232
99307
|
function renderSkeleton2(templatePath, tokens) {
|
|
99233
|
-
let content =
|
|
99308
|
+
let content = fs80.readFileSync(templatePath, "utf8");
|
|
99234
99309
|
for (const [token, value] of Object.entries(tokens)) {
|
|
99235
99310
|
content = content.replace(new RegExp(token, "g"), value);
|
|
99236
99311
|
}
|
|
@@ -99255,7 +99330,7 @@ function createLocalPlugin(repoPath, options) {
|
|
|
99255
99330
|
}
|
|
99256
99331
|
const pluginDir = path97.join(resolved, LOCAL_PLUGINS_DIR, id);
|
|
99257
99332
|
const pluginDirRel = `${LOCAL_PLUGINS_DIR}/${id}`;
|
|
99258
|
-
if (
|
|
99333
|
+
if (fs80.existsSync(pluginDir) && !options.force) {
|
|
99259
99334
|
throw new Error(`Plugin already exists: ${pluginDirRel}/. Use --force to overwrite.`);
|
|
99260
99335
|
}
|
|
99261
99336
|
const description = options.description ?? `Custom ${kind} stage (local plugin: ${id})`;
|
|
@@ -99298,9 +99373,9 @@ function createLocalPlugin(repoPath, options) {
|
|
|
99298
99373
|
const filesWritten = [];
|
|
99299
99374
|
const write = (rel, content, executable = false) => {
|
|
99300
99375
|
const abs = path97.join(pluginDir, rel);
|
|
99301
|
-
|
|
99302
|
-
|
|
99303
|
-
if (executable)
|
|
99376
|
+
fs80.mkdirSync(path97.dirname(abs), { recursive: true });
|
|
99377
|
+
fs80.writeFileSync(abs, content);
|
|
99378
|
+
if (executable) fs80.chmodSync(abs, 493);
|
|
99304
99379
|
filesWritten.push(`${pluginDirRel}/${rel}`);
|
|
99305
99380
|
};
|
|
99306
99381
|
write("template.manifest.json", `${JSON.stringify(manifest, null, 2)}
|
|
@@ -99800,16 +99875,16 @@ async function runCli() {
|
|
|
99800
99875
|
}
|
|
99801
99876
|
|
|
99802
99877
|
// src/core/prefer-local-runtime.ts
|
|
99803
|
-
var
|
|
99878
|
+
var fs81 = __toESM(require("fs"));
|
|
99804
99879
|
var path100 = __toESM(require("path"));
|
|
99805
99880
|
var import_child_process22 = require("child_process");
|
|
99806
99881
|
init_package_version();
|
|
99807
99882
|
var PACKAGE_NAME = "@osfactory/har";
|
|
99808
99883
|
function readPackageJson(dir) {
|
|
99809
99884
|
const pkgPath = path100.join(dir, "package.json");
|
|
99810
|
-
if (!
|
|
99885
|
+
if (!fs81.existsSync(pkgPath)) return null;
|
|
99811
99886
|
try {
|
|
99812
|
-
return JSON.parse(
|
|
99887
|
+
return JSON.parse(fs81.readFileSync(pkgPath, "utf8"));
|
|
99813
99888
|
} catch {
|
|
99814
99889
|
return null;
|
|
99815
99890
|
}
|
|
@@ -99823,11 +99898,11 @@ function resolveHarEntry(pkgDir, pkg) {
|
|
|
99823
99898
|
rel = pkg.bin;
|
|
99824
99899
|
}
|
|
99825
99900
|
const entry = path100.resolve(pkgDir, rel);
|
|
99826
|
-
return
|
|
99901
|
+
return fs81.existsSync(entry) ? entry : null;
|
|
99827
99902
|
}
|
|
99828
99903
|
function sameFile(a, b2) {
|
|
99829
99904
|
try {
|
|
99830
|
-
return
|
|
99905
|
+
return fs81.realpathSync(a) === fs81.realpathSync(b2);
|
|
99831
99906
|
} catch {
|
|
99832
99907
|
return path100.resolve(a) === path100.resolve(b2);
|
|
99833
99908
|
}
|