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