@osfactory/har 0.43.2 → 0.44.0
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/README.md +1 -1
- package/dist/index.js +930 -561
- package/dist/prompts/system-authoring.md +7 -7
- package/dist/templates/AGENTS.md.template +73 -0
- package/dist/templates/CLAUDE.md.template +1 -1
- package/dist/templates/adaptation-prompt-init.md +12 -6
- package/dist/templates/adaptation-prompt-maintain.md +18 -6
- package/dist/templates/agent-skills/har-maintain.md +2 -2
- package/dist/templates/agent-skills/setup-har.md +2 -2
- package/dist/templates/cursor-rule.mdc.template +1 -1
- package/dist/templates/har-boilerplate/CLAUDE.agent.md +1 -1
- package/dist/templates/har-boilerplate/README.md +1 -1
- package/dist/templates/har-boilerplate/gitignore.template +2 -0
- package/dist/templates/har-boilerplate-cli/CLAUDE.agent.md +1 -1
- package/dist/templates/har-boilerplate-cli/README.md +1 -1
- package/dist/templates/har-boilerplate-cli/gitignore.template +2 -0
- package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +2 -2
- package/dist/templates/har-boilerplate-ios/CLAUDE.agent.md +1 -1
- package/dist/templates/har-boilerplate-ios/gitignore.template +2 -0
- package/package.json +1 -1
- package/dist/templates/AGENT.md.template +0 -46
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: path64, errorMaps, issueData } = params;
|
|
557
|
+
const fullPath = [...path64, ...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, path64, key) {
|
|
866
866
|
this._cachedPath = [];
|
|
867
867
|
this.parent = parent;
|
|
868
868
|
this.data = value;
|
|
869
|
-
this._path =
|
|
869
|
+
this._path = path64;
|
|
870
870
|
this._key = key;
|
|
871
871
|
}
|
|
872
872
|
get path() {
|
|
@@ -28236,11 +28236,13 @@ var init_manifest = __esm({
|
|
|
28236
28236
|
path4 = __toESM(require("path"));
|
|
28237
28237
|
init_schema2();
|
|
28238
28238
|
init_file_ops();
|
|
28239
|
-
GENERATOR_VERSION = "0.
|
|
28239
|
+
GENERATOR_VERSION = "0.5.0";
|
|
28240
28240
|
MANIFEST_VERSION = "1";
|
|
28241
28241
|
DEFAULT_HAR_DIR = ".har";
|
|
28242
28242
|
CHECKSUM_SKIP = /* @__PURE__ */ new Set([
|
|
28243
28243
|
"manifest.json",
|
|
28244
|
+
"AGENTS.md.proposed",
|
|
28245
|
+
"AGENTS.md.proposed.meta.json",
|
|
28244
28246
|
"AGENT.md.proposed",
|
|
28245
28247
|
"AGENT.md.proposed.meta.json",
|
|
28246
28248
|
"ADAPT-PROMPT.md"
|
|
@@ -33266,14 +33268,14 @@ var require_url_state_machine = __commonJS({
|
|
|
33266
33268
|
return url.replace(/\u0009|\u000A|\u000D/g, "");
|
|
33267
33269
|
}
|
|
33268
33270
|
function shortenPath(url) {
|
|
33269
|
-
const
|
|
33270
|
-
if (
|
|
33271
|
+
const path64 = url.path;
|
|
33272
|
+
if (path64.length === 0) {
|
|
33271
33273
|
return;
|
|
33272
33274
|
}
|
|
33273
|
-
if (url.scheme === "file" &&
|
|
33275
|
+
if (url.scheme === "file" && path64.length === 1 && isNormalizedWindowsDriveLetter(path64[0])) {
|
|
33274
33276
|
return;
|
|
33275
33277
|
}
|
|
33276
|
-
|
|
33278
|
+
path64.pop();
|
|
33277
33279
|
}
|
|
33278
33280
|
function includesCredentials(url) {
|
|
33279
33281
|
return url.username !== "" || url.password !== "";
|
|
@@ -38852,14 +38854,14 @@ __export(fileFromPath_exports, {
|
|
|
38852
38854
|
fileFromPathSync: () => fileFromPathSync,
|
|
38853
38855
|
isFile: () => isFile
|
|
38854
38856
|
});
|
|
38855
|
-
function createFileFromPath(
|
|
38857
|
+
function createFileFromPath(path64, { mtimeMs, size }, filenameOrOptions, options = {}) {
|
|
38856
38858
|
let filename;
|
|
38857
38859
|
if (isPlainObject_default2(filenameOrOptions)) {
|
|
38858
38860
|
[options, filename] = [filenameOrOptions, void 0];
|
|
38859
38861
|
} else {
|
|
38860
38862
|
filename = filenameOrOptions;
|
|
38861
38863
|
}
|
|
38862
|
-
const file = new FileFromPath({ path:
|
|
38864
|
+
const file = new FileFromPath({ path: path64, size, lastModified: mtimeMs });
|
|
38863
38865
|
if (!filename) {
|
|
38864
38866
|
filename = file.name;
|
|
38865
38867
|
}
|
|
@@ -38868,13 +38870,13 @@ function createFileFromPath(path63, { mtimeMs, size }, filenameOrOptions, option
|
|
|
38868
38870
|
lastModified: file.lastModified
|
|
38869
38871
|
});
|
|
38870
38872
|
}
|
|
38871
|
-
function fileFromPathSync(
|
|
38872
|
-
const stats = (0, import_fs5.statSync)(
|
|
38873
|
-
return createFileFromPath(
|
|
38873
|
+
function fileFromPathSync(path64, filenameOrOptions, options = {}) {
|
|
38874
|
+
const stats = (0, import_fs5.statSync)(path64);
|
|
38875
|
+
return createFileFromPath(path64, stats, filenameOrOptions, options);
|
|
38874
38876
|
}
|
|
38875
|
-
async function fileFromPath2(
|
|
38876
|
-
const stats = await import_fs5.promises.stat(
|
|
38877
|
-
return createFileFromPath(
|
|
38877
|
+
async function fileFromPath2(path64, filenameOrOptions, options) {
|
|
38878
|
+
const stats = await import_fs5.promises.stat(path64);
|
|
38879
|
+
return createFileFromPath(path64, stats, filenameOrOptions, options);
|
|
38878
38880
|
}
|
|
38879
38881
|
var import_fs5, import_path5, import_node_domexception, __classPrivateFieldSet5, __classPrivateFieldGet6, _FileFromPath_path, _FileFromPath_start, MESSAGE, FileFromPath;
|
|
38880
38882
|
var init_fileFromPath = __esm({
|
|
@@ -38956,32 +38958,32 @@ __export(otel_hooks_exports, {
|
|
|
38956
38958
|
});
|
|
38957
38959
|
function getOtelHooksHome() {
|
|
38958
38960
|
if (process.env.HAR_OTEL_HOOKS_HOME) {
|
|
38959
|
-
return
|
|
38961
|
+
return path49.resolve(process.env.HAR_OTEL_HOOKS_HOME);
|
|
38960
38962
|
}
|
|
38961
|
-
return
|
|
38963
|
+
return path49.join(os15.homedir(), ".har", "otel-hooks");
|
|
38962
38964
|
}
|
|
38963
38965
|
function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
|
|
38964
|
-
return
|
|
38966
|
+
return path49.join(hooksHome, "otel_config.json");
|
|
38965
38967
|
}
|
|
38966
38968
|
function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
|
|
38967
|
-
return
|
|
38969
|
+
return path49.join(hooksHome, "run-otel-hook.sh");
|
|
38968
38970
|
}
|
|
38969
38971
|
function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
|
|
38970
|
-
return
|
|
38972
|
+
return path49.join(hooksHome, "state");
|
|
38971
38973
|
}
|
|
38972
38974
|
function localOtelHookBin(hooksHome) {
|
|
38973
|
-
return
|
|
38975
|
+
return path49.join(hooksHome, "node_modules", ".bin", "otel-hook");
|
|
38974
38976
|
}
|
|
38975
38977
|
function installedPackageVersion(hooksHome) {
|
|
38976
38978
|
try {
|
|
38977
|
-
const pkgPath =
|
|
38979
|
+
const pkgPath = path49.join(
|
|
38978
38980
|
hooksHome,
|
|
38979
38981
|
"node_modules",
|
|
38980
38982
|
"@osfactory",
|
|
38981
38983
|
"otel-hook",
|
|
38982
38984
|
"package.json"
|
|
38983
38985
|
);
|
|
38984
|
-
const pkg = JSON.parse(
|
|
38986
|
+
const pkg = JSON.parse(fs44.readFileSync(pkgPath, "utf8"));
|
|
38985
38987
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
38986
38988
|
} catch {
|
|
38987
38989
|
return null;
|
|
@@ -39032,15 +39034,15 @@ function buildOtelHooksConfig(options) {
|
|
|
39032
39034
|
};
|
|
39033
39035
|
}
|
|
39034
39036
|
function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
|
|
39035
|
-
|
|
39037
|
+
fs44.mkdirSync(hooksHome, { recursive: true });
|
|
39036
39038
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
39037
|
-
|
|
39039
|
+
fs44.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
|
|
39038
39040
|
`);
|
|
39039
39041
|
return configPath;
|
|
39040
39042
|
}
|
|
39041
39043
|
function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
|
|
39042
|
-
|
|
39043
|
-
|
|
39044
|
+
fs44.mkdirSync(hooksHome, { recursive: true });
|
|
39045
|
+
fs44.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
|
|
39044
39046
|
const wrapperPath = getOtelHooksWrapperPath(hooksHome);
|
|
39045
39047
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
39046
39048
|
const stateDir = getOtelHooksStateDir(hooksHome);
|
|
@@ -39052,9 +39054,9 @@ exec "${otelHookCommand}" run \\
|
|
|
39052
39054
|
--state-dir "${stateDir}" \\
|
|
39053
39055
|
"$@"
|
|
39054
39056
|
`;
|
|
39055
|
-
|
|
39057
|
+
fs44.writeFileSync(wrapperPath, script, { mode: 493 });
|
|
39056
39058
|
try {
|
|
39057
|
-
|
|
39059
|
+
fs44.chmodSync(wrapperPath, 493);
|
|
39058
39060
|
} catch {
|
|
39059
39061
|
}
|
|
39060
39062
|
return wrapperPath;
|
|
@@ -39067,11 +39069,11 @@ function commandExists2(command2) {
|
|
|
39067
39069
|
}
|
|
39068
39070
|
function resolveOtelHookCommand(hooksHome) {
|
|
39069
39071
|
const local = localOtelHookBin(hooksHome);
|
|
39070
|
-
if (
|
|
39072
|
+
if (fs44.existsSync(local)) return local;
|
|
39071
39073
|
return null;
|
|
39072
39074
|
}
|
|
39073
39075
|
function tryInstallPackage(hooksHome) {
|
|
39074
|
-
|
|
39076
|
+
fs44.mkdirSync(hooksHome, { recursive: true });
|
|
39075
39077
|
if (!commandExists2("npm")) {
|
|
39076
39078
|
return {
|
|
39077
39079
|
ok: false,
|
|
@@ -39083,7 +39085,7 @@ function tryInstallPackage(hooksHome) {
|
|
|
39083
39085
|
["install", "--prefix", hooksHome, "--no-fund", "--no-audit", OTEL_HOOKS_PACKAGE],
|
|
39084
39086
|
{ encoding: "utf8", timeout: 18e4 }
|
|
39085
39087
|
);
|
|
39086
|
-
if (result.status === 0 &&
|
|
39088
|
+
if (result.status === 0 && fs44.existsSync(localOtelHookBin(hooksHome))) {
|
|
39087
39089
|
return { ok: true, detail: `npm install --prefix ${hooksHome} ${OTEL_HOOKS_PACKAGE}` };
|
|
39088
39090
|
}
|
|
39089
39091
|
return {
|
|
@@ -39109,14 +39111,14 @@ function uninstallLegacyPythonHooks(hooksHome) {
|
|
|
39109
39111
|
}
|
|
39110
39112
|
function removeLegacyPythonArtifacts(hooksHome) {
|
|
39111
39113
|
const legacyPaths = [
|
|
39112
|
-
|
|
39113
|
-
|
|
39114
|
-
|
|
39114
|
+
path49.join(hooksHome, ".venv"),
|
|
39115
|
+
path49.join(hooksHome, "otel_config.yaml"),
|
|
39116
|
+
path49.join(hooksHome, "venv")
|
|
39115
39117
|
];
|
|
39116
39118
|
for (const target of legacyPaths) {
|
|
39117
39119
|
try {
|
|
39118
|
-
if (
|
|
39119
|
-
|
|
39120
|
+
if (fs44.existsSync(target)) {
|
|
39121
|
+
fs44.rmSync(target, { recursive: true, force: true });
|
|
39120
39122
|
}
|
|
39121
39123
|
} catch {
|
|
39122
39124
|
}
|
|
@@ -39157,10 +39159,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
|
|
|
39157
39159
|
};
|
|
39158
39160
|
}
|
|
39159
39161
|
function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
39160
|
-
if (!
|
|
39162
|
+
if (!fs44.existsSync(filePath)) return false;
|
|
39161
39163
|
let raw;
|
|
39162
39164
|
try {
|
|
39163
|
-
raw =
|
|
39165
|
+
raw = fs44.readFileSync(filePath, "utf8");
|
|
39164
39166
|
} catch {
|
|
39165
39167
|
return false;
|
|
39166
39168
|
}
|
|
@@ -39207,15 +39209,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
|
39207
39209
|
return changed;
|
|
39208
39210
|
};
|
|
39209
39211
|
if (!walk(parsed)) return false;
|
|
39210
|
-
|
|
39212
|
+
fs44.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
39211
39213
|
`);
|
|
39212
39214
|
return true;
|
|
39213
39215
|
}
|
|
39214
39216
|
function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
39215
|
-
if (!
|
|
39217
|
+
if (!fs44.existsSync(filePath)) return false;
|
|
39216
39218
|
let raw;
|
|
39217
39219
|
try {
|
|
39218
|
-
raw =
|
|
39220
|
+
raw = fs44.readFileSync(filePath, "utf8");
|
|
39219
39221
|
} catch {
|
|
39220
39222
|
return false;
|
|
39221
39223
|
}
|
|
@@ -39250,21 +39252,21 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
|
39250
39252
|
}
|
|
39251
39253
|
}
|
|
39252
39254
|
if (!changed) return false;
|
|
39253
|
-
|
|
39255
|
+
fs44.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
39254
39256
|
`);
|
|
39255
39257
|
return true;
|
|
39256
39258
|
}
|
|
39257
39259
|
function rewriteKnownHookRegistrations(wrapperPath) {
|
|
39258
|
-
const home =
|
|
39260
|
+
const home = os15.homedir();
|
|
39259
39261
|
const candidates = [
|
|
39260
|
-
|
|
39261
|
-
|
|
39262
|
-
|
|
39262
|
+
path49.join(home, ".cursor", "hooks.json"),
|
|
39263
|
+
path49.join(home, ".claude", "settings.json"),
|
|
39264
|
+
path49.join(home, ".codex", "hooks.json")
|
|
39263
39265
|
];
|
|
39264
39266
|
for (const filePath of candidates) {
|
|
39265
39267
|
try {
|
|
39266
39268
|
rewriteHookCommandsToWrapper(filePath, wrapperPath);
|
|
39267
|
-
if (filePath.endsWith(`${
|
|
39269
|
+
if (filePath.endsWith(`${path49.sep}.cursor${path49.sep}hooks.json`)) {
|
|
39268
39270
|
pruneLegacyCursorHookEvents(filePath, wrapperPath);
|
|
39269
39271
|
}
|
|
39270
39272
|
} catch {
|
|
@@ -39280,7 +39282,7 @@ function ensureOtelHooks(options) {
|
|
|
39280
39282
|
const hooksHome = getOtelHooksHome();
|
|
39281
39283
|
const errors = [];
|
|
39282
39284
|
const providersSetup = [];
|
|
39283
|
-
|
|
39285
|
+
fs44.mkdirSync(hooksHome, { recursive: true });
|
|
39284
39286
|
let otelHookCommand = resolveOtelHookCommand(hooksHome);
|
|
39285
39287
|
const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
|
|
39286
39288
|
if (needsInstall) {
|
|
@@ -39374,14 +39376,14 @@ function ensureOtelHooks(options) {
|
|
|
39374
39376
|
function disableOtelHooksExport() {
|
|
39375
39377
|
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
39376
39378
|
}
|
|
39377
|
-
var import_child_process10,
|
|
39379
|
+
var import_child_process10, fs44, os15, path49, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
|
|
39378
39380
|
var init_otel_hooks = __esm({
|
|
39379
39381
|
"src/core/otel-hooks.ts"() {
|
|
39380
39382
|
"use strict";
|
|
39381
39383
|
import_child_process10 = require("child_process");
|
|
39382
|
-
|
|
39383
|
-
|
|
39384
|
-
|
|
39384
|
+
fs44 = __toESM(require("fs"));
|
|
39385
|
+
os15 = __toESM(require("os"));
|
|
39386
|
+
path49 = __toESM(require("path"));
|
|
39385
39387
|
init_control_config();
|
|
39386
39388
|
init_telemetry_config();
|
|
39387
39389
|
OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.1.2";
|
|
@@ -40497,15 +40499,15 @@ var require_route = __commonJS({
|
|
|
40497
40499
|
};
|
|
40498
40500
|
}
|
|
40499
40501
|
function wrapConversion(toModel, graph) {
|
|
40500
|
-
const
|
|
40502
|
+
const path64 = [graph[toModel].parent, toModel];
|
|
40501
40503
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
40502
40504
|
let cur = graph[toModel].parent;
|
|
40503
40505
|
while (graph[cur].parent) {
|
|
40504
|
-
|
|
40506
|
+
path64.unshift(graph[cur].parent);
|
|
40505
40507
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
40506
40508
|
cur = graph[cur].parent;
|
|
40507
40509
|
}
|
|
40508
|
-
fn.conversion =
|
|
40510
|
+
fn.conversion = path64;
|
|
40509
40511
|
return fn;
|
|
40510
40512
|
}
|
|
40511
40513
|
module2.exports = function(fromModel) {
|
|
@@ -46435,7 +46437,7 @@ var require_iso2022 = __commonJS({
|
|
|
46435
46437
|
// node_modules/chardet/index.js
|
|
46436
46438
|
var require_chardet = __commonJS({
|
|
46437
46439
|
"node_modules/chardet/index.js"(exports2, module2) {
|
|
46438
|
-
var
|
|
46440
|
+
var fs51 = require("fs");
|
|
46439
46441
|
var utf8 = require_utf8();
|
|
46440
46442
|
var unicode = require_unicode();
|
|
46441
46443
|
var mbcs = require_mbcs();
|
|
@@ -46509,28 +46511,28 @@ var require_chardet = __commonJS({
|
|
|
46509
46511
|
var fd;
|
|
46510
46512
|
var handler = function(err, buffer) {
|
|
46511
46513
|
if (fd) {
|
|
46512
|
-
|
|
46514
|
+
fs51.closeSync(fd);
|
|
46513
46515
|
}
|
|
46514
46516
|
if (err) return cb(err, null);
|
|
46515
46517
|
cb(null, self.detect(buffer, opts));
|
|
46516
46518
|
};
|
|
46517
46519
|
if (opts && opts.sampleSize) {
|
|
46518
|
-
fd =
|
|
46519
|
-
|
|
46520
|
+
fd = fs51.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
|
|
46521
|
+
fs51.read(fd, sample, 0, opts.sampleSize, null, function(err) {
|
|
46520
46522
|
handler(err, sample);
|
|
46521
46523
|
});
|
|
46522
46524
|
return;
|
|
46523
46525
|
}
|
|
46524
|
-
|
|
46526
|
+
fs51.readFile(filepath, handler);
|
|
46525
46527
|
};
|
|
46526
46528
|
module2.exports.detectFileSync = function(filepath, opts) {
|
|
46527
46529
|
if (opts && opts.sampleSize) {
|
|
46528
|
-
var fd =
|
|
46529
|
-
|
|
46530
|
-
|
|
46530
|
+
var fd = fs51.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
|
|
46531
|
+
fs51.readSync(fd, sample2, 0, opts.sampleSize);
|
|
46532
|
+
fs51.closeSync(fd);
|
|
46531
46533
|
return self.detect(sample2, opts);
|
|
46532
46534
|
}
|
|
46533
|
-
return self.detect(
|
|
46535
|
+
return self.detect(fs51.readFileSync(filepath), opts);
|
|
46534
46536
|
};
|
|
46535
46537
|
module2.exports.detectAll = function(buffer, opts) {
|
|
46536
46538
|
if (typeof opts !== "object") {
|
|
@@ -49995,16 +49997,16 @@ var require_os_tmpdir = __commonJS({
|
|
|
49995
49997
|
var isWindows = process.platform === "win32";
|
|
49996
49998
|
var trailingSlashRe = isWindows ? /[^:]\\$/ : /.\/$/;
|
|
49997
49999
|
module2.exports = function() {
|
|
49998
|
-
var
|
|
50000
|
+
var path64;
|
|
49999
50001
|
if (isWindows) {
|
|
50000
|
-
|
|
50002
|
+
path64 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
|
|
50001
50003
|
} else {
|
|
50002
|
-
|
|
50004
|
+
path64 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
|
|
50003
50005
|
}
|
|
50004
|
-
if (trailingSlashRe.test(
|
|
50005
|
-
|
|
50006
|
+
if (trailingSlashRe.test(path64)) {
|
|
50007
|
+
path64 = path64.slice(0, -1);
|
|
50006
50008
|
}
|
|
50007
|
-
return
|
|
50009
|
+
return path64;
|
|
50008
50010
|
};
|
|
50009
50011
|
}
|
|
50010
50012
|
});
|
|
@@ -50012,8 +50014,8 @@ var require_os_tmpdir = __commonJS({
|
|
|
50012
50014
|
// node_modules/tmp/lib/tmp.js
|
|
50013
50015
|
var require_tmp = __commonJS({
|
|
50014
50016
|
"node_modules/tmp/lib/tmp.js"(exports2, module2) {
|
|
50015
|
-
var
|
|
50016
|
-
var
|
|
50017
|
+
var fs51 = require("fs");
|
|
50018
|
+
var path64 = require("path");
|
|
50017
50019
|
var crypto6 = require("crypto");
|
|
50018
50020
|
var osTmpDir = require_os_tmpdir();
|
|
50019
50021
|
var _c2 = process.binding("constants");
|
|
@@ -50055,7 +50057,7 @@ var require_tmp = __commonJS({
|
|
|
50055
50057
|
}
|
|
50056
50058
|
function _generateTmpName(opts) {
|
|
50057
50059
|
if (opts.name) {
|
|
50058
|
-
return
|
|
50060
|
+
return path64.join(opts.dir || tmpDir, opts.name);
|
|
50059
50061
|
}
|
|
50060
50062
|
if (opts.template) {
|
|
50061
50063
|
return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
|
|
@@ -50066,7 +50068,7 @@ var require_tmp = __commonJS({
|
|
|
50066
50068
|
_randomChars(12),
|
|
50067
50069
|
opts.postfix || ""
|
|
50068
50070
|
].join("");
|
|
50069
|
-
return
|
|
50071
|
+
return path64.join(opts.dir || tmpDir, name);
|
|
50070
50072
|
}
|
|
50071
50073
|
function tmpName(options, callback) {
|
|
50072
50074
|
var args = _parseArguments(options, callback), opts = args[0], cb = args[1], tries = opts.name ? 1 : opts.tries || DEFAULT_TRIES;
|
|
@@ -50076,7 +50078,7 @@ var require_tmp = __commonJS({
|
|
|
50076
50078
|
return cb(new Error("Invalid template provided"));
|
|
50077
50079
|
(function _getUniqueName() {
|
|
50078
50080
|
const name = _generateTmpName(opts);
|
|
50079
|
-
|
|
50081
|
+
fs51.stat(name, function(err) {
|
|
50080
50082
|
if (!err) {
|
|
50081
50083
|
if (tries-- > 0) return _getUniqueName();
|
|
50082
50084
|
return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
|
|
@@ -50094,7 +50096,7 @@ var require_tmp = __commonJS({
|
|
|
50094
50096
|
do {
|
|
50095
50097
|
const name = _generateTmpName(opts);
|
|
50096
50098
|
try {
|
|
50097
|
-
|
|
50099
|
+
fs51.statSync(name);
|
|
50098
50100
|
} catch (e2) {
|
|
50099
50101
|
return name;
|
|
50100
50102
|
}
|
|
@@ -50106,13 +50108,13 @@ var require_tmp = __commonJS({
|
|
|
50106
50108
|
opts.postfix = _isUndefined(opts.postfix) ? ".tmp" : opts.postfix;
|
|
50107
50109
|
tmpName(opts, function _tmpNameCreated(err, name) {
|
|
50108
50110
|
if (err) return cb(err);
|
|
50109
|
-
|
|
50111
|
+
fs51.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
|
|
50110
50112
|
if (err2) return cb(err2);
|
|
50111
50113
|
if (opts.discardDescriptor) {
|
|
50112
|
-
return
|
|
50114
|
+
return fs51.close(fd, function _discardCallback(err3) {
|
|
50113
50115
|
if (err3) {
|
|
50114
50116
|
try {
|
|
50115
|
-
|
|
50117
|
+
fs51.unlinkSync(name);
|
|
50116
50118
|
} catch (e2) {
|
|
50117
50119
|
if (!isENOENT(e2)) {
|
|
50118
50120
|
err3 = e2;
|
|
@@ -50135,9 +50137,9 @@ var require_tmp = __commonJS({
|
|
|
50135
50137
|
opts.postfix = opts.postfix || ".tmp";
|
|
50136
50138
|
const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
|
|
50137
50139
|
const name = tmpNameSync(opts);
|
|
50138
|
-
var fd =
|
|
50140
|
+
var fd = fs51.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
|
|
50139
50141
|
if (opts.discardDescriptor) {
|
|
50140
|
-
|
|
50142
|
+
fs51.closeSync(fd);
|
|
50141
50143
|
fd = void 0;
|
|
50142
50144
|
}
|
|
50143
50145
|
return {
|
|
@@ -50149,9 +50151,9 @@ var require_tmp = __commonJS({
|
|
|
50149
50151
|
function _rmdirRecursiveSync(root) {
|
|
50150
50152
|
const dirs = [root];
|
|
50151
50153
|
do {
|
|
50152
|
-
var dir2 = dirs.pop(), deferred = false, files =
|
|
50154
|
+
var dir2 = dirs.pop(), deferred = false, files = fs51.readdirSync(dir2);
|
|
50153
50155
|
for (var i2 = 0, length = files.length; i2 < length; i2++) {
|
|
50154
|
-
var file2 =
|
|
50156
|
+
var file2 = path64.join(dir2, files[i2]), stat = fs51.lstatSync(file2);
|
|
50155
50157
|
if (stat.isDirectory()) {
|
|
50156
50158
|
if (!deferred) {
|
|
50157
50159
|
deferred = true;
|
|
@@ -50159,11 +50161,11 @@ var require_tmp = __commonJS({
|
|
|
50159
50161
|
}
|
|
50160
50162
|
dirs.push(file2);
|
|
50161
50163
|
} else {
|
|
50162
|
-
|
|
50164
|
+
fs51.unlinkSync(file2);
|
|
50163
50165
|
}
|
|
50164
50166
|
}
|
|
50165
50167
|
if (!deferred) {
|
|
50166
|
-
|
|
50168
|
+
fs51.rmdirSync(dir2);
|
|
50167
50169
|
}
|
|
50168
50170
|
} while (dirs.length !== 0);
|
|
50169
50171
|
}
|
|
@@ -50171,7 +50173,7 @@ var require_tmp = __commonJS({
|
|
|
50171
50173
|
var args = _parseArguments(options, callback), opts = args[0], cb = args[1];
|
|
50172
50174
|
tmpName(opts, function _tmpNameCreated(err, name) {
|
|
50173
50175
|
if (err) return cb(err);
|
|
50174
|
-
|
|
50176
|
+
fs51.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
|
|
50175
50177
|
if (err2) return cb(err2);
|
|
50176
50178
|
cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
|
|
50177
50179
|
});
|
|
@@ -50180,7 +50182,7 @@ var require_tmp = __commonJS({
|
|
|
50180
50182
|
function dirSync(options) {
|
|
50181
50183
|
var args = _parseArguments(options), opts = args[0];
|
|
50182
50184
|
const name = tmpNameSync(opts);
|
|
50183
|
-
|
|
50185
|
+
fs51.mkdirSync(name, opts.mode || DIR_MODE);
|
|
50184
50186
|
return {
|
|
50185
50187
|
name,
|
|
50186
50188
|
removeCallback: _prepareTmpDirRemoveCallback(name, opts)
|
|
@@ -50190,7 +50192,7 @@ var require_tmp = __commonJS({
|
|
|
50190
50192
|
const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
|
|
50191
50193
|
try {
|
|
50192
50194
|
if (0 <= fdPath[0]) {
|
|
50193
|
-
|
|
50195
|
+
fs51.closeSync(fdPath[0]);
|
|
50194
50196
|
}
|
|
50195
50197
|
} catch (e2) {
|
|
50196
50198
|
if (!isEBADF(e2) && !isENOENT(e2)) {
|
|
@@ -50198,7 +50200,7 @@ var require_tmp = __commonJS({
|
|
|
50198
50200
|
}
|
|
50199
50201
|
}
|
|
50200
50202
|
try {
|
|
50201
|
-
|
|
50203
|
+
fs51.unlinkSync(fdPath[1]);
|
|
50202
50204
|
} catch (e2) {
|
|
50203
50205
|
if (!isENOENT(e2)) {
|
|
50204
50206
|
throw e2;
|
|
@@ -50211,7 +50213,7 @@ var require_tmp = __commonJS({
|
|
|
50211
50213
|
return removeCallback;
|
|
50212
50214
|
}
|
|
50213
50215
|
function _prepareTmpDirRemoveCallback(name, opts) {
|
|
50214
|
-
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync :
|
|
50216
|
+
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs51.rmdirSync.bind(fs51);
|
|
50215
50217
|
const removeCallback = _prepareRemoveCallback(removeFunction, name);
|
|
50216
50218
|
if (!opts.keep) {
|
|
50217
50219
|
_removeObjects.unshift(removeCallback);
|
|
@@ -63344,8 +63346,8 @@ var require_utils2 = __commonJS({
|
|
|
63344
63346
|
}
|
|
63345
63347
|
return ind;
|
|
63346
63348
|
}
|
|
63347
|
-
function removeDotSegments(
|
|
63348
|
-
let input =
|
|
63349
|
+
function removeDotSegments(path64) {
|
|
63350
|
+
let input = path64;
|
|
63349
63351
|
const output = [];
|
|
63350
63352
|
let nextSlash = -1;
|
|
63351
63353
|
let len = 0;
|
|
@@ -63597,8 +63599,8 @@ var require_schemes = __commonJS({
|
|
|
63597
63599
|
wsComponent.secure = void 0;
|
|
63598
63600
|
}
|
|
63599
63601
|
if (wsComponent.resourceName) {
|
|
63600
|
-
const [
|
|
63601
|
-
wsComponent.path =
|
|
63602
|
+
const [path64, query] = wsComponent.resourceName.split("?");
|
|
63603
|
+
wsComponent.path = path64 && path64 !== "/" ? path64 : void 0;
|
|
63602
63604
|
wsComponent.query = query;
|
|
63603
63605
|
wsComponent.resourceName = void 0;
|
|
63604
63606
|
}
|
|
@@ -66991,12 +66993,12 @@ var require_dist = __commonJS({
|
|
|
66991
66993
|
throw new Error(`Unknown format "${name}"`);
|
|
66992
66994
|
return f2;
|
|
66993
66995
|
};
|
|
66994
|
-
function addFormats(ajv, list,
|
|
66996
|
+
function addFormats(ajv, list, fs51, exportName) {
|
|
66995
66997
|
var _a3;
|
|
66996
66998
|
var _b2;
|
|
66997
66999
|
(_a3 = (_b2 = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
66998
67000
|
for (const f2 of list)
|
|
66999
|
-
ajv.addFormat(f2,
|
|
67001
|
+
ajv.addFormat(f2, fs51[f2]);
|
|
67000
67002
|
}
|
|
67001
67003
|
module2.exports = exports2 = formatsPlugin;
|
|
67002
67004
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -68280,11 +68282,11 @@ var parser = new YargsParser({
|
|
|
68280
68282
|
resolve: import_path2.resolve,
|
|
68281
68283
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
68282
68284
|
// we can exercise all the lines below:
|
|
68283
|
-
require: (
|
|
68285
|
+
require: (path64) => {
|
|
68284
68286
|
if (typeof require !== "undefined") {
|
|
68285
|
-
return require(
|
|
68286
|
-
} else if (
|
|
68287
|
-
return JSON.parse((0, import_fs2.readFileSync)(
|
|
68287
|
+
return require(path64);
|
|
68288
|
+
} else if (path64.match(/\.json$/)) {
|
|
68289
|
+
return JSON.parse((0, import_fs2.readFileSync)(path64, "utf8"));
|
|
68288
68290
|
} else {
|
|
68289
68291
|
throw Error("only .json config files are supported in ESM");
|
|
68290
68292
|
}
|
|
@@ -72203,7 +72205,7 @@ function handleRemove(argv) {
|
|
|
72203
72205
|
}
|
|
72204
72206
|
|
|
72205
72207
|
// src/cli/commands/env.ts
|
|
72206
|
-
var
|
|
72208
|
+
var path53 = __toESM(require("path"));
|
|
72207
72209
|
|
|
72208
72210
|
// src/cli/finish-command.ts
|
|
72209
72211
|
init_sync_context();
|
|
@@ -72213,8 +72215,8 @@ async function finishCommand(code) {
|
|
|
72213
72215
|
}
|
|
72214
72216
|
|
|
72215
72217
|
// src/core/harness.ts
|
|
72216
|
-
var
|
|
72217
|
-
var
|
|
72218
|
+
var fs40 = __toESM(require("fs"));
|
|
72219
|
+
var path44 = __toESM(require("path"));
|
|
72218
72220
|
|
|
72219
72221
|
// src/harness/generator.ts
|
|
72220
72222
|
var fs28 = __toESM(require("fs"));
|
|
@@ -72291,15 +72293,6 @@ function pruneCliProfile(harnessDir) {
|
|
|
72291
72293
|
}
|
|
72292
72294
|
}
|
|
72293
72295
|
}
|
|
72294
|
-
function scaffoldClaudeMd(repoPath, projectName, force) {
|
|
72295
|
-
const templatePath = resolveTemplateFile("CLAUDE.md.template");
|
|
72296
|
-
if (!templatePath) return;
|
|
72297
|
-
const dest = path34.join(repoPath, "CLAUDE.md");
|
|
72298
|
-
if (fs28.existsSync(dest) && !force) return;
|
|
72299
|
-
const displayName = projectName.replace(/_/g, " ");
|
|
72300
|
-
const content = fs28.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
|
|
72301
|
-
fs28.writeFileSync(dest, content);
|
|
72302
|
-
}
|
|
72303
72296
|
function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
72304
72297
|
const harnessDir = path34.join(repoPath, DEFAULT_HAR_DIR);
|
|
72305
72298
|
const projectName = path34.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
@@ -72335,7 +72328,6 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
|
72335
72328
|
profile
|
|
72336
72329
|
);
|
|
72337
72330
|
writeManifest(repoPath, manifest);
|
|
72338
|
-
scaffoldClaudeMd(repoPath, projectName, options.force ?? false);
|
|
72339
72331
|
ensureRootGitignorePatterns(repoPath);
|
|
72340
72332
|
success(`Copied harness boilerplate to .har/ (profile: ${profile})`);
|
|
72341
72333
|
info(`Project name: ${projectName}`);
|
|
@@ -72349,8 +72341,8 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
|
|
|
72349
72341
|
}
|
|
72350
72342
|
|
|
72351
72343
|
// src/llm/authoring-agent.ts
|
|
72352
|
-
var
|
|
72353
|
-
var
|
|
72344
|
+
var fs33 = __toESM(require("fs"));
|
|
72345
|
+
var path38 = __toESM(require("path"));
|
|
72354
72346
|
|
|
72355
72347
|
// node_modules/@anthropic-ai/sdk/error.mjs
|
|
72356
72348
|
var error_exports = {};
|
|
@@ -72749,13 +72741,13 @@ var MultipartBody = class {
|
|
|
72749
72741
|
// node_modules/@anthropic-ai/sdk/_shims/node-runtime.mjs
|
|
72750
72742
|
var import_web = require("node:stream/web");
|
|
72751
72743
|
var fileFromPathWarned = false;
|
|
72752
|
-
async function fileFromPath3(
|
|
72744
|
+
async function fileFromPath3(path64, ...args) {
|
|
72753
72745
|
const { fileFromPath: _fileFromPath } = await Promise.resolve().then(() => (init_fileFromPath(), fileFromPath_exports));
|
|
72754
72746
|
if (!fileFromPathWarned) {
|
|
72755
|
-
console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(
|
|
72747
|
+
console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path64)}) instead`);
|
|
72756
72748
|
fileFromPathWarned = true;
|
|
72757
72749
|
}
|
|
72758
|
-
return await _fileFromPath(
|
|
72750
|
+
return await _fileFromPath(path64, ...args);
|
|
72759
72751
|
}
|
|
72760
72752
|
var defaultHttpAgent = new import_agentkeepalive.default({ keepAlive: true, timeout: 5 * 60 * 1e3 });
|
|
72761
72753
|
var defaultHttpsAgent = new import_agentkeepalive.default.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1e3 });
|
|
@@ -73352,29 +73344,29 @@ var APIClient = class {
|
|
|
73352
73344
|
defaultIdempotencyKey() {
|
|
73353
73345
|
return `stainless-node-retry-${uuid4()}`;
|
|
73354
73346
|
}
|
|
73355
|
-
get(
|
|
73356
|
-
return this.methodRequest("get",
|
|
73347
|
+
get(path64, opts) {
|
|
73348
|
+
return this.methodRequest("get", path64, opts);
|
|
73357
73349
|
}
|
|
73358
|
-
post(
|
|
73359
|
-
return this.methodRequest("post",
|
|
73350
|
+
post(path64, opts) {
|
|
73351
|
+
return this.methodRequest("post", path64, opts);
|
|
73360
73352
|
}
|
|
73361
|
-
patch(
|
|
73362
|
-
return this.methodRequest("patch",
|
|
73353
|
+
patch(path64, opts) {
|
|
73354
|
+
return this.methodRequest("patch", path64, opts);
|
|
73363
73355
|
}
|
|
73364
|
-
put(
|
|
73365
|
-
return this.methodRequest("put",
|
|
73356
|
+
put(path64, opts) {
|
|
73357
|
+
return this.methodRequest("put", path64, opts);
|
|
73366
73358
|
}
|
|
73367
|
-
delete(
|
|
73368
|
-
return this.methodRequest("delete",
|
|
73359
|
+
delete(path64, opts) {
|
|
73360
|
+
return this.methodRequest("delete", path64, opts);
|
|
73369
73361
|
}
|
|
73370
|
-
methodRequest(method,
|
|
73362
|
+
methodRequest(method, path64, opts) {
|
|
73371
73363
|
return this.request(Promise.resolve(opts).then(async (opts2) => {
|
|
73372
73364
|
const body = opts2 && isBlobLike(opts2?.body) ? new DataView(await opts2.body.arrayBuffer()) : opts2?.body instanceof DataView ? opts2.body : opts2?.body instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2?.body) ? new DataView(opts2.body.buffer) : opts2?.body;
|
|
73373
|
-
return { method, path:
|
|
73365
|
+
return { method, path: path64, ...opts2, body };
|
|
73374
73366
|
}));
|
|
73375
73367
|
}
|
|
73376
|
-
getAPIList(
|
|
73377
|
-
return this.requestAPIList(Page, { method: "get", path:
|
|
73368
|
+
getAPIList(path64, Page, opts) {
|
|
73369
|
+
return this.requestAPIList(Page, { method: "get", path: path64, ...opts });
|
|
73378
73370
|
}
|
|
73379
73371
|
calculateContentLength(body) {
|
|
73380
73372
|
if (typeof body === "string") {
|
|
@@ -73392,10 +73384,10 @@ var APIClient = class {
|
|
|
73392
73384
|
return null;
|
|
73393
73385
|
}
|
|
73394
73386
|
buildRequest(options) {
|
|
73395
|
-
const { method, path:
|
|
73387
|
+
const { method, path: path64, query, headers = {} } = options;
|
|
73396
73388
|
const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === "string" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;
|
|
73397
73389
|
const contentLength = this.calculateContentLength(body);
|
|
73398
|
-
const url = this.buildURL(
|
|
73390
|
+
const url = this.buildURL(path64, query);
|
|
73399
73391
|
if ("timeout" in options)
|
|
73400
73392
|
validatePositiveInteger("timeout", options.timeout);
|
|
73401
73393
|
const timeout = options.timeout ?? this.timeout;
|
|
@@ -73504,8 +73496,8 @@ var APIClient = class {
|
|
|
73504
73496
|
const request = this.makeRequest(options, null);
|
|
73505
73497
|
return new PagePromise(this, request, Page);
|
|
73506
73498
|
}
|
|
73507
|
-
buildURL(
|
|
73508
|
-
const url = isAbsoluteURL(
|
|
73499
|
+
buildURL(path64, query) {
|
|
73500
|
+
const url = isAbsoluteURL(path64) ? new URL(path64) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path64.startsWith("/") ? path64.slice(1) : path64));
|
|
73509
73501
|
const defaultQuery = this.defaultQuery();
|
|
73510
73502
|
if (!isEmptyObj(defaultQuery)) {
|
|
73511
73503
|
query = { ...defaultQuery, ...query };
|
|
@@ -75328,64 +75320,368 @@ var { AnthropicError: AnthropicError2, APIError: APIError2, APIConnectionError:
|
|
|
75328
75320
|
var sdk_default = Anthropic;
|
|
75329
75321
|
|
|
75330
75322
|
// src/llm/tools.ts
|
|
75323
|
+
var fs32 = __toESM(require("fs"));
|
|
75324
|
+
var path37 = __toESM(require("path"));
|
|
75325
|
+
var readline4 = __toESM(require("readline"));
|
|
75326
|
+
init_file_ops();
|
|
75327
|
+
init_logging();
|
|
75328
|
+
|
|
75329
|
+
// src/harness/agent-md.ts
|
|
75331
75330
|
var fs31 = __toESM(require("fs"));
|
|
75332
75331
|
var path36 = __toESM(require("path"));
|
|
75333
75332
|
var readline3 = __toESM(require("readline"));
|
|
75334
75333
|
init_file_ops();
|
|
75335
75334
|
init_logging();
|
|
75335
|
+
init_manifest();
|
|
75336
75336
|
|
|
75337
|
-
// src/harness/
|
|
75337
|
+
// src/harness/instruction-files.ts
|
|
75338
75338
|
var fs30 = __toESM(require("fs"));
|
|
75339
|
+
var os13 = __toESM(require("os"));
|
|
75339
75340
|
var path35 = __toESM(require("path"));
|
|
75340
75341
|
var readline2 = __toESM(require("readline"));
|
|
75341
75342
|
init_file_ops();
|
|
75342
75343
|
init_logging();
|
|
75343
|
-
|
|
75344
|
+
var AGENTS_MD = "AGENTS.md";
|
|
75345
|
+
var LEGACY_AGENT_MD = "AGENT.md";
|
|
75346
|
+
var CLAUDE_MD = "CLAUDE.md";
|
|
75347
|
+
var HAR_SECTION_START = "<!-- har:agent-environment:start -->";
|
|
75348
|
+
var HAR_SECTION_END = "<!-- har:agent-environment:end -->";
|
|
75349
|
+
var CLAUDE_HAR_SECTION_START = "<!-- har:claude-pointer:start -->";
|
|
75350
|
+
var CLAUDE_HAR_SECTION_END = "<!-- har:claude-pointer:end -->";
|
|
75351
|
+
function escapeRegExp(value) {
|
|
75352
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
75353
|
+
}
|
|
75354
|
+
function detectInstructionFiles(repoPath) {
|
|
75355
|
+
return {
|
|
75356
|
+
agentsMd: fs30.existsSync(path35.join(repoPath, AGENTS_MD)),
|
|
75357
|
+
agentMd: fs30.existsSync(path35.join(repoPath, LEGACY_AGENT_MD)),
|
|
75358
|
+
claudeMd: fs30.existsSync(path35.join(repoPath, CLAUDE_MD)),
|
|
75359
|
+
cursorDir: fs30.existsSync(path35.join(repoPath, ".cursor")),
|
|
75360
|
+
claudeDir: fs30.existsSync(path35.join(repoPath, ".claude")),
|
|
75361
|
+
codexHome: fs30.existsSync(path35.join(os13.homedir(), ".codex"))
|
|
75362
|
+
};
|
|
75363
|
+
}
|
|
75364
|
+
function formatDetectionReport(detection) {
|
|
75365
|
+
const lines2 = ["Detected:"];
|
|
75366
|
+
lines2.push(` - ${AGENTS_MD} (${detection.agentsMd ? "exists" : "missing"})`);
|
|
75367
|
+
if (detection.agentMd) {
|
|
75368
|
+
lines2.push(` - ${LEGACY_AGENT_MD} (legacy \u2014 will migrate into ${AGENTS_MD})`);
|
|
75369
|
+
}
|
|
75370
|
+
lines2.push(` - ${CLAUDE_MD} (${detection.claudeMd ? "exists" : "missing"})`);
|
|
75371
|
+
lines2.push(` - .cursor/ (${detection.cursorDir ? "exists" : "missing"})`);
|
|
75372
|
+
lines2.push(` - .claude/ (${detection.claudeDir ? "exists" : "missing"})`);
|
|
75373
|
+
lines2.push(` - ~/.codex (${detection.codexHome ? "exists" : "missing"})`);
|
|
75374
|
+
return lines2.join("\n");
|
|
75375
|
+
}
|
|
75376
|
+
function buildInstallPlan(detection, targets, options = {}) {
|
|
75377
|
+
const writeAgentsMd = options.writeAgentsMd !== false;
|
|
75378
|
+
const skillsEnabled = options.skillsEnabled !== false;
|
|
75379
|
+
const cursorExplicit = options.cursorRule;
|
|
75380
|
+
const wantsCursor = cursorExplicit === true || cursorExplicit !== false && (targets.includes("cursor") || detection.cursorDir);
|
|
75381
|
+
return {
|
|
75382
|
+
agentsMd: writeAgentsMd,
|
|
75383
|
+
migrateLegacyAgentMd: writeAgentsMd && detection.agentMd,
|
|
75384
|
+
claudeMd: skillsEnabled && targets.includes("claude"),
|
|
75385
|
+
cursorRule: wantsCursor,
|
|
75386
|
+
skills: skillsEnabled ? targets : []
|
|
75387
|
+
};
|
|
75388
|
+
}
|
|
75389
|
+
function formatInstallPlan(plan, detection) {
|
|
75390
|
+
const mark = (on) => on ? "[x]" : "[ ]";
|
|
75391
|
+
const lines2 = ["After you confirm, HAR will:"];
|
|
75392
|
+
const agentsAction = detection.agentsMd ? `Update ${AGENTS_MD} \u2014 refresh HAR / agent environment section` : `Create ${AGENTS_MD} \u2014 shared HAR workflow (Codex + cross-tool)`;
|
|
75393
|
+
lines2.push(` ${mark(plan.agentsMd)} ${agentsAction}`);
|
|
75394
|
+
if (plan.migrateLegacyAgentMd) {
|
|
75395
|
+
lines2.push(` ${mark(true)} Migrate ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD}, then remove legacy file`);
|
|
75396
|
+
}
|
|
75397
|
+
lines2.push(
|
|
75398
|
+
` ${mark(plan.claudeMd)} Claude \u2014 ensure ${CLAUDE_MD} points at ${AGENTS_MD}; install .claude/skills if confirmed`
|
|
75399
|
+
);
|
|
75400
|
+
lines2.push(
|
|
75401
|
+
` ${mark(plan.cursorRule)} Cursor \u2014 install/refresh .cursor/rules/har-workflow.mdc + commands if confirmed`
|
|
75402
|
+
);
|
|
75403
|
+
lines2.push(
|
|
75404
|
+
` ${mark(plan.skills.includes("codex"))} Codex \u2014 global ~/.codex/prompts (skills); project contract is ${AGENTS_MD}`
|
|
75405
|
+
);
|
|
75406
|
+
return lines2.join("\n");
|
|
75407
|
+
}
|
|
75408
|
+
function loadHarAgentsSectionFromTemplate() {
|
|
75409
|
+
const templatePath = resolveTemplateFile("AGENTS.md.template");
|
|
75410
|
+
if (!templatePath) {
|
|
75411
|
+
throw new Error("AGENTS.md.template not found. Run npm run build.");
|
|
75412
|
+
}
|
|
75413
|
+
const content = fs30.readFileSync(templatePath, "utf8");
|
|
75414
|
+
const start = content.indexOf(HAR_SECTION_START);
|
|
75415
|
+
const end = content.indexOf(HAR_SECTION_END);
|
|
75416
|
+
if (start === -1 || end === -1 || end < start) {
|
|
75417
|
+
throw new Error("AGENTS.md.template is missing har:agent-environment markers.");
|
|
75418
|
+
}
|
|
75419
|
+
return content.slice(start, end + HAR_SECTION_END.length);
|
|
75420
|
+
}
|
|
75421
|
+
function loadAgentsMdTemplate() {
|
|
75422
|
+
const templatePath = resolveTemplateFile("AGENTS.md.template");
|
|
75423
|
+
if (!templatePath) {
|
|
75424
|
+
throw new Error("AGENTS.md.template not found. Run npm run build.");
|
|
75425
|
+
}
|
|
75426
|
+
return fs30.readFileSync(templatePath, "utf8");
|
|
75427
|
+
}
|
|
75428
|
+
function upsertMarkedBlock(content, block, startMarker, endMarker) {
|
|
75429
|
+
if (content.includes(startMarker)) {
|
|
75430
|
+
const pattern = new RegExp(
|
|
75431
|
+
`${escapeRegExp(startMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`
|
|
75432
|
+
);
|
|
75433
|
+
return { content: content.replace(pattern, block), action: "updated" };
|
|
75434
|
+
}
|
|
75435
|
+
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
75436
|
+
return { content: `${content}${suffix}
|
|
75437
|
+
${block}
|
|
75438
|
+
`, action: "appended" };
|
|
75439
|
+
}
|
|
75440
|
+
function upsertAgentsMdHarSection(repoPath) {
|
|
75441
|
+
const dest = path35.join(repoPath, AGENTS_MD);
|
|
75442
|
+
const section = loadHarAgentsSectionFromTemplate();
|
|
75443
|
+
if (!fs30.existsSync(dest)) {
|
|
75444
|
+
writeFileSafe(dest, loadAgentsMdTemplate());
|
|
75445
|
+
return "created";
|
|
75446
|
+
}
|
|
75447
|
+
const existing = fs30.readFileSync(dest, "utf8");
|
|
75448
|
+
const { content, action } = upsertMarkedBlock(
|
|
75449
|
+
existing,
|
|
75450
|
+
section,
|
|
75451
|
+
HAR_SECTION_START,
|
|
75452
|
+
HAR_SECTION_END
|
|
75453
|
+
);
|
|
75454
|
+
writeFileSafe(dest, content);
|
|
75455
|
+
return action;
|
|
75456
|
+
}
|
|
75457
|
+
function migrateLegacyAgentMd(repoPath) {
|
|
75458
|
+
const legacyPath = path35.join(repoPath, LEGACY_AGENT_MD);
|
|
75459
|
+
const agentsPath = path35.join(repoPath, AGENTS_MD);
|
|
75460
|
+
if (!fs30.existsSync(legacyPath)) return false;
|
|
75461
|
+
const legacy = fs30.readFileSync(legacyPath, "utf8");
|
|
75462
|
+
if (!fs30.existsSync(agentsPath)) {
|
|
75463
|
+
writeFileSafe(agentsPath, legacy);
|
|
75464
|
+
upsertAgentsMdHarSection(repoPath);
|
|
75465
|
+
} else {
|
|
75466
|
+
upsertAgentsMdHarSection(repoPath);
|
|
75467
|
+
}
|
|
75468
|
+
fs30.unlinkSync(legacyPath);
|
|
75469
|
+
info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
|
|
75470
|
+
return true;
|
|
75471
|
+
}
|
|
75472
|
+
function loadClaudeMdTemplate(projectName) {
|
|
75473
|
+
const templatePath = resolveTemplateFile("CLAUDE.md.template");
|
|
75474
|
+
if (!templatePath) {
|
|
75475
|
+
throw new Error("CLAUDE.md.template not found. Run npm run build.");
|
|
75476
|
+
}
|
|
75477
|
+
const displayName = projectName.replace(/_/g, " ");
|
|
75478
|
+
return fs30.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
|
|
75479
|
+
}
|
|
75480
|
+
function isThinClaudePointer(content) {
|
|
75481
|
+
const trimmed = content.trim();
|
|
75482
|
+
if (trimmed.length > 600) return false;
|
|
75483
|
+
return /AGENTS\.md|AGENT\.md/.test(trimmed) && (trimmed.includes(".har/README.md") || trimmed.includes("har-workflow"));
|
|
75484
|
+
}
|
|
75485
|
+
var CLAUDE_POINTER_BLOCK = `${CLAUDE_HAR_SECTION_START}
|
|
75486
|
+
## HAR
|
|
75487
|
+
|
|
75488
|
+
This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
|
|
75489
|
+
[\`.har/README.md\`](./.har/README.md) before making changes.
|
|
75490
|
+
${CLAUDE_HAR_SECTION_END}`;
|
|
75491
|
+
function ensureClaudeMdPointer(repoPath, options = {}) {
|
|
75492
|
+
const dest = path35.join(repoPath, CLAUDE_MD);
|
|
75493
|
+
const projectName = path35.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
75494
|
+
const thin = loadClaudeMdTemplate(projectName);
|
|
75495
|
+
if (!fs30.existsSync(dest)) {
|
|
75496
|
+
writeFileSafe(dest, thin);
|
|
75497
|
+
return "created";
|
|
75498
|
+
}
|
|
75499
|
+
const existing = fs30.readFileSync(dest, "utf8");
|
|
75500
|
+
if (isThinClaudePointer(existing) || options.force) {
|
|
75501
|
+
writeFileSafe(dest, thin);
|
|
75502
|
+
return "updated";
|
|
75503
|
+
}
|
|
75504
|
+
if (existing.includes(CLAUDE_HAR_SECTION_START) || /\[AGENTS\.md\]/.test(existing)) {
|
|
75505
|
+
if (existing.includes(CLAUDE_HAR_SECTION_START)) {
|
|
75506
|
+
const { content: content2, action: action2 } = upsertMarkedBlock(
|
|
75507
|
+
existing,
|
|
75508
|
+
CLAUDE_POINTER_BLOCK,
|
|
75509
|
+
CLAUDE_HAR_SECTION_START,
|
|
75510
|
+
CLAUDE_HAR_SECTION_END
|
|
75511
|
+
);
|
|
75512
|
+
writeFileSafe(dest, content2);
|
|
75513
|
+
return action2;
|
|
75514
|
+
}
|
|
75515
|
+
return "skipped";
|
|
75516
|
+
}
|
|
75517
|
+
const { content, action } = upsertMarkedBlock(
|
|
75518
|
+
existing,
|
|
75519
|
+
CLAUDE_POINTER_BLOCK,
|
|
75520
|
+
CLAUDE_HAR_SECTION_START,
|
|
75521
|
+
CLAUDE_HAR_SECTION_END
|
|
75522
|
+
);
|
|
75523
|
+
writeFileSafe(dest, content);
|
|
75524
|
+
return action;
|
|
75525
|
+
}
|
|
75526
|
+
async function askYesNo2(question, defaultYes = true) {
|
|
75527
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
75528
|
+
return new Promise((resolve47) => {
|
|
75529
|
+
process.stderr.write(`${question} `);
|
|
75530
|
+
rl.once("line", (answer) => {
|
|
75531
|
+
rl.close();
|
|
75532
|
+
const trimmed = answer.trim();
|
|
75533
|
+
if (trimmed === "") {
|
|
75534
|
+
resolve47(defaultYes);
|
|
75535
|
+
return;
|
|
75536
|
+
}
|
|
75537
|
+
resolve47(/^y(es)?$/i.test(trimmed));
|
|
75538
|
+
});
|
|
75539
|
+
});
|
|
75540
|
+
}
|
|
75541
|
+
async function handleInstructionFiles(options) {
|
|
75542
|
+
const { repoPath, mode } = options;
|
|
75543
|
+
const writeAgentsMd = options.writeAgentsMd !== false;
|
|
75544
|
+
const skillsEnabled = options.enabled !== false;
|
|
75545
|
+
const detection = detectInstructionFiles(repoPath);
|
|
75546
|
+
let targets;
|
|
75547
|
+
if (!skillsEnabled) {
|
|
75548
|
+
targets = [];
|
|
75549
|
+
} else if (typeof options.agents === "string") {
|
|
75550
|
+
targets = parseAgentTargets(options.agents);
|
|
75551
|
+
} else {
|
|
75552
|
+
targets = detectAgentTargets(repoPath);
|
|
75553
|
+
}
|
|
75554
|
+
if (skillsEnabled && targets.length === 0 && mode === "init" && typeof options.agents !== "string" && !options.autoYes) {
|
|
75555
|
+
targets = [...AGENT_SKILL_TARGETS];
|
|
75556
|
+
}
|
|
75557
|
+
let plan = buildInstallPlan(detection, targets, {
|
|
75558
|
+
writeAgentsMd,
|
|
75559
|
+
cursorRule: options.cursorRule,
|
|
75560
|
+
skillsEnabled
|
|
75561
|
+
});
|
|
75562
|
+
divider();
|
|
75563
|
+
process.stderr.write(`${formatDetectionReport(detection)}
|
|
75564
|
+
|
|
75565
|
+
`);
|
|
75566
|
+
process.stderr.write(`${formatInstallPlan(plan, detection)}
|
|
75567
|
+
`);
|
|
75568
|
+
divider();
|
|
75569
|
+
const shouldPrompt = !options.autoYes && skillsEnabled && typeof options.agents !== "string" && !(mode === "maintain" && targets.length > 0 && !detection.agentMd);
|
|
75570
|
+
if (shouldPrompt && targets.length > 0) {
|
|
75571
|
+
const accepted = await askYesNo2(
|
|
75572
|
+
`Install HAR agent instructions for: ${targets.join(", ")}? [Y/n]`
|
|
75573
|
+
);
|
|
75574
|
+
if (!accepted) {
|
|
75575
|
+
info("Skipped agent instruction adapters (AGENTS.md will still be updated)");
|
|
75576
|
+
targets = [];
|
|
75577
|
+
plan = buildInstallPlan(detection, targets, {
|
|
75578
|
+
writeAgentsMd,
|
|
75579
|
+
cursorRule: options.cursorRule === true ? true : false,
|
|
75580
|
+
skillsEnabled: false
|
|
75581
|
+
});
|
|
75582
|
+
}
|
|
75583
|
+
}
|
|
75584
|
+
let migratedLegacy = false;
|
|
75585
|
+
let agentsMdAction = null;
|
|
75586
|
+
let claudeMdAction = null;
|
|
75587
|
+
if (writeAgentsMd) {
|
|
75588
|
+
if (detection.agentMd) {
|
|
75589
|
+
migratedLegacy = migrateLegacyAgentMd(repoPath);
|
|
75590
|
+
}
|
|
75591
|
+
agentsMdAction = upsertAgentsMdHarSection(repoPath);
|
|
75592
|
+
if (agentsMdAction === "created") {
|
|
75593
|
+
success(`Wrote ${AGENTS_MD}`);
|
|
75594
|
+
} else if (agentsMdAction === "updated" || agentsMdAction === "appended") {
|
|
75595
|
+
info(
|
|
75596
|
+
`${agentsMdAction === "updated" ? "Refreshed" : "Appended"} HAR section in ${AGENTS_MD}`
|
|
75597
|
+
);
|
|
75598
|
+
}
|
|
75599
|
+
} else {
|
|
75600
|
+
agentsMdAction = "skipped";
|
|
75601
|
+
}
|
|
75602
|
+
if (plan.claudeMd) {
|
|
75603
|
+
claudeMdAction = ensureClaudeMdPointer(repoPath);
|
|
75604
|
+
if (claudeMdAction === "created") {
|
|
75605
|
+
success(`Wrote ${CLAUDE_MD} (pointer \u2192 ${AGENTS_MD})`);
|
|
75606
|
+
} else if (claudeMdAction === "updated" || claudeMdAction === "appended") {
|
|
75607
|
+
info(
|
|
75608
|
+
`${claudeMdAction === "updated" ? "Updated" : "Appended"} ${CLAUDE_MD} pointer \u2192 ${AGENTS_MD}`
|
|
75609
|
+
);
|
|
75610
|
+
}
|
|
75611
|
+
} else {
|
|
75612
|
+
claudeMdAction = "skipped";
|
|
75613
|
+
}
|
|
75614
|
+
return {
|
|
75615
|
+
detection,
|
|
75616
|
+
plan,
|
|
75617
|
+
targets,
|
|
75618
|
+
agentsMdAction,
|
|
75619
|
+
migratedLegacy,
|
|
75620
|
+
claudeMdAction
|
|
75621
|
+
};
|
|
75622
|
+
}
|
|
75623
|
+
|
|
75624
|
+
// src/harness/agent-md.ts
|
|
75625
|
+
var AGENTS_MD_PROPOSAL = "AGENTS.md.proposed";
|
|
75626
|
+
var AGENTS_MD_PROPOSAL_META = "AGENTS.md.proposed.meta.json";
|
|
75344
75627
|
var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
|
|
75345
75628
|
var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
|
|
75346
75629
|
function writeAgentMdProposal(repoPath, content, rationale) {
|
|
75347
75630
|
const harnessDir = getHarnessDir(repoPath);
|
|
75348
|
-
writeFileSafe(
|
|
75631
|
+
writeFileSafe(path36.join(harnessDir, AGENTS_MD_PROPOSAL), content);
|
|
75349
75632
|
writeFileSafe(
|
|
75350
|
-
|
|
75633
|
+
path36.join(harnessDir, AGENTS_MD_PROPOSAL_META),
|
|
75351
75634
|
JSON.stringify({ rationale, createdAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n"
|
|
75352
75635
|
);
|
|
75636
|
+
for (const file of [AGENT_MD_PROPOSAL, AGENT_MD_PROPOSAL_META]) {
|
|
75637
|
+
const p2 = path36.join(harnessDir, file);
|
|
75638
|
+
if (fs31.existsSync(p2)) fs31.unlinkSync(p2);
|
|
75639
|
+
}
|
|
75353
75640
|
}
|
|
75354
75641
|
function readAgentMdProposal(repoPath) {
|
|
75355
75642
|
const harnessDir = getHarnessDir(repoPath);
|
|
75356
|
-
const proposalPath =
|
|
75357
|
-
const metaPath =
|
|
75358
|
-
|
|
75359
|
-
const
|
|
75643
|
+
const proposalPath = path36.join(harnessDir, AGENTS_MD_PROPOSAL);
|
|
75644
|
+
const metaPath = path36.join(harnessDir, AGENTS_MD_PROPOSAL_META);
|
|
75645
|
+
const legacyProposalPath = path36.join(harnessDir, AGENT_MD_PROPOSAL);
|
|
75646
|
+
const legacyMetaPath = path36.join(harnessDir, AGENT_MD_PROPOSAL_META);
|
|
75647
|
+
const resolvedProposal = fs31.existsSync(proposalPath) ? proposalPath : fs31.existsSync(legacyProposalPath) ? legacyProposalPath : null;
|
|
75648
|
+
if (!resolvedProposal) return null;
|
|
75649
|
+
const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
|
|
75650
|
+
const content = fs31.readFileSync(resolvedProposal, "utf8");
|
|
75360
75651
|
let rationale = "";
|
|
75361
|
-
|
|
75652
|
+
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
75653
|
+
if (fs31.existsSync(resolvedMeta)) {
|
|
75362
75654
|
try {
|
|
75363
|
-
|
|
75655
|
+
const meta = JSON.parse(fs31.readFileSync(resolvedMeta, "utf8"));
|
|
75656
|
+
rationale = meta.rationale ?? "";
|
|
75657
|
+
createdAt = meta.createdAt ?? createdAt;
|
|
75364
75658
|
} catch {
|
|
75365
75659
|
rationale = "";
|
|
75366
75660
|
}
|
|
75367
75661
|
}
|
|
75368
|
-
return {
|
|
75369
|
-
content,
|
|
75370
|
-
rationale,
|
|
75371
|
-
createdAt: fs30.existsSync(metaPath) ? JSON.parse(fs30.readFileSync(metaPath, "utf8")).createdAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
75372
|
-
};
|
|
75662
|
+
return { content, rationale, createdAt };
|
|
75373
75663
|
}
|
|
75374
75664
|
function clearAgentMdProposal(repoPath) {
|
|
75375
75665
|
const harnessDir = getHarnessDir(repoPath);
|
|
75376
|
-
for (const file of [
|
|
75377
|
-
|
|
75378
|
-
|
|
75666
|
+
for (const file of [
|
|
75667
|
+
AGENTS_MD_PROPOSAL,
|
|
75668
|
+
AGENTS_MD_PROPOSAL_META,
|
|
75669
|
+
AGENT_MD_PROPOSAL,
|
|
75670
|
+
AGENT_MD_PROPOSAL_META
|
|
75671
|
+
]) {
|
|
75672
|
+
const p2 = path36.join(harnessDir, file);
|
|
75673
|
+
if (fs31.existsSync(p2)) fs31.unlinkSync(p2);
|
|
75379
75674
|
}
|
|
75380
75675
|
}
|
|
75381
75676
|
async function promptApplyAgentMdProposal(repoPath) {
|
|
75382
75677
|
const proposal = readAgentMdProposal(repoPath);
|
|
75383
75678
|
if (!proposal) return false;
|
|
75384
|
-
const
|
|
75385
|
-
const exists =
|
|
75679
|
+
const agentsMdPath = path36.join(repoPath, AGENTS_MD);
|
|
75680
|
+
const exists = fs31.existsSync(agentsMdPath);
|
|
75386
75681
|
process.stderr.write("\n");
|
|
75387
75682
|
process.stderr.write("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
|
|
75388
|
-
process.stderr.write(
|
|
75683
|
+
process.stderr.write(`Proposed ${AGENTS_MD} (repo root)
|
|
75684
|
+
`);
|
|
75389
75685
|
process.stderr.write("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
|
|
75390
75686
|
if (proposal.rationale) {
|
|
75391
75687
|
process.stderr.write(`Why: ${proposal.rationale}
|
|
@@ -75401,29 +75697,29 @@ async function promptApplyAgentMdProposal(repoPath) {
|
|
|
75401
75697
|
process.stderr.write(" ...\n");
|
|
75402
75698
|
}
|
|
75403
75699
|
process.stderr.write("\n");
|
|
75404
|
-
process.stderr.write(`Full proposal: .har/${
|
|
75700
|
+
process.stderr.write(`Full proposal: .har/${AGENTS_MD_PROPOSAL}
|
|
75405
75701
|
`);
|
|
75406
75702
|
if (exists) {
|
|
75407
|
-
warn(
|
|
75408
|
-
const answer = await
|
|
75703
|
+
warn(`${AGENTS_MD} already exists at repo root.`);
|
|
75704
|
+
const answer = await askYesNo3(`Replace ${AGENTS_MD} with this proposal? (y/n)`);
|
|
75409
75705
|
if (!answer) {
|
|
75410
|
-
info(
|
|
75706
|
+
info(`Skipped \u2014 proposal kept at .har/${AGENTS_MD_PROPOSAL}`);
|
|
75411
75707
|
return false;
|
|
75412
75708
|
}
|
|
75413
75709
|
} else {
|
|
75414
|
-
const answer = await
|
|
75710
|
+
const answer = await askYesNo3(`Create ${AGENTS_MD} at repo root? (y/n)`);
|
|
75415
75711
|
if (!answer) {
|
|
75416
|
-
info(
|
|
75712
|
+
info(`Skipped \u2014 proposal kept at .har/${AGENTS_MD_PROPOSAL}`);
|
|
75417
75713
|
return false;
|
|
75418
75714
|
}
|
|
75419
75715
|
}
|
|
75420
|
-
writeFileSafe(
|
|
75716
|
+
writeFileSafe(agentsMdPath, proposal.content);
|
|
75421
75717
|
clearAgentMdProposal(repoPath);
|
|
75422
|
-
info(
|
|
75718
|
+
info(`Wrote ${AGENTS_MD}`);
|
|
75423
75719
|
return true;
|
|
75424
75720
|
}
|
|
75425
|
-
async function
|
|
75426
|
-
const rl =
|
|
75721
|
+
async function askYesNo3(question) {
|
|
75722
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
75427
75723
|
return new Promise((resolve47) => {
|
|
75428
75724
|
process.stderr.write(`${question} `);
|
|
75429
75725
|
rl.once("line", (answer) => {
|
|
@@ -75520,12 +75816,12 @@ function buildAuthoringTools() {
|
|
|
75520
75816
|
}
|
|
75521
75817
|
},
|
|
75522
75818
|
{
|
|
75523
|
-
name: "
|
|
75524
|
-
description: "Propose content for
|
|
75819
|
+
name: "proposeAgentsMd",
|
|
75820
|
+
description: "Propose content for AGENTS.md at the repo root. Does NOT write the file \u2014 the user approves after init/maintain. Include project-specific notes and pointer to .har/.",
|
|
75525
75821
|
input_schema: {
|
|
75526
75822
|
type: "object",
|
|
75527
75823
|
properties: {
|
|
75528
|
-
content: { type: "string", description: "Full proposed
|
|
75824
|
+
content: { type: "string", description: "Full proposed AGENTS.md content" },
|
|
75529
75825
|
rationale: { type: "string", description: "Why these changes (shown to user)" }
|
|
75530
75826
|
},
|
|
75531
75827
|
required: ["content", "rationale"]
|
|
@@ -75570,13 +75866,13 @@ async function handleAuthoringToolCall(toolName, input, repoPath, harnessDir, ca
|
|
|
75570
75866
|
async function executeAuthoringToolCall(toolName, input, repoPath, harnessDir, callbacks) {
|
|
75571
75867
|
switch (toolName) {
|
|
75572
75868
|
case "readRepoFile": {
|
|
75573
|
-
const filePath =
|
|
75869
|
+
const filePath = path37.join(repoPath, input.path);
|
|
75574
75870
|
const content = readFile(filePath, input.maxChars ?? 8e3);
|
|
75575
75871
|
info(`Read repo: ${input.path}`);
|
|
75576
75872
|
return content;
|
|
75577
75873
|
}
|
|
75578
75874
|
case "listRepoDir": {
|
|
75579
|
-
const dirPath =
|
|
75875
|
+
const dirPath = path37.join(repoPath, input.path ?? ".");
|
|
75580
75876
|
const entries = listDir(dirPath, input.maxFiles ?? 60);
|
|
75581
75877
|
info(`List repo: ${input.path} \u2192 ${entries.length} entries`);
|
|
75582
75878
|
return entries.length > 0 ? entries.join("\n") : "(empty directory)";
|
|
@@ -75601,17 +75897,17 @@ async function executeAuthoringToolCall(toolName, input, repoPath, harnessDir, c
|
|
|
75601
75897
|
const filePath = resolveSafePath(harnessDir, relPath);
|
|
75602
75898
|
writeFileSafe(filePath, input.content);
|
|
75603
75899
|
if (relPath.endsWith(".sh")) {
|
|
75604
|
-
|
|
75900
|
+
fs32.chmodSync(filePath, 493);
|
|
75605
75901
|
}
|
|
75606
75902
|
info(`Wrote harness: ${relPath}`);
|
|
75607
75903
|
return `Written ${relPath} (${input.content.length} bytes)`;
|
|
75608
75904
|
}
|
|
75609
75905
|
case "editHarnessFile": {
|
|
75610
75906
|
const filePath = resolveSafePath(harnessDir, input.path);
|
|
75611
|
-
if (!
|
|
75907
|
+
if (!fs32.existsSync(filePath)) {
|
|
75612
75908
|
return `Error: file not found: ${input.path}`;
|
|
75613
75909
|
}
|
|
75614
|
-
const content =
|
|
75910
|
+
const content = fs32.readFileSync(filePath, "utf8");
|
|
75615
75911
|
const oldStr = input.old_string;
|
|
75616
75912
|
const newStr = input.new_string;
|
|
75617
75913
|
const count = content.split(oldStr).length - 1;
|
|
@@ -75628,17 +75924,17 @@ async function executeAuthoringToolCall(toolName, input, repoPath, harnessDir, c
|
|
|
75628
75924
|
}
|
|
75629
75925
|
case "deleteHarnessFile": {
|
|
75630
75926
|
const filePath = resolveSafePath(harnessDir, input.path);
|
|
75631
|
-
if (!
|
|
75927
|
+
if (!fs32.existsSync(filePath)) {
|
|
75632
75928
|
return `File not found (already deleted): ${input.path}`;
|
|
75633
75929
|
}
|
|
75634
|
-
|
|
75930
|
+
fs32.unlinkSync(filePath);
|
|
75635
75931
|
info(`Deleted harness: ${input.path}`);
|
|
75636
75932
|
return `Deleted ${input.path}`;
|
|
75637
75933
|
}
|
|
75638
|
-
case "
|
|
75934
|
+
case "proposeAgentsMd": {
|
|
75639
75935
|
writeAgentMdProposal(repoPath, input.content, input.rationale);
|
|
75640
|
-
info("Proposed
|
|
75641
|
-
return "
|
|
75936
|
+
info("Proposed AGENTS.md (awaiting user approval)");
|
|
75937
|
+
return "AGENTS.md proposal saved to .har/AGENTS.md.proposed \u2014 user will be prompted to apply.";
|
|
75642
75938
|
}
|
|
75643
75939
|
case "ask": {
|
|
75644
75940
|
return askUser(input.question, input.options ?? []);
|
|
@@ -75657,7 +75953,7 @@ async function executeAuthoringToolCall(toolName, input, repoPath, harnessDir, c
|
|
|
75657
75953
|
}
|
|
75658
75954
|
}
|
|
75659
75955
|
async function askUser(question, options) {
|
|
75660
|
-
const rl =
|
|
75956
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
75661
75957
|
return new Promise((resolve47) => {
|
|
75662
75958
|
process.stderr.write("\n");
|
|
75663
75959
|
process.stderr.write(`\u2753 ${question}
|
|
@@ -75683,30 +75979,30 @@ async function authorHarness(repoPath, apiKey, options = {}) {
|
|
|
75683
75979
|
const harnessDir = getHarnessDir(repoPath);
|
|
75684
75980
|
const mode = options.mode ?? "init";
|
|
75685
75981
|
const systemPromptPath = resolvePromptPath("system-authoring.md");
|
|
75686
|
-
const agentMdTemplatePath = resolveTemplateFile("
|
|
75687
|
-
let systemPrompt =
|
|
75982
|
+
const agentMdTemplatePath = resolveTemplateFile("AGENTS.md.template");
|
|
75983
|
+
let systemPrompt = fs33.existsSync(systemPromptPath) ? fs33.readFileSync(systemPromptPath, "utf8") : "Adapt the .har/ boilerplate to match the repository. Edit files directly. Call finishAuthoring when done.";
|
|
75688
75984
|
if (agentMdTemplatePath) {
|
|
75689
75985
|
systemPrompt += `
|
|
75690
75986
|
|
|
75691
|
-
##
|
|
75987
|
+
## AGENTS.md template (starting point for proposeAgentsMd)
|
|
75692
75988
|
|
|
75693
|
-
${
|
|
75989
|
+
${fs33.readFileSync(agentMdTemplatePath, "utf8")}`;
|
|
75694
75990
|
}
|
|
75695
75991
|
const tools = buildAuthoringTools();
|
|
75696
75992
|
const messages = [];
|
|
75697
75993
|
let rootListing;
|
|
75698
75994
|
try {
|
|
75699
|
-
rootListing =
|
|
75995
|
+
rootListing = fs33.readdirSync(repoPath).slice(0, 50).join("\n");
|
|
75700
75996
|
} catch {
|
|
75701
75997
|
throw new Error(`Cannot read repo at path: ${repoPath}`);
|
|
75702
75998
|
}
|
|
75703
75999
|
let harnessListing;
|
|
75704
76000
|
try {
|
|
75705
|
-
harnessListing =
|
|
76001
|
+
harnessListing = fs33.readdirSync(harnessDir).join("\n");
|
|
75706
76002
|
} catch {
|
|
75707
76003
|
throw new Error(`Cannot read harness dir at: ${harnessDir}`);
|
|
75708
76004
|
}
|
|
75709
|
-
const existingAgentMd =
|
|
76005
|
+
const existingAgentMd = fs33.existsSync(path38.join(repoPath, "AGENTS.md")) ? "AGENTS.md exists at repo root \u2014 read it before proposing changes via proposeAgentsMd." : "No AGENTS.md at repo root yet \u2014 propose one via proposeAgentsMd.";
|
|
75710
76006
|
const modeInstructions = mode === "maintain" ? `This is a MAINTENANCE run. .har/ already exists and may have been edited by humans.
|
|
75711
76007
|
Update it to reflect current repo changes. Prefer editHarnessFile over writeHarnessFile.
|
|
75712
76008
|
Keep README.md accurate \u2014 it is the index of the harness. ${existingAgentMd}` : `This is an INITIAL setup. A fresh boilerplate has been copied to .har/.
|
|
@@ -75786,8 +76082,8 @@ Try running with --verbose to see what the agent is doing.`
|
|
|
75786
76082
|
}
|
|
75787
76083
|
|
|
75788
76084
|
// src/harness/validator.ts
|
|
75789
|
-
var
|
|
75790
|
-
var
|
|
76085
|
+
var fs34 = __toESM(require("fs"));
|
|
76086
|
+
var path39 = __toESM(require("path"));
|
|
75791
76087
|
init_shell();
|
|
75792
76088
|
init_manifest();
|
|
75793
76089
|
init_stages();
|
|
@@ -75842,22 +76138,22 @@ var SHELL_SCRIPTS = [
|
|
|
75842
76138
|
function validateHarness(repoPath) {
|
|
75843
76139
|
const harnessDir = getHarnessDir(repoPath);
|
|
75844
76140
|
const issues = [];
|
|
75845
|
-
if (!
|
|
76141
|
+
if (!fs34.existsSync(harnessDir)) {
|
|
75846
76142
|
return {
|
|
75847
76143
|
pass: false,
|
|
75848
76144
|
issues: [{ file: ".har", message: "Harness directory not found", severity: "error" }]
|
|
75849
76145
|
};
|
|
75850
76146
|
}
|
|
75851
76147
|
for (const file of getRequiredFiles(repoPath)) {
|
|
75852
|
-
const filePath =
|
|
75853
|
-
if (!
|
|
76148
|
+
const filePath = path39.join(harnessDir, file);
|
|
76149
|
+
if (!fs34.existsSync(filePath)) {
|
|
75854
76150
|
issues.push({ file, message: "Required file missing", severity: "error" });
|
|
75855
76151
|
}
|
|
75856
76152
|
}
|
|
75857
76153
|
for (const script of SHELL_SCRIPTS) {
|
|
75858
|
-
const scriptPath =
|
|
75859
|
-
if (!
|
|
75860
|
-
const stat =
|
|
76154
|
+
const scriptPath = path39.join(harnessDir, script);
|
|
76155
|
+
if (!fs34.existsSync(scriptPath)) continue;
|
|
76156
|
+
const stat = fs34.statSync(scriptPath);
|
|
75861
76157
|
if (!(stat.mode & 73)) {
|
|
75862
76158
|
issues.push({ file: script, message: "Script is not executable", severity: "warning" });
|
|
75863
76159
|
}
|
|
@@ -75872,9 +76168,9 @@ function validateHarness(repoPath) {
|
|
|
75872
76168
|
}
|
|
75873
76169
|
const manifest = readManifest(repoPath);
|
|
75874
76170
|
const profile = manifest?.profile ?? "default";
|
|
75875
|
-
const ecosystemPath =
|
|
75876
|
-
if (profile !== "cli" &&
|
|
75877
|
-
const content =
|
|
76171
|
+
const ecosystemPath = path39.join(harnessDir, "ecosystem.agent.template.cjs");
|
|
76172
|
+
if (profile !== "cli" && fs34.existsSync(ecosystemPath)) {
|
|
76173
|
+
const content = fs34.readFileSync(ecosystemPath, "utf8");
|
|
75878
76174
|
if (!content.includes("module.exports")) {
|
|
75879
76175
|
issues.push({
|
|
75880
76176
|
file: "ecosystem.agent.template.cjs",
|
|
@@ -75883,9 +76179,9 @@ function validateHarness(repoPath) {
|
|
|
75883
76179
|
});
|
|
75884
76180
|
}
|
|
75885
76181
|
}
|
|
75886
|
-
const harnessEnvPath =
|
|
75887
|
-
if (
|
|
75888
|
-
const content =
|
|
76182
|
+
const harnessEnvPath = path39.join(harnessDir, "harness.env");
|
|
76183
|
+
if (fs34.existsSync(harnessEnvPath)) {
|
|
76184
|
+
const content = fs34.readFileSync(harnessEnvPath, "utf8");
|
|
75889
76185
|
if (content.includes("TODO: set migrate command")) {
|
|
75890
76186
|
issues.push({ file: "harness.env", message: "Migrate command still has TODO", severity: "warning" });
|
|
75891
76187
|
}
|
|
@@ -75893,17 +76189,17 @@ function validateHarness(repoPath) {
|
|
|
75893
76189
|
issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
|
|
75894
76190
|
}
|
|
75895
76191
|
}
|
|
75896
|
-
const verifyPath =
|
|
75897
|
-
if (
|
|
75898
|
-
const content =
|
|
76192
|
+
const verifyPath = path39.join(harnessDir, "verify.sh");
|
|
76193
|
+
if (fs34.existsSync(verifyPath)) {
|
|
76194
|
+
const content = fs34.readFileSync(verifyPath, "utf8");
|
|
75899
76195
|
if (content.includes("echo 'TODO:")) {
|
|
75900
76196
|
issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
|
|
75901
76197
|
}
|
|
75902
76198
|
}
|
|
75903
|
-
const stagesPath =
|
|
75904
|
-
if (
|
|
76199
|
+
const stagesPath = path39.join(harnessDir, "stages.json");
|
|
76200
|
+
if (fs34.existsSync(stagesPath)) {
|
|
75905
76201
|
try {
|
|
75906
|
-
JSON.parse(
|
|
76202
|
+
JSON.parse(fs34.readFileSync(stagesPath, "utf8"));
|
|
75907
76203
|
const registry2 = readStageRegistry(repoPath);
|
|
75908
76204
|
if (registry2.stages.length === 0) {
|
|
75909
76205
|
issues.push({ file: "stages.json", message: "No harness stages declared", severity: "warning" });
|
|
@@ -75918,9 +76214,9 @@ function validateHarness(repoPath) {
|
|
|
75918
76214
|
} else {
|
|
75919
76215
|
issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
|
|
75920
76216
|
}
|
|
75921
|
-
const readmePath =
|
|
75922
|
-
if (
|
|
75923
|
-
const content =
|
|
76217
|
+
const readmePath = path39.join(harnessDir, "README.md");
|
|
76218
|
+
if (fs34.existsSync(readmePath)) {
|
|
76219
|
+
const content = fs34.readFileSync(readmePath, "utf8");
|
|
75924
76220
|
if (!content.includes(".har")) {
|
|
75925
76221
|
issues.push({ file: "README.md", message: "README should document .har/ paths", severity: "warning" });
|
|
75926
76222
|
}
|
|
@@ -75934,8 +76230,8 @@ function validateHarness(repoPath) {
|
|
|
75934
76230
|
async function smokeTestHarness(repoPath) {
|
|
75935
76231
|
const harnessDir = getHarnessDir(repoPath);
|
|
75936
76232
|
const issues = [];
|
|
75937
|
-
const setupScript =
|
|
75938
|
-
if (
|
|
76233
|
+
const setupScript = path39.join(harnessDir, "setup-infra.sh");
|
|
76234
|
+
if (fs34.existsSync(setupScript)) {
|
|
75939
76235
|
const result = run(`bash "${setupScript}"`, { cwd: repoPath });
|
|
75940
76236
|
if (result.code !== 0) {
|
|
75941
76237
|
issues.push({
|
|
@@ -75950,8 +76246,8 @@ async function smokeTestHarness(repoPath) {
|
|
|
75950
76246
|
}
|
|
75951
76247
|
|
|
75952
76248
|
// src/harness/drift.ts
|
|
75953
|
-
var
|
|
75954
|
-
var
|
|
76249
|
+
var fs35 = __toESM(require("fs"));
|
|
76250
|
+
var path40 = __toESM(require("path"));
|
|
75955
76251
|
init_env();
|
|
75956
76252
|
init_manifest();
|
|
75957
76253
|
init_stages();
|
|
@@ -76022,16 +76318,16 @@ function substituteProjectName(content, projectName) {
|
|
|
76022
76318
|
return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
76023
76319
|
}
|
|
76024
76320
|
function listBoilerplateFiles(boilerplateDir) {
|
|
76025
|
-
if (!
|
|
76026
|
-
return
|
|
76321
|
+
if (!fs35.existsSync(boilerplateDir)) return [];
|
|
76322
|
+
return fs35.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
76027
76323
|
}
|
|
76028
76324
|
function compareHarnessToTemplate(repoPath) {
|
|
76029
|
-
const resolved =
|
|
76325
|
+
const resolved = path40.resolve(repoPath);
|
|
76030
76326
|
const manifest = readManifest(resolved);
|
|
76031
76327
|
const profile = manifest?.profile ?? "default";
|
|
76032
76328
|
const harnessDir = getHarnessDir(resolved);
|
|
76033
|
-
const projectName =
|
|
76034
|
-
const boilerplateDir =
|
|
76329
|
+
const projectName = path40.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
76330
|
+
const boilerplateDir = path40.join(resolveTemplatesDir(), PROFILE_DIRS2[profile]);
|
|
76035
76331
|
const templateFiles = listBoilerplateFiles(boilerplateDir);
|
|
76036
76332
|
const missing = [];
|
|
76037
76333
|
const checksumMismatch = [];
|
|
@@ -76039,17 +76335,17 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
76039
76335
|
const unchanged = [];
|
|
76040
76336
|
for (const file of templateFiles) {
|
|
76041
76337
|
const harnessFile = harnessFileForTemplate(file);
|
|
76042
|
-
const templatePath =
|
|
76043
|
-
const harnessPath =
|
|
76044
|
-
let templateContent =
|
|
76338
|
+
const templatePath = path40.join(boilerplateDir, file);
|
|
76339
|
+
const harnessPath = path40.join(harnessDir, harnessFile);
|
|
76340
|
+
let templateContent = fs35.readFileSync(templatePath, "utf8");
|
|
76045
76341
|
if (file === "harness.env") {
|
|
76046
76342
|
templateContent = substituteProjectName(templateContent, projectName);
|
|
76047
76343
|
}
|
|
76048
|
-
if (!
|
|
76344
|
+
if (!fs35.existsSync(harnessPath)) {
|
|
76049
76345
|
missing.push(harnessFile);
|
|
76050
76346
|
continue;
|
|
76051
76347
|
}
|
|
76052
|
-
const harnessChecksum = computeFileChecksum(
|
|
76348
|
+
const harnessChecksum = computeFileChecksum(fs35.readFileSync(harnessPath, "utf8"));
|
|
76053
76349
|
const templateChecksum = computeFileChecksum(templateContent);
|
|
76054
76350
|
if (harnessChecksum === templateChecksum) {
|
|
76055
76351
|
unchanged.push(harnessFile);
|
|
@@ -76057,10 +76353,10 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
76057
76353
|
checksumMismatch.push(harnessFile);
|
|
76058
76354
|
}
|
|
76059
76355
|
}
|
|
76060
|
-
if (
|
|
76061
|
-
for (const file of
|
|
76062
|
-
const full =
|
|
76063
|
-
if (!
|
|
76356
|
+
if (fs35.existsSync(harnessDir)) {
|
|
76357
|
+
for (const file of fs35.readdirSync(harnessDir)) {
|
|
76358
|
+
const full = path40.join(harnessDir, file);
|
|
76359
|
+
if (!fs35.statSync(full).isFile()) continue;
|
|
76064
76360
|
if (file === "manifest.json" || file.startsWith("ADAPT-PROMPT")) continue;
|
|
76065
76361
|
if (profile === "cli" && CLI_EXPECTED_ABSENT.has(file)) {
|
|
76066
76362
|
extra.push(file);
|
|
@@ -76091,29 +76387,29 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
76091
76387
|
}
|
|
76092
76388
|
|
|
76093
76389
|
// src/harness/maintain-bundle.ts
|
|
76094
|
-
var
|
|
76095
|
-
var
|
|
76096
|
-
var
|
|
76390
|
+
var fs39 = __toESM(require("fs"));
|
|
76391
|
+
var os14 = __toESM(require("os"));
|
|
76392
|
+
var path43 = __toESM(require("path"));
|
|
76097
76393
|
init_file_ops();
|
|
76098
76394
|
init_shell();
|
|
76099
76395
|
init_manifest();
|
|
76100
76396
|
|
|
76101
76397
|
// src/harness/plugin-drift.ts
|
|
76102
|
-
var
|
|
76103
|
-
var
|
|
76398
|
+
var fs38 = __toESM(require("fs"));
|
|
76399
|
+
var path42 = __toESM(require("path"));
|
|
76104
76400
|
init_manifest();
|
|
76105
76401
|
|
|
76106
76402
|
// src/harness/plugins.ts
|
|
76107
|
-
var
|
|
76108
|
-
var
|
|
76403
|
+
var fs37 = __toESM(require("fs"));
|
|
76404
|
+
var path41 = __toESM(require("path"));
|
|
76109
76405
|
init_zod();
|
|
76110
76406
|
init_logging();
|
|
76111
76407
|
|
|
76112
76408
|
// src/harness/parser.ts
|
|
76113
|
-
var
|
|
76409
|
+
var fs36 = __toESM(require("fs"));
|
|
76114
76410
|
init_manifest();
|
|
76115
76411
|
function harnessExists(repoPath) {
|
|
76116
|
-
return
|
|
76412
|
+
return fs36.existsSync(`${repoPath}/.har/setup-infra.sh`);
|
|
76117
76413
|
}
|
|
76118
76414
|
|
|
76119
76415
|
// src/harness/plugins.ts
|
|
@@ -76138,16 +76434,16 @@ var PluginManifestSchema = external_exports.object({
|
|
|
76138
76434
|
docsPath: external_exports.string().min(1)
|
|
76139
76435
|
});
|
|
76140
76436
|
function resolvePluginDir(pluginId) {
|
|
76141
|
-
const dir =
|
|
76142
|
-
if (!
|
|
76437
|
+
const dir = path41.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
76438
|
+
if (!fs37.existsSync(dir)) {
|
|
76143
76439
|
throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
|
|
76144
76440
|
}
|
|
76145
76441
|
return dir;
|
|
76146
76442
|
}
|
|
76147
76443
|
function readPluginManifest(pluginId) {
|
|
76148
|
-
const manifestPath =
|
|
76444
|
+
const manifestPath = path41.join(resolvePluginDir(pluginId), "template.manifest.json");
|
|
76149
76445
|
const parsed = PluginManifestSchema.safeParse(
|
|
76150
|
-
JSON.parse(
|
|
76446
|
+
JSON.parse(fs37.readFileSync(manifestPath, "utf8"))
|
|
76151
76447
|
);
|
|
76152
76448
|
if (!parsed.success) {
|
|
76153
76449
|
throw new Error(`Invalid plugin manifest for ${pluginId}: ${parsed.error.message}`);
|
|
@@ -76158,40 +76454,40 @@ function readPluginManifest(pluginId) {
|
|
|
76158
76454
|
return parsed.data;
|
|
76159
76455
|
}
|
|
76160
76456
|
function ensureParentDir(filePath) {
|
|
76161
|
-
const parent =
|
|
76162
|
-
if (!
|
|
76163
|
-
|
|
76457
|
+
const parent = path41.dirname(filePath);
|
|
76458
|
+
if (!fs37.existsSync(parent)) {
|
|
76459
|
+
fs37.mkdirSync(parent, { recursive: true });
|
|
76164
76460
|
}
|
|
76165
76461
|
}
|
|
76166
76462
|
function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
76167
|
-
const srcPath =
|
|
76168
|
-
const destPath =
|
|
76169
|
-
if (!
|
|
76463
|
+
const srcPath = path41.join(pluginDir, file.src);
|
|
76464
|
+
const destPath = path41.join(repoPath, file.dest);
|
|
76465
|
+
if (!fs37.existsSync(srcPath)) {
|
|
76170
76466
|
throw new Error(`Plugin file missing: ${file.src}`);
|
|
76171
76467
|
}
|
|
76172
|
-
if (
|
|
76468
|
+
if (fs37.existsSync(destPath) && !force) {
|
|
76173
76469
|
throw new Error(
|
|
76174
76470
|
`File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
|
|
76175
76471
|
);
|
|
76176
76472
|
}
|
|
76177
76473
|
ensureParentDir(destPath);
|
|
76178
|
-
|
|
76474
|
+
fs37.copyFileSync(srcPath, destPath);
|
|
76179
76475
|
if (file.executable) {
|
|
76180
|
-
|
|
76476
|
+
fs37.chmodSync(destPath, 493);
|
|
76181
76477
|
}
|
|
76182
76478
|
return { written: true, path: file.dest };
|
|
76183
76479
|
}
|
|
76184
76480
|
function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
76185
|
-
const packagePath =
|
|
76186
|
-
if (!
|
|
76481
|
+
const packagePath = path41.join(repoPath, "package.json");
|
|
76482
|
+
if (!fs37.existsSync(packagePath)) {
|
|
76187
76483
|
throw new Error("No package.json in repo root. Add one before applying this plugin.");
|
|
76188
76484
|
}
|
|
76189
|
-
const fragmentPath =
|
|
76190
|
-
if (!
|
|
76485
|
+
const fragmentPath = path41.join(pluginDir, fragmentRelPath);
|
|
76486
|
+
if (!fs37.existsSync(fragmentPath)) {
|
|
76191
76487
|
throw new Error(`Package fragment missing: ${fragmentRelPath}`);
|
|
76192
76488
|
}
|
|
76193
|
-
const pkg = JSON.parse(
|
|
76194
|
-
const fragment = JSON.parse(
|
|
76489
|
+
const pkg = JSON.parse(fs37.readFileSync(packagePath, "utf8"));
|
|
76490
|
+
const fragment = JSON.parse(fs37.readFileSync(fragmentPath, "utf8"));
|
|
76195
76491
|
for (const section of ["scripts", "devDependencies"]) {
|
|
76196
76492
|
const existing = pkg[section] ?? {};
|
|
76197
76493
|
const incoming = fragment[section] ?? {};
|
|
@@ -76204,7 +76500,7 @@ function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
|
76204
76500
|
}
|
|
76205
76501
|
pkg[section] = existing;
|
|
76206
76502
|
}
|
|
76207
|
-
|
|
76503
|
+
fs37.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
|
|
76208
76504
|
}
|
|
76209
76505
|
function patchStageRegistry(repoPath, manifest, force) {
|
|
76210
76506
|
const registry2 = readStageRegistry(repoPath);
|
|
@@ -76244,8 +76540,8 @@ function assertHarnessPresent(repoPath) {
|
|
|
76244
76540
|
}
|
|
76245
76541
|
function assertStageNotPresent(repoPath, stageId, force) {
|
|
76246
76542
|
if (force) return;
|
|
76247
|
-
const scriptPath =
|
|
76248
|
-
if (
|
|
76543
|
+
const scriptPath = path41.join(repoPath, ".har", "stages", `${stageId}.sh`);
|
|
76544
|
+
if (fs37.existsSync(scriptPath)) {
|
|
76249
76545
|
throw new Error(
|
|
76250
76546
|
`Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
|
|
76251
76547
|
);
|
|
@@ -76258,7 +76554,7 @@ function assertStageNotPresent(repoPath, stageId, force) {
|
|
|
76258
76554
|
}
|
|
76259
76555
|
}
|
|
76260
76556
|
function applyPlugin(repoPath, pluginId, options = {}) {
|
|
76261
|
-
const resolved =
|
|
76557
|
+
const resolved = path41.resolve(repoPath);
|
|
76262
76558
|
const force = options.force ?? false;
|
|
76263
76559
|
const warnings = [];
|
|
76264
76560
|
const filesWritten = [];
|
|
@@ -76277,7 +76573,7 @@ function applyPlugin(repoPath, pluginId, options = {}) {
|
|
|
76277
76573
|
if (file.skipFlag === "skipCi" && options.skipCi) {
|
|
76278
76574
|
continue;
|
|
76279
76575
|
}
|
|
76280
|
-
if (
|
|
76576
|
+
if (fs37.existsSync(path41.join(resolved, file.dest)) && !force) {
|
|
76281
76577
|
warnings.push(`Skipped optional file (exists): ${file.dest}`);
|
|
76282
76578
|
continue;
|
|
76283
76579
|
}
|
|
@@ -76312,18 +76608,18 @@ function applyPlugin(repoPath, pluginId, options = {}) {
|
|
|
76312
76608
|
};
|
|
76313
76609
|
}
|
|
76314
76610
|
function listPluginIds() {
|
|
76315
|
-
const root =
|
|
76316
|
-
if (!
|
|
76317
|
-
return
|
|
76611
|
+
const root = path41.join(resolveTemplatesDir(), "plugins");
|
|
76612
|
+
if (!fs37.existsSync(root)) return [...PLUGIN_IDS];
|
|
76613
|
+
return fs37.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
|
|
76318
76614
|
}
|
|
76319
76615
|
|
|
76320
76616
|
// src/harness/plugin-drift.ts
|
|
76321
76617
|
init_stages();
|
|
76322
76618
|
var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
|
|
76323
76619
|
function detectInstalledPlugins(repoPath) {
|
|
76324
|
-
const resolved =
|
|
76325
|
-
const registryPath =
|
|
76326
|
-
if (!
|
|
76620
|
+
const resolved = path42.resolve(repoPath);
|
|
76621
|
+
const registryPath = path42.join(resolved, ".har", "stages.json");
|
|
76622
|
+
if (!fs38.existsSync(registryPath)) return [];
|
|
76327
76623
|
const registry2 = readStageRegistry(resolved);
|
|
76328
76624
|
const stageIds = new Set(registry2.stages.map((stage) => stage.id));
|
|
76329
76625
|
const installed = [];
|
|
@@ -76336,17 +76632,17 @@ function detectInstalledPlugins(repoPath) {
|
|
|
76336
76632
|
return installed;
|
|
76337
76633
|
}
|
|
76338
76634
|
function pluginTemplatePath(pluginId, srcRel) {
|
|
76339
|
-
return
|
|
76635
|
+
return path42.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
|
|
76340
76636
|
}
|
|
76341
76637
|
function readBundledPluginFile(pluginId, srcRel) {
|
|
76342
|
-
return
|
|
76638
|
+
return fs38.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
|
|
76343
76639
|
}
|
|
76344
76640
|
function listPluginDestPaths(pluginId, repoPath) {
|
|
76345
76641
|
const manifest = readPluginManifest(pluginId);
|
|
76346
76642
|
const paths = manifest.files.map((file) => file.dest);
|
|
76347
76643
|
if (manifest.optionalFiles) {
|
|
76348
76644
|
for (const file of manifest.optionalFiles) {
|
|
76349
|
-
if (
|
|
76645
|
+
if (fs38.existsSync(path42.join(repoPath, file.dest))) {
|
|
76350
76646
|
paths.push(file.dest);
|
|
76351
76647
|
}
|
|
76352
76648
|
}
|
|
@@ -76405,9 +76701,9 @@ function readTemplatePluginFile(pluginId, dest) {
|
|
|
76405
76701
|
return null;
|
|
76406
76702
|
}
|
|
76407
76703
|
function readInstalledPluginFile(repoPath, pluginId, dest) {
|
|
76408
|
-
const installedPath =
|
|
76409
|
-
if (!
|
|
76410
|
-
const content =
|
|
76704
|
+
const installedPath = path42.join(path42.resolve(repoPath), dest);
|
|
76705
|
+
if (!fs38.existsSync(installedPath)) return null;
|
|
76706
|
+
const content = fs38.readFileSync(installedPath, "utf8");
|
|
76411
76707
|
const manifest = readPluginManifest(pluginId);
|
|
76412
76708
|
const fragmentRel = manifest.merge?.[dest];
|
|
76413
76709
|
if (fragmentRel) {
|
|
@@ -76426,7 +76722,7 @@ function pluginActionHint(pluginId, dest, kind2) {
|
|
|
76426
76722
|
}
|
|
76427
76723
|
function comparePluginToTemplate(repoPath, pluginId) {
|
|
76428
76724
|
const manifest = readPluginManifest(pluginId);
|
|
76429
|
-
const resolved =
|
|
76725
|
+
const resolved = path42.resolve(repoPath);
|
|
76430
76726
|
const destPaths = listPluginDestPaths(pluginId, resolved);
|
|
76431
76727
|
const missing = [];
|
|
76432
76728
|
const checksumMismatch = [];
|
|
@@ -76441,8 +76737,8 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
76441
76737
|
}
|
|
76442
76738
|
if (dest === "package.json") {
|
|
76443
76739
|
const fragmentRel = manifest.merge?.[dest];
|
|
76444
|
-
const installedPath =
|
|
76445
|
-
const installedRaw =
|
|
76740
|
+
const installedPath = path42.join(resolved, dest);
|
|
76741
|
+
const installedRaw = fs38.readFileSync(installedPath, "utf8");
|
|
76446
76742
|
if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
|
|
76447
76743
|
unchanged.push(dest);
|
|
76448
76744
|
} else if (computeFileChecksum(installedContent) === computeFileChecksum(templateContent)) {
|
|
@@ -76511,14 +76807,14 @@ function substituteProjectName2(content, projectName) {
|
|
|
76511
76807
|
return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
76512
76808
|
}
|
|
76513
76809
|
function projectNameFromRepo(repoPath) {
|
|
76514
|
-
return
|
|
76810
|
+
return path43.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
76515
76811
|
}
|
|
76516
76812
|
function boilerplateDirForProfile(profile) {
|
|
76517
|
-
return
|
|
76813
|
+
return path43.join(resolveTemplatesDir(), PROFILE_DIRS3[profile]);
|
|
76518
76814
|
}
|
|
76519
76815
|
function readBundledTemplateContent(repoPath, profile, file) {
|
|
76520
|
-
const templatePath =
|
|
76521
|
-
let content =
|
|
76816
|
+
const templatePath = path43.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
|
|
76817
|
+
let content = fs39.readFileSync(templatePath, "utf8");
|
|
76522
76818
|
if (file === "harness.env") {
|
|
76523
76819
|
content = substituteProjectName2(content, projectNameFromRepo(repoPath));
|
|
76524
76820
|
}
|
|
@@ -76549,12 +76845,12 @@ function actionHint(file, kind2) {
|
|
|
76549
76845
|
return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
|
|
76550
76846
|
}
|
|
76551
76847
|
function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
|
|
76552
|
-
const tmpDir =
|
|
76848
|
+
const tmpDir = fs39.mkdtempSync(path43.join(os14.tmpdir(), "har-maintain-diff-"));
|
|
76553
76849
|
try {
|
|
76554
|
-
const installedPath =
|
|
76555
|
-
const templatePath =
|
|
76556
|
-
|
|
76557
|
-
|
|
76850
|
+
const installedPath = path43.join(tmpDir, "installed");
|
|
76851
|
+
const templatePath = path43.join(tmpDir, "template");
|
|
76852
|
+
fs39.writeFileSync(installedPath, installedContent);
|
|
76853
|
+
fs39.writeFileSync(templatePath, templateContent);
|
|
76558
76854
|
const result = run(`diff -u "${installedPath}" "${templatePath}"`);
|
|
76559
76855
|
const body = result.stdout.trim();
|
|
76560
76856
|
if (!body) return "";
|
|
@@ -76563,7 +76859,7 @@ function createUnifiedDiff(installedContent, templateContent, installedLabel, te
|
|
|
76563
76859
|
${body.split("\n").slice(2).join("\n")}
|
|
76564
76860
|
`;
|
|
76565
76861
|
} finally {
|
|
76566
|
-
|
|
76862
|
+
fs39.rmSync(tmpDir, { recursive: true, force: true });
|
|
76567
76863
|
}
|
|
76568
76864
|
}
|
|
76569
76865
|
function buildActions(repoPath, profile, drift) {
|
|
@@ -76578,7 +76874,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
76578
76874
|
});
|
|
76579
76875
|
}
|
|
76580
76876
|
for (const file of drift.checksumMismatch) {
|
|
76581
|
-
const installedPath =
|
|
76877
|
+
const installedPath = path43.join(harnessDir, file);
|
|
76582
76878
|
const installedRel = `maintain/installed/${file}`;
|
|
76583
76879
|
const templateRel = `maintain/templates/${file}`;
|
|
76584
76880
|
const diffRel = `maintain/diffs/${file}.diff`;
|
|
@@ -76586,7 +76882,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
76586
76882
|
file,
|
|
76587
76883
|
kind: "drift",
|
|
76588
76884
|
template: templateRel,
|
|
76589
|
-
installed:
|
|
76885
|
+
installed: fs39.existsSync(installedPath) ? installedRel : void 0,
|
|
76590
76886
|
diff: diffRel,
|
|
76591
76887
|
hint: actionHint(file, "drift")
|
|
76592
76888
|
});
|
|
@@ -76596,6 +76892,44 @@ function buildActions(repoPath, profile, drift) {
|
|
|
76596
76892
|
function buildStale(drift) {
|
|
76597
76893
|
return drift.extra.map((file) => ({ file, hint: staleFileHint(file) })).sort((a2, b3) => a2.file.localeCompare(b3.file));
|
|
76598
76894
|
}
|
|
76895
|
+
function buildInstructionFileNotes(repoPath) {
|
|
76896
|
+
const detection = detectInstructionFiles(repoPath);
|
|
76897
|
+
const notes = [];
|
|
76898
|
+
if (detection.agentMd) {
|
|
76899
|
+
notes.push({
|
|
76900
|
+
kind: "migrate_legacy_agent_md",
|
|
76901
|
+
path: "AGENT.md",
|
|
76902
|
+
message: "Legacy AGENT.md (singular) found \u2014 merge unique notes into AGENTS.md, then delete AGENT.md. Codex auto-loads AGENTS.md only."
|
|
76903
|
+
});
|
|
76904
|
+
}
|
|
76905
|
+
if (!detection.agentsMd) {
|
|
76906
|
+
notes.push({
|
|
76907
|
+
kind: "create_agents_md",
|
|
76908
|
+
path: "AGENTS.md",
|
|
76909
|
+
message: "AGENTS.md missing \u2014 create it with a HAR / agent environment section (or let maintain\u2019s instruction-files step scaffold it, then fill project-specific notes)."
|
|
76910
|
+
});
|
|
76911
|
+
} else {
|
|
76912
|
+
notes.push({
|
|
76913
|
+
kind: "refresh_agents_md_har_section",
|
|
76914
|
+
path: "AGENTS.md",
|
|
76915
|
+
message: "Refresh the managed HAR / agent environment section in AGENTS.md if workflow/commands changed \u2014 do not wipe unrelated project guidance."
|
|
76916
|
+
});
|
|
76917
|
+
}
|
|
76918
|
+
if (detection.claudeMd) {
|
|
76919
|
+
notes.push({
|
|
76920
|
+
kind: "claude_md_pointer",
|
|
76921
|
+
path: "CLAUDE.md",
|
|
76922
|
+
message: "Keep CLAUDE.md as a thin pointer to AGENTS.md (do not duplicate the full HAR workflow)."
|
|
76923
|
+
});
|
|
76924
|
+
} else {
|
|
76925
|
+
notes.push({
|
|
76926
|
+
kind: "claude_md_pointer",
|
|
76927
|
+
path: "CLAUDE.md",
|
|
76928
|
+
message: "Optional: add a thin CLAUDE.md pointer \u2192 AGENTS.md when Claude Code is used on this repo."
|
|
76929
|
+
});
|
|
76930
|
+
}
|
|
76931
|
+
return notes;
|
|
76932
|
+
}
|
|
76599
76933
|
function buildReadme(report) {
|
|
76600
76934
|
const lines2 = [
|
|
76601
76935
|
"# Harness maintenance bundle",
|
|
@@ -76663,6 +76997,16 @@ function buildReadme(report) {
|
|
|
76663
76997
|
""
|
|
76664
76998
|
);
|
|
76665
76999
|
}
|
|
77000
|
+
if (report.instructionFiles.length > 0) {
|
|
77001
|
+
lines2.push("", "## Agent instruction files (generator 0.5.0)", "");
|
|
77002
|
+
lines2.push(
|
|
77003
|
+
"Repo-root agent docs are **outside** `.har/` checksum drift. Apply while adapting:",
|
|
77004
|
+
""
|
|
77005
|
+
);
|
|
77006
|
+
for (const note of report.instructionFiles) {
|
|
77007
|
+
lines2.push(`- **\`${note.path}\`** (${note.kind}): ${note.message}`);
|
|
77008
|
+
}
|
|
77009
|
+
}
|
|
76666
77010
|
lines2.push("", "## Stale files (review)", "");
|
|
76667
77011
|
if (report.stale.length === 0) {
|
|
76668
77012
|
lines2.push("None detected.");
|
|
@@ -76686,28 +77030,28 @@ function buildReadme(report) {
|
|
|
76686
77030
|
}
|
|
76687
77031
|
function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
76688
77032
|
const harnessDir = getHarnessDir(repoPath);
|
|
76689
|
-
const bundleDir =
|
|
76690
|
-
if (
|
|
76691
|
-
|
|
77033
|
+
const bundleDir = path43.join(harnessDir, MAINTAIN_DIR);
|
|
77034
|
+
if (fs39.existsSync(bundleDir)) {
|
|
77035
|
+
fs39.rmSync(bundleDir, { recursive: true, force: true });
|
|
76692
77036
|
}
|
|
76693
77037
|
const dirs = [
|
|
76694
77038
|
bundleDir,
|
|
76695
|
-
|
|
76696
|
-
|
|
76697
|
-
|
|
76698
|
-
|
|
77039
|
+
path43.join(bundleDir, "templates"),
|
|
77040
|
+
path43.join(bundleDir, "installed"),
|
|
77041
|
+
path43.join(bundleDir, "diffs"),
|
|
77042
|
+
path43.join(bundleDir, "stale")
|
|
76699
77043
|
];
|
|
76700
77044
|
for (const dir of dirs) {
|
|
76701
|
-
|
|
77045
|
+
fs39.mkdirSync(dir, { recursive: true });
|
|
76702
77046
|
}
|
|
76703
77047
|
const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
|
|
76704
77048
|
for (const file of affectedFiles) {
|
|
76705
77049
|
const templateContent = readBundledTemplateContent(repoPath, profile, file);
|
|
76706
|
-
writeFileSafe(
|
|
76707
|
-
const harnessPath =
|
|
76708
|
-
if (
|
|
76709
|
-
const installedContent =
|
|
76710
|
-
writeFileSafe(
|
|
77050
|
+
writeFileSafe(path43.join(bundleDir, "templates", file), templateContent);
|
|
77051
|
+
const harnessPath = path43.join(harnessDir, file);
|
|
77052
|
+
if (fs39.existsSync(harnessPath)) {
|
|
77053
|
+
const installedContent = fs39.readFileSync(harnessPath, "utf8");
|
|
77054
|
+
writeFileSafe(path43.join(bundleDir, "installed", file), installedContent);
|
|
76711
77055
|
const diff = createUnifiedDiff(
|
|
76712
77056
|
installedContent,
|
|
76713
77057
|
templateContent,
|
|
@@ -76715,14 +77059,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
76715
77059
|
`templates/${file}`
|
|
76716
77060
|
);
|
|
76717
77061
|
if (diff) {
|
|
76718
|
-
writeFileSafe(
|
|
77062
|
+
writeFileSafe(path43.join(bundleDir, "diffs", `${file}.diff`), diff);
|
|
76719
77063
|
}
|
|
76720
77064
|
}
|
|
76721
77065
|
}
|
|
76722
|
-
writeFileSafe(
|
|
76723
|
-
writeFileSafe(
|
|
77066
|
+
writeFileSafe(path43.join(bundleDir, "README.md"), buildReadme(report));
|
|
77067
|
+
writeFileSafe(path43.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
|
|
76724
77068
|
writeFileSafe(
|
|
76725
|
-
|
|
77069
|
+
path43.join(bundleDir, "validation.json"),
|
|
76726
77070
|
JSON.stringify(report.validation, null, 2) + "\n"
|
|
76727
77071
|
);
|
|
76728
77072
|
if (report.stale.length > 0) {
|
|
@@ -76734,34 +77078,34 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
76734
77078
|
...report.stale.map((s2) => `- **${s2.file}** \u2014 ${s2.hint}`),
|
|
76735
77079
|
""
|
|
76736
77080
|
];
|
|
76737
|
-
writeFileSafe(
|
|
77081
|
+
writeFileSafe(path43.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
|
|
76738
77082
|
}
|
|
76739
77083
|
return bundleDir;
|
|
76740
77084
|
}
|
|
76741
77085
|
function ensureParentDir2(filePath) {
|
|
76742
|
-
const parent =
|
|
76743
|
-
if (!
|
|
76744
|
-
|
|
77086
|
+
const parent = path43.dirname(filePath);
|
|
77087
|
+
if (!fs39.existsSync(parent)) {
|
|
77088
|
+
fs39.mkdirSync(parent, { recursive: true });
|
|
76745
77089
|
}
|
|
76746
77090
|
}
|
|
76747
77091
|
function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
76748
77092
|
if (report.pluginActions.length === 0) return;
|
|
76749
77093
|
for (const action of report.pluginActions) {
|
|
76750
|
-
const pluginRoot =
|
|
76751
|
-
const templatesDir =
|
|
76752
|
-
const installedDir =
|
|
76753
|
-
const diffsDir =
|
|
77094
|
+
const pluginRoot = path43.join(bundleDir, "plugins", action.pluginId);
|
|
77095
|
+
const templatesDir = path43.join(pluginRoot, "templates");
|
|
77096
|
+
const installedDir = path43.join(pluginRoot, "installed");
|
|
77097
|
+
const diffsDir = path43.join(pluginRoot, "diffs");
|
|
76754
77098
|
for (const dir of [templatesDir, installedDir, diffsDir]) {
|
|
76755
|
-
|
|
77099
|
+
fs39.mkdirSync(dir, { recursive: true });
|
|
76756
77100
|
}
|
|
76757
77101
|
const templateContent = readTemplatePluginFile(action.pluginId, action.file);
|
|
76758
77102
|
if (templateContent === null) continue;
|
|
76759
|
-
const templatePath =
|
|
77103
|
+
const templatePath = path43.join(templatesDir, action.file);
|
|
76760
77104
|
ensureParentDir2(templatePath);
|
|
76761
77105
|
writeFileSafe(templatePath, templateContent);
|
|
76762
77106
|
const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
|
|
76763
77107
|
if (installedContent !== null) {
|
|
76764
|
-
const installedPath =
|
|
77108
|
+
const installedPath = path43.join(installedDir, action.file);
|
|
76765
77109
|
ensureParentDir2(installedPath);
|
|
76766
77110
|
writeFileSafe(installedPath, installedContent);
|
|
76767
77111
|
const diff = createUnifiedDiff(
|
|
@@ -76771,7 +77115,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
|
76771
77115
|
`templates/${action.file}`
|
|
76772
77116
|
);
|
|
76773
77117
|
if (diff) {
|
|
76774
|
-
const diffPath =
|
|
77118
|
+
const diffPath = path43.join(diffsDir, `${action.file}.diff`);
|
|
76775
77119
|
ensureParentDir2(diffPath);
|
|
76776
77120
|
writeFileSafe(diffPath, diff);
|
|
76777
77121
|
}
|
|
@@ -76795,6 +77139,7 @@ function buildMaintainBundle(repoPath, validation2, drift) {
|
|
|
76795
77139
|
stale: buildStale(drift),
|
|
76796
77140
|
missingPortVars: drift.missingPortVars,
|
|
76797
77141
|
agentSlotMismatch: drift.agentSlotMismatch,
|
|
77142
|
+
instructionFiles: buildInstructionFileNotes(repoPath),
|
|
76798
77143
|
validation: {
|
|
76799
77144
|
pass: validation2.pass,
|
|
76800
77145
|
errors,
|
|
@@ -76806,9 +77151,9 @@ function buildMaintainBundle(repoPath, validation2, drift) {
|
|
|
76806
77151
|
return { bundleDir, report };
|
|
76807
77152
|
}
|
|
76808
77153
|
function removeMaintainBundle(repoPath) {
|
|
76809
|
-
const bundleDir =
|
|
76810
|
-
if (
|
|
76811
|
-
|
|
77154
|
+
const bundleDir = path43.join(getHarnessDir(repoPath), MAINTAIN_DIR);
|
|
77155
|
+
if (fs39.existsSync(bundleDir)) {
|
|
77156
|
+
fs39.rmSync(bundleDir, { recursive: true, force: true });
|
|
76812
77157
|
}
|
|
76813
77158
|
}
|
|
76814
77159
|
function formatMaintainBundlePromptSection(report) {
|
|
@@ -76874,7 +77219,19 @@ function formatMaintainBundlePromptSection(report) {
|
|
|
76874
77219
|
""
|
|
76875
77220
|
);
|
|
76876
77221
|
}
|
|
76877
|
-
if (report.
|
|
77222
|
+
if (report.instructionFiles.length > 0) {
|
|
77223
|
+
lines2.push(
|
|
77224
|
+
"### Agent instruction files (generator 0.5.0 \u2014 outside `.har/` drift)",
|
|
77225
|
+
"",
|
|
77226
|
+
"These are **not** checksum drift rows. Apply them while adapting (HAR also migrates/scaffolds on maintain):",
|
|
77227
|
+
""
|
|
77228
|
+
);
|
|
77229
|
+
for (const note of report.instructionFiles) {
|
|
77230
|
+
lines2.push(`- **\`${note.path}\`** (${note.kind}): ${note.message}`);
|
|
77231
|
+
}
|
|
77232
|
+
lines2.push("");
|
|
77233
|
+
}
|
|
77234
|
+
if (report.actions.length === 0 && report.pluginActions.length === 0 && report.stale.length === 0 && report.missingPortVars.length === 0 && !report.agentSlotMismatch && report.validation.errors.length === 0 && report.instructionFiles.length === 0) {
|
|
76878
77235
|
lines2.push("No template drift detected. Review repo stack changes manually if needed.", "");
|
|
76879
77236
|
}
|
|
76880
77237
|
return lines2.join("\n");
|
|
@@ -76886,11 +77243,11 @@ init_stages();
|
|
|
76886
77243
|
init_validation();
|
|
76887
77244
|
function listHarnessScripts(repoPath) {
|
|
76888
77245
|
const harnessDir = getHarnessDir(repoPath);
|
|
76889
|
-
if (!
|
|
76890
|
-
return
|
|
77246
|
+
if (!fs40.existsSync(harnessDir)) return [];
|
|
77247
|
+
return fs40.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
|
|
76891
77248
|
}
|
|
76892
77249
|
function describeProject(repoPath) {
|
|
76893
|
-
const resolved =
|
|
77250
|
+
const resolved = path44.resolve(repoPath);
|
|
76894
77251
|
const manifest = readManifest(resolved);
|
|
76895
77252
|
const present = harnessExists(resolved);
|
|
76896
77253
|
return {
|
|
@@ -76910,8 +77267,8 @@ function describeProject(repoPath) {
|
|
|
76910
77267
|
};
|
|
76911
77268
|
}
|
|
76912
77269
|
async function initHarness(options) {
|
|
76913
|
-
const repoPath =
|
|
76914
|
-
if (!
|
|
77270
|
+
const repoPath = path44.resolve(options.repoPath);
|
|
77271
|
+
if (!fs40.existsSync(repoPath)) {
|
|
76915
77272
|
throw new Error(`Path not found: ${repoPath}`);
|
|
76916
77273
|
}
|
|
76917
77274
|
const scaffold = scaffoldHarnessBoilerplate(repoPath, {
|
|
@@ -76943,9 +77300,9 @@ async function initHarness(options) {
|
|
|
76943
77300
|
};
|
|
76944
77301
|
}
|
|
76945
77302
|
async function maintainHarness(options) {
|
|
76946
|
-
const repoPath =
|
|
77303
|
+
const repoPath = path44.resolve(options.repoPath);
|
|
76947
77304
|
const harnessDir = getHarnessDir(repoPath);
|
|
76948
|
-
if (!
|
|
77305
|
+
if (!fs40.existsSync(harnessDir)) {
|
|
76949
77306
|
throw new Error('No .har/ found. Run "har env init" first.');
|
|
76950
77307
|
}
|
|
76951
77308
|
if (options.auto) {
|
|
@@ -76997,13 +77354,13 @@ function addPlugin(repoPath, pluginId, options = {}) {
|
|
|
76997
77354
|
}
|
|
76998
77355
|
|
|
76999
77356
|
// src/harness/custom-stage.ts
|
|
77000
|
-
var
|
|
77001
|
-
var
|
|
77357
|
+
var fs41 = __toESM(require("fs"));
|
|
77358
|
+
var path45 = __toESM(require("path"));
|
|
77002
77359
|
init_schema2();
|
|
77003
77360
|
init_stages();
|
|
77004
77361
|
var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
77005
77362
|
function addCustomStage(repoPath, options) {
|
|
77006
|
-
const resolved =
|
|
77363
|
+
const resolved = path45.resolve(repoPath);
|
|
77007
77364
|
if (!harnessExists(resolved)) {
|
|
77008
77365
|
throw new Error('No .har/ harness found. Run "har env init" first.');
|
|
77009
77366
|
}
|
|
@@ -77040,20 +77397,20 @@ function addCustomStage(repoPath, options) {
|
|
|
77040
77397
|
if (options.command) {
|
|
77041
77398
|
stage.command = options.command;
|
|
77042
77399
|
} else {
|
|
77043
|
-
const scriptRel =
|
|
77044
|
-
const scriptAbs =
|
|
77045
|
-
if (
|
|
77400
|
+
const scriptRel = path45.join("stages", `${id}.sh`);
|
|
77401
|
+
const scriptAbs = path45.join(resolved, ".har", scriptRel);
|
|
77402
|
+
if (fs41.existsSync(scriptAbs) && !options.force) {
|
|
77046
77403
|
throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
|
|
77047
77404
|
}
|
|
77048
|
-
const skeletonPath =
|
|
77405
|
+
const skeletonPath = path45.join(
|
|
77049
77406
|
resolveTemplatesDir(),
|
|
77050
77407
|
"plugins",
|
|
77051
77408
|
"custom-stage-skeleton.sh"
|
|
77052
77409
|
);
|
|
77053
|
-
const skeleton =
|
|
77054
|
-
|
|
77055
|
-
|
|
77056
|
-
|
|
77410
|
+
const skeleton = fs41.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind2).replace(/__STAGE_DESCRIPTION__/g, stage.description);
|
|
77411
|
+
fs41.mkdirSync(path45.dirname(scriptAbs), { recursive: true });
|
|
77412
|
+
fs41.writeFileSync(scriptAbs, skeleton);
|
|
77413
|
+
fs41.chmodSync(scriptAbs, 493);
|
|
77057
77414
|
filesWritten.push(`.har/${scriptRel}`);
|
|
77058
77415
|
stage.script = scriptRel;
|
|
77059
77416
|
stage.artifacts = [
|
|
@@ -77101,9 +77458,9 @@ function addCustomStage(repoPath, options) {
|
|
|
77101
77458
|
}
|
|
77102
77459
|
|
|
77103
77460
|
// src/harness/adaptation-prompt.ts
|
|
77104
|
-
var
|
|
77105
|
-
var
|
|
77106
|
-
var
|
|
77461
|
+
var fs42 = __toESM(require("fs"));
|
|
77462
|
+
var path46 = __toESM(require("path"));
|
|
77463
|
+
var readline5 = __toESM(require("readline"));
|
|
77107
77464
|
|
|
77108
77465
|
// src/utils/clipboard.ts
|
|
77109
77466
|
var import_child_process8 = require("child_process");
|
|
@@ -77192,7 +77549,7 @@ function loadTemplate(name) {
|
|
|
77192
77549
|
if (!filePath) {
|
|
77193
77550
|
throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
|
|
77194
77551
|
}
|
|
77195
|
-
return
|
|
77552
|
+
return fs42.readFileSync(filePath, "utf8");
|
|
77196
77553
|
}
|
|
77197
77554
|
function applyProfilePlaceholders(content, profile) {
|
|
77198
77555
|
return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
|
|
@@ -77214,7 +77571,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
|
|
|
77214
77571
|
}
|
|
77215
77572
|
function writeAdaptationPrompt(repoPath, content) {
|
|
77216
77573
|
const harnessDir = getHarnessDir(repoPath);
|
|
77217
|
-
const filePath =
|
|
77574
|
+
const filePath = path46.join(harnessDir, ADAPTATION_PROMPT_FILE);
|
|
77218
77575
|
writeFileSafe(filePath, content);
|
|
77219
77576
|
return filePath;
|
|
77220
77577
|
}
|
|
@@ -77231,8 +77588,8 @@ function printAdaptationPrompt(content) {
|
|
|
77231
77588
|
`);
|
|
77232
77589
|
process.stderr.write("\n");
|
|
77233
77590
|
}
|
|
77234
|
-
function
|
|
77235
|
-
const rl =
|
|
77591
|
+
function askYesNo4(question) {
|
|
77592
|
+
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
77236
77593
|
return new Promise((resolve47) => {
|
|
77237
77594
|
process.stderr.write(`${question} `);
|
|
77238
77595
|
rl.once("line", (answer) => {
|
|
@@ -77250,7 +77607,7 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
77250
77607
|
}
|
|
77251
77608
|
let shouldCopy = options.autoYes === true;
|
|
77252
77609
|
if (!shouldCopy && interactive) {
|
|
77253
|
-
shouldCopy = await
|
|
77610
|
+
shouldCopy = await askYesNo4("Copy adaptation prompt to clipboard for your coding agent? [Y/n]");
|
|
77254
77611
|
}
|
|
77255
77612
|
if (!shouldCopy) {
|
|
77256
77613
|
info("Skipped clipboard copy \u2014 prompt is in .har/ADAPT-PROMPT.md");
|
|
@@ -77269,27 +77626,27 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
77269
77626
|
}
|
|
77270
77627
|
|
|
77271
77628
|
// src/harness/cursor-rule.ts
|
|
77272
|
-
var
|
|
77273
|
-
var
|
|
77274
|
-
var
|
|
77629
|
+
var fs43 = __toESM(require("fs"));
|
|
77630
|
+
var path47 = __toESM(require("path"));
|
|
77631
|
+
var readline6 = __toESM(require("readline"));
|
|
77275
77632
|
init_file_ops();
|
|
77276
77633
|
init_logging();
|
|
77277
77634
|
var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
|
|
77278
77635
|
function getCursorRulePath(repoPath) {
|
|
77279
|
-
return
|
|
77636
|
+
return path47.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
77280
77637
|
}
|
|
77281
77638
|
function isCursorWorkspace(repoPath) {
|
|
77282
|
-
return
|
|
77639
|
+
return fs43.existsSync(path47.join(repoPath, ".cursor"));
|
|
77283
77640
|
}
|
|
77284
77641
|
function cursorRuleExists(repoPath) {
|
|
77285
|
-
return
|
|
77642
|
+
return fs43.existsSync(getCursorRulePath(repoPath));
|
|
77286
77643
|
}
|
|
77287
77644
|
function scaffoldCursorRule(repoPath) {
|
|
77288
77645
|
const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
|
|
77289
77646
|
if (!templatePath) {
|
|
77290
77647
|
throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
|
|
77291
77648
|
}
|
|
77292
|
-
const content =
|
|
77649
|
+
const content = fs43.readFileSync(templatePath, "utf8");
|
|
77293
77650
|
writeFileSafe(getCursorRulePath(repoPath), content);
|
|
77294
77651
|
}
|
|
77295
77652
|
async function handleCursorRule(options) {
|
|
@@ -77323,10 +77680,10 @@ async function handleCursorRule(options) {
|
|
|
77323
77680
|
}
|
|
77324
77681
|
async function promptScaffoldCursorRule(exists) {
|
|
77325
77682
|
const action = exists ? "Update" : "Create";
|
|
77326
|
-
return
|
|
77683
|
+
return askYesNo5(`${action} ${CURSOR_RULE_RELATIVE_PATH}? [Y/n]`);
|
|
77327
77684
|
}
|
|
77328
|
-
async function
|
|
77329
|
-
const rl =
|
|
77685
|
+
async function askYesNo5(question) {
|
|
77686
|
+
const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
|
|
77330
77687
|
return new Promise((resolve47) => {
|
|
77331
77688
|
process.stderr.write(`${question} `);
|
|
77332
77689
|
rl.once("line", (answer) => {
|
|
@@ -77379,7 +77736,7 @@ init_control_config();
|
|
|
77379
77736
|
|
|
77380
77737
|
// src/core/control-lifecycle.ts
|
|
77381
77738
|
var import_child_process9 = require("child_process");
|
|
77382
|
-
var
|
|
77739
|
+
var path48 = __toESM(require("path"));
|
|
77383
77740
|
|
|
77384
77741
|
// src/core/control-image.ts
|
|
77385
77742
|
var DEFAULT_CONTROL_IMAGE = "theosfactory/har-control";
|
|
@@ -77405,10 +77762,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
|
|
|
77405
77762
|
var CONTROL_CONTAINER_PORT = 3847;
|
|
77406
77763
|
var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
|
|
77407
77764
|
function resolveControlDir() {
|
|
77408
|
-
return
|
|
77765
|
+
return path48.resolve(__dirname, "..", "control");
|
|
77409
77766
|
}
|
|
77410
77767
|
function resolveControlBuildContext() {
|
|
77411
|
-
return
|
|
77768
|
+
return path48.resolve(resolveControlDir(), "..");
|
|
77412
77769
|
}
|
|
77413
77770
|
function buildDockerRunArgs(options) {
|
|
77414
77771
|
const name = options.containerName ?? CONTROL_CONTAINER_NAME;
|
|
@@ -77464,7 +77821,7 @@ async function startMissionControl(options) {
|
|
|
77464
77821
|
"-t",
|
|
77465
77822
|
imageRef,
|
|
77466
77823
|
"-f",
|
|
77467
|
-
|
|
77824
|
+
path48.join(resolveControlDir(), "Dockerfile"),
|
|
77468
77825
|
resolveControlBuildContext()
|
|
77469
77826
|
]);
|
|
77470
77827
|
if (buildCode !== 0) {
|
|
@@ -77611,7 +77968,7 @@ async function ensureTelemetryInfrastructure(options) {
|
|
|
77611
77968
|
// src/core/run-service.ts
|
|
77612
77969
|
init_telemetry_config();
|
|
77613
77970
|
init_telemetry_env();
|
|
77614
|
-
var
|
|
77971
|
+
var path50 = __toESM(require("path"));
|
|
77615
77972
|
init_local_executor();
|
|
77616
77973
|
function extractShellOutput(result) {
|
|
77617
77974
|
const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
|
|
@@ -77814,12 +78171,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
|
|
|
77814
78171
|
suffix: session.suffix,
|
|
77815
78172
|
createdAt: session.createdAt
|
|
77816
78173
|
});
|
|
77817
|
-
const envFile =
|
|
78174
|
+
const envFile = path50.join(session.workDir, `.env.agent.${options.agentId}`);
|
|
77818
78175
|
try {
|
|
77819
78176
|
appendTelemetryEnvToFile(envFile, {
|
|
77820
78177
|
sessionKey,
|
|
77821
78178
|
agentId: options.agentId,
|
|
77822
|
-
repoPath:
|
|
78179
|
+
repoPath: path50.resolve(options.repoPath),
|
|
77823
78180
|
workDir: session.workDir,
|
|
77824
78181
|
branch: session.branch,
|
|
77825
78182
|
suffix: session.suffix,
|
|
@@ -78054,12 +78411,12 @@ init_runs();
|
|
|
78054
78411
|
init_slot_status();
|
|
78055
78412
|
|
|
78056
78413
|
// src/core/commit-gate-onboarding.ts
|
|
78057
|
-
var
|
|
78414
|
+
var readline7 = __toESM(require("readline"));
|
|
78058
78415
|
|
|
78059
78416
|
// src/core/hooks.ts
|
|
78060
|
-
var
|
|
78061
|
-
var
|
|
78062
|
-
var
|
|
78417
|
+
var fs45 = __toESM(require("fs"));
|
|
78418
|
+
var os16 = __toESM(require("os"));
|
|
78419
|
+
var path51 = __toESM(require("path"));
|
|
78063
78420
|
init_shell();
|
|
78064
78421
|
init_schema2();
|
|
78065
78422
|
init_stages();
|
|
@@ -78090,7 +78447,7 @@ function resolveCheckoutRoot(cwd) {
|
|
|
78090
78447
|
function resolveHooksDir(checkoutDir) {
|
|
78091
78448
|
const hooksPath = tryGit3(checkoutDir, "rev-parse --git-path hooks");
|
|
78092
78449
|
if (!hooksPath) throw new Error(`Not a git checkout: ${checkoutDir}`);
|
|
78093
|
-
return
|
|
78450
|
+
return path51.resolve(checkoutDir, hooksPath);
|
|
78094
78451
|
}
|
|
78095
78452
|
function getConfiguredHooksPath(checkoutDir) {
|
|
78096
78453
|
return tryGit3(checkoutDir, "config core.hooksPath") || void 0;
|
|
@@ -78098,9 +78455,9 @@ function getConfiguredHooksPath(checkoutDir) {
|
|
|
78098
78455
|
function defaultHarInvocation() {
|
|
78099
78456
|
const entry = process.argv[1];
|
|
78100
78457
|
if (entry && entry.endsWith(".js")) {
|
|
78101
|
-
return `"${process.execPath}" "${
|
|
78458
|
+
return `"${process.execPath}" "${path51.resolve(entry)}"`;
|
|
78102
78459
|
}
|
|
78103
|
-
if (entry) return `"${
|
|
78460
|
+
if (entry) return `"${path51.resolve(entry)}"`;
|
|
78104
78461
|
return "har";
|
|
78105
78462
|
}
|
|
78106
78463
|
function buildHookScript(harInvocation, subcommand, failOpenNotice) {
|
|
@@ -78120,45 +78477,45 @@ echo "${failOpenNotice}" >&2
|
|
|
78120
78477
|
exit 0
|
|
78121
78478
|
`;
|
|
78122
78479
|
}
|
|
78123
|
-
function
|
|
78124
|
-
if (!
|
|
78125
|
-
|
|
78480
|
+
function upsertMarkedBlock2(filePath, block) {
|
|
78481
|
+
if (!fs45.existsSync(filePath)) {
|
|
78482
|
+
fs45.writeFileSync(filePath, `#!/bin/sh
|
|
78126
78483
|
${block}
|
|
78127
78484
|
`, { mode: 493 });
|
|
78128
78485
|
return "created";
|
|
78129
78486
|
}
|
|
78130
|
-
const content =
|
|
78487
|
+
const content = fs45.readFileSync(filePath, "utf8");
|
|
78131
78488
|
if (content.includes(MARKER_START)) {
|
|
78132
78489
|
const pattern = new RegExp(
|
|
78133
|
-
`${
|
|
78490
|
+
`${escapeRegExp2(MARKER_START)}[\\s\\S]*?${escapeRegExp2(MARKER_END)}`
|
|
78134
78491
|
);
|
|
78135
|
-
|
|
78136
|
-
|
|
78492
|
+
fs45.writeFileSync(filePath, content.replace(pattern, block));
|
|
78493
|
+
fs45.chmodSync(filePath, 493);
|
|
78137
78494
|
return "updated";
|
|
78138
78495
|
}
|
|
78139
78496
|
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
78140
|
-
|
|
78497
|
+
fs45.writeFileSync(filePath, `${content}${suffix}
|
|
78141
78498
|
${block}
|
|
78142
78499
|
`);
|
|
78143
|
-
|
|
78500
|
+
fs45.chmodSync(filePath, 493);
|
|
78144
78501
|
return "appended";
|
|
78145
78502
|
}
|
|
78146
78503
|
function removeMarkedBlock(filePath) {
|
|
78147
|
-
if (!
|
|
78148
|
-
const content =
|
|
78504
|
+
if (!fs45.existsSync(filePath)) return false;
|
|
78505
|
+
const content = fs45.readFileSync(filePath, "utf8");
|
|
78149
78506
|
if (!content.includes(MARKER_START)) return false;
|
|
78150
78507
|
const pattern = new RegExp(
|
|
78151
|
-
`\\n?${
|
|
78508
|
+
`\\n?${escapeRegExp2(MARKER_START)}[\\s\\S]*?${escapeRegExp2(MARKER_END)}\\n?`
|
|
78152
78509
|
);
|
|
78153
78510
|
const stripped = content.replace(pattern, "\n");
|
|
78154
78511
|
if (stripped.replace(/^#!\/bin\/sh\n?/, "").trim() === "") {
|
|
78155
|
-
|
|
78512
|
+
fs45.rmSync(filePath);
|
|
78156
78513
|
} else {
|
|
78157
|
-
|
|
78514
|
+
fs45.writeFileSync(filePath, stripped);
|
|
78158
78515
|
}
|
|
78159
78516
|
return true;
|
|
78160
78517
|
}
|
|
78161
|
-
function
|
|
78518
|
+
function escapeRegExp2(value) {
|
|
78162
78519
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
78163
78520
|
}
|
|
78164
78521
|
function installHooks(options) {
|
|
@@ -78176,20 +78533,20 @@ Or re-run with --force to write into that directory anyway.`
|
|
|
78176
78533
|
);
|
|
78177
78534
|
}
|
|
78178
78535
|
const hooksDir = resolveHooksDir(checkout);
|
|
78179
|
-
|
|
78536
|
+
fs45.mkdirSync(hooksDir, { recursive: true });
|
|
78180
78537
|
const invocation = options.harInvocation ?? defaultHarInvocation();
|
|
78181
|
-
|
|
78182
|
-
|
|
78538
|
+
fs45.writeFileSync(
|
|
78539
|
+
path51.join(hooksDir, "har-pre-commit"),
|
|
78183
78540
|
buildHookScript(invocation, "check", "har: binary not found; skipping commit gate (reinstall with har hooks install)"),
|
|
78184
78541
|
{ mode: 493 }
|
|
78185
78542
|
);
|
|
78186
|
-
|
|
78187
|
-
|
|
78543
|
+
fs45.writeFileSync(
|
|
78544
|
+
path51.join(hooksDir, "har-post-commit"),
|
|
78188
78545
|
buildHookScript(invocation, "record-commit", "har: binary not found; skipping commit association"),
|
|
78189
78546
|
{ mode: 493 }
|
|
78190
78547
|
);
|
|
78191
|
-
const preCommit =
|
|
78192
|
-
const postCommit =
|
|
78548
|
+
const preCommit = upsertMarkedBlock2(path51.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
|
|
78549
|
+
const postCommit = upsertMarkedBlock2(path51.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
|
|
78193
78550
|
ensureValidationsIgnored(checkout);
|
|
78194
78551
|
return { hooksDir, preCommit, postCommit };
|
|
78195
78552
|
}
|
|
@@ -78198,12 +78555,12 @@ function uninstallHooks(repoPath) {
|
|
|
78198
78555
|
if (!checkout) throw new Error(`Not a git repository: ${repoPath}`);
|
|
78199
78556
|
const hooksDir = resolveHooksDir(checkout);
|
|
78200
78557
|
let removed = false;
|
|
78201
|
-
removed = removeMarkedBlock(
|
|
78202
|
-
removed = removeMarkedBlock(
|
|
78558
|
+
removed = removeMarkedBlock(path51.join(hooksDir, "pre-commit")) || removed;
|
|
78559
|
+
removed = removeMarkedBlock(path51.join(hooksDir, "post-commit")) || removed;
|
|
78203
78560
|
for (const file of ["har-pre-commit", "har-post-commit"]) {
|
|
78204
|
-
const full =
|
|
78205
|
-
if (
|
|
78206
|
-
|
|
78561
|
+
const full = path51.join(hooksDir, file);
|
|
78562
|
+
if (fs45.existsSync(full)) {
|
|
78563
|
+
fs45.rmSync(full);
|
|
78207
78564
|
removed = true;
|
|
78208
78565
|
}
|
|
78209
78566
|
}
|
|
@@ -78222,10 +78579,10 @@ function isAgentWorktree(checkoutDir) {
|
|
|
78222
78579
|
if (branch && (/^har-agent-\d+$/.test(branch) || /-har-agent-\d+-[a-z0-9]+$/.test(branch))) {
|
|
78223
78580
|
return true;
|
|
78224
78581
|
}
|
|
78225
|
-
const worktreesRoot =
|
|
78226
|
-
const resolved =
|
|
78227
|
-
const name =
|
|
78228
|
-
return resolved.startsWith(`${worktreesRoot}${
|
|
78582
|
+
const worktreesRoot = path51.join(os16.homedir(), "worktrees");
|
|
78583
|
+
const resolved = path51.resolve(checkoutDir);
|
|
78584
|
+
const name = path51.basename(resolved);
|
|
78585
|
+
return resolved.startsWith(`${worktreesRoot}${path51.sep}`) && (/-agent-\d+$/.test(name) || /-har-agent-\d+-[a-z0-9]+$/.test(name));
|
|
78229
78586
|
}
|
|
78230
78587
|
function resolveEffectiveMode(checkoutDir, gate) {
|
|
78231
78588
|
if (!gate.enabled) return "off";
|
|
@@ -78238,15 +78595,15 @@ function getHooksStatus(repoPath) {
|
|
|
78238
78595
|
const hooksDir = resolveHooksDir(checkout);
|
|
78239
78596
|
const gate = getCommitGateConfig(checkout);
|
|
78240
78597
|
const hasBlock = (name) => {
|
|
78241
|
-
const file =
|
|
78242
|
-
return
|
|
78598
|
+
const file = path51.join(hooksDir, name);
|
|
78599
|
+
return fs45.existsSync(file) && fs45.readFileSync(file, "utf8").includes(MARKER_START);
|
|
78243
78600
|
};
|
|
78244
78601
|
return {
|
|
78245
78602
|
checkout,
|
|
78246
78603
|
hooksDir,
|
|
78247
78604
|
configuredHooksPath: getConfiguredHooksPath(checkout),
|
|
78248
|
-
preCommitInstalled: hasBlock("pre-commit") &&
|
|
78249
|
-
postCommitInstalled: hasBlock("post-commit") &&
|
|
78605
|
+
preCommitInstalled: hasBlock("pre-commit") && fs45.existsSync(path51.join(hooksDir, "har-pre-commit")),
|
|
78606
|
+
postCommitInstalled: hasBlock("post-commit") && fs45.existsSync(path51.join(hooksDir, "har-post-commit")),
|
|
78250
78607
|
gate,
|
|
78251
78608
|
effectiveMode: resolveEffectiveMode(checkout, gate)
|
|
78252
78609
|
};
|
|
@@ -78257,7 +78614,7 @@ function checkCommitGate(cwd) {
|
|
|
78257
78614
|
}
|
|
78258
78615
|
const checkout = resolveCheckoutRoot(cwd);
|
|
78259
78616
|
if (!checkout) return { exitCode: 0, messages: [] };
|
|
78260
|
-
if (!
|
|
78617
|
+
if (!fs45.existsSync(path51.join(checkout, ".har", "stages.json"))) {
|
|
78261
78618
|
return { exitCode: 0, messages: [] };
|
|
78262
78619
|
}
|
|
78263
78620
|
const gate = getCommitGateConfig(checkout);
|
|
@@ -78330,8 +78687,8 @@ async function recordCommitAssociation(cwd) {
|
|
|
78330
78687
|
// src/core/commit-gate-onboarding.ts
|
|
78331
78688
|
init_stages();
|
|
78332
78689
|
init_logging();
|
|
78333
|
-
function
|
|
78334
|
-
const rl =
|
|
78690
|
+
function askYesNo6(question) {
|
|
78691
|
+
const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
|
|
78335
78692
|
return new Promise((resolve47) => {
|
|
78336
78693
|
process.stderr.write(`${question} `);
|
|
78337
78694
|
rl.once("line", (answer) => {
|
|
@@ -78362,7 +78719,7 @@ async function handleCommitGateOnboarding(options) {
|
|
|
78362
78719
|
const status = getHooksStatus(options.repoPath);
|
|
78363
78720
|
let shouldInstall = status.preCommitInstalled || status.postCommitInstalled || options.install === "always" || options.autoYes === true;
|
|
78364
78721
|
if (!shouldInstall && options.install === "prompt" && process.stdin.isTTY && process.stdout.isTTY) {
|
|
78365
|
-
shouldInstall = await
|
|
78722
|
+
shouldInstall = await askYesNo6("Install the HAR commit gate for this repository? [Y/n]");
|
|
78366
78723
|
}
|
|
78367
78724
|
if (!shouldInstall) {
|
|
78368
78725
|
info("Commit gate is not installed; run `har hooks install` when ready.");
|
|
@@ -78379,21 +78736,21 @@ async function handleCommitGateOnboarding(options) {
|
|
|
78379
78736
|
}
|
|
78380
78737
|
|
|
78381
78738
|
// src/core/onboarding-preferences.ts
|
|
78382
|
-
var
|
|
78383
|
-
var
|
|
78384
|
-
var
|
|
78739
|
+
var fs46 = __toESM(require("fs"));
|
|
78740
|
+
var os17 = __toESM(require("os"));
|
|
78741
|
+
var path52 = __toESM(require("path"));
|
|
78385
78742
|
init_schema2();
|
|
78386
78743
|
function getOnboardingPreferencesPath() {
|
|
78387
78744
|
if (process.env.HAR_PREFERENCES_PATH) {
|
|
78388
|
-
return
|
|
78745
|
+
return path52.resolve(process.env.HAR_PREFERENCES_PATH);
|
|
78389
78746
|
}
|
|
78390
|
-
return
|
|
78747
|
+
return path52.join(os17.homedir(), ".har", "preferences.json");
|
|
78391
78748
|
}
|
|
78392
78749
|
function readOnboardingPreferences() {
|
|
78393
78750
|
const preferencePath = getOnboardingPreferencesPath();
|
|
78394
78751
|
try {
|
|
78395
|
-
if (!
|
|
78396
|
-
return OnboardingPreferencesSchema.parse(JSON.parse(
|
|
78752
|
+
if (!fs46.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
|
|
78753
|
+
return OnboardingPreferencesSchema.parse(JSON.parse(fs46.readFileSync(preferencePath, "utf8")));
|
|
78397
78754
|
} catch {
|
|
78398
78755
|
return OnboardingPreferencesSchema.parse({});
|
|
78399
78756
|
}
|
|
@@ -78418,8 +78775,8 @@ function writeOnboardingPreferences(overrides) {
|
|
|
78418
78775
|
};
|
|
78419
78776
|
const parsed = OnboardingPreferencesSchema.parse(preference);
|
|
78420
78777
|
const preferencePath = getOnboardingPreferencesPath();
|
|
78421
|
-
|
|
78422
|
-
|
|
78778
|
+
fs46.mkdirSync(path52.dirname(preferencePath), { recursive: true });
|
|
78779
|
+
fs46.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
|
|
78423
78780
|
`);
|
|
78424
78781
|
return parsed;
|
|
78425
78782
|
}
|
|
@@ -78713,7 +79070,7 @@ var envCommand = {
|
|
|
78713
79070
|
}
|
|
78714
79071
|
};
|
|
78715
79072
|
async function handleInit(argv) {
|
|
78716
|
-
const repoPath =
|
|
79073
|
+
const repoPath = path53.resolve(argv.repo);
|
|
78717
79074
|
const onboarding = resolveOnboardingOptions(argv);
|
|
78718
79075
|
header("har env init");
|
|
78719
79076
|
info(`Repository: ${repoPath}`);
|
|
@@ -78756,18 +79113,13 @@ async function handleInit(argv) {
|
|
|
78756
79113
|
...onboarding.commitGate,
|
|
78757
79114
|
autoYes: argv.yes
|
|
78758
79115
|
});
|
|
78759
|
-
await
|
|
79116
|
+
await applyAgentIntegrations({
|
|
78760
79117
|
repoPath,
|
|
78761
|
-
|
|
78762
|
-
autoYes: argv.yes,
|
|
78763
|
-
mode: "init"
|
|
78764
|
-
});
|
|
78765
|
-
await handleAgentSkills({
|
|
78766
|
-
repoPath,
|
|
78767
|
-
...onboarding.agentSkills,
|
|
79118
|
+
mode: "init",
|
|
78768
79119
|
autoYes: argv.yes,
|
|
78769
79120
|
force: argv.force,
|
|
78770
|
-
|
|
79121
|
+
cursorRule: onboarding.cursorRule,
|
|
79122
|
+
...onboarding.agentSkills
|
|
78771
79123
|
});
|
|
78772
79124
|
printNextSteps(argv.auto);
|
|
78773
79125
|
} catch (err) {
|
|
@@ -78776,7 +79128,7 @@ async function handleInit(argv) {
|
|
|
78776
79128
|
}
|
|
78777
79129
|
}
|
|
78778
79130
|
async function handleMaintain(argv) {
|
|
78779
|
-
const repoPath =
|
|
79131
|
+
const repoPath = path53.resolve(argv.repo);
|
|
78780
79132
|
const onboarding = resolveOnboardingOptions(argv);
|
|
78781
79133
|
header("har env maintain");
|
|
78782
79134
|
info(`Repository: ${repoPath}`);
|
|
@@ -78840,17 +79192,12 @@ async function handleMaintain(argv) {
|
|
|
78840
79192
|
...onboarding.commitGate,
|
|
78841
79193
|
autoYes: argv.yes
|
|
78842
79194
|
});
|
|
78843
|
-
await
|
|
79195
|
+
await applyAgentIntegrations({
|
|
78844
79196
|
repoPath,
|
|
78845
|
-
|
|
79197
|
+
mode: "maintain",
|
|
78846
79198
|
autoYes: argv.yes,
|
|
78847
|
-
|
|
78848
|
-
|
|
78849
|
-
await handleAgentSkills({
|
|
78850
|
-
repoPath,
|
|
78851
|
-
...onboarding.agentSkills,
|
|
78852
|
-
autoYes: argv.yes,
|
|
78853
|
-
mode: "maintain"
|
|
79199
|
+
cursorRule: onboarding.cursorRule,
|
|
79200
|
+
...onboarding.agentSkills
|
|
78854
79201
|
});
|
|
78855
79202
|
} catch (err) {
|
|
78856
79203
|
error(err.message);
|
|
@@ -78898,16 +79245,43 @@ async function handleAgentMdProposal(repoPath, autoYes) {
|
|
|
78898
79245
|
if (autoYes) {
|
|
78899
79246
|
const proposal = readAgentMdProposal(repoPath);
|
|
78900
79247
|
if (proposal) {
|
|
78901
|
-
writeFileSafe(
|
|
79248
|
+
writeFileSafe(path53.join(repoPath, AGENTS_MD), proposal.content);
|
|
78902
79249
|
clearAgentMdProposal(repoPath);
|
|
78903
|
-
info(
|
|
79250
|
+
info(`Applied ${AGENTS_MD} proposal (--yes)`);
|
|
78904
79251
|
}
|
|
78905
79252
|
return;
|
|
78906
79253
|
}
|
|
78907
79254
|
await promptApplyAgentMdProposal(repoPath);
|
|
78908
79255
|
}
|
|
79256
|
+
async function applyAgentIntegrations(options) {
|
|
79257
|
+
const instruction = await handleInstructionFiles({
|
|
79258
|
+
repoPath: options.repoPath,
|
|
79259
|
+
agents: options.agents,
|
|
79260
|
+
enabled: options.enabled,
|
|
79261
|
+
cursorRule: options.cursorRule,
|
|
79262
|
+
autoYes: options.autoYes,
|
|
79263
|
+
mode: options.mode
|
|
79264
|
+
});
|
|
79265
|
+
const cursorRuleFlag = options.cursorRule === false ? false : options.cursorRule === true || instruction.plan.cursorRule ? true : false;
|
|
79266
|
+
await handleCursorRule({
|
|
79267
|
+
repoPath: options.repoPath,
|
|
79268
|
+
cursorRule: cursorRuleFlag,
|
|
79269
|
+
autoYes: options.autoYes,
|
|
79270
|
+
mode: options.mode
|
|
79271
|
+
});
|
|
79272
|
+
if (instruction.plan.skills.length > 0) {
|
|
79273
|
+
await handleAgentSkills({
|
|
79274
|
+
repoPath: options.repoPath,
|
|
79275
|
+
agents: instruction.plan.skills.join(","),
|
|
79276
|
+
autoYes: options.autoYes,
|
|
79277
|
+
force: options.force,
|
|
79278
|
+
mode: options.mode
|
|
79279
|
+
});
|
|
79280
|
+
} else if (options.enabled === false) {
|
|
79281
|
+
}
|
|
79282
|
+
}
|
|
78909
79283
|
async function handleAddPlugin(argv) {
|
|
78910
|
-
const repoPath =
|
|
79284
|
+
const repoPath = path53.resolve(argv.repo);
|
|
78911
79285
|
const available = listPluginIds();
|
|
78912
79286
|
if (argv.list) {
|
|
78913
79287
|
for (const id of available) {
|
|
@@ -78945,7 +79319,7 @@ async function handleAddPlugin(argv) {
|
|
|
78945
79319
|
}
|
|
78946
79320
|
}
|
|
78947
79321
|
async function handleAddStage(argv) {
|
|
78948
|
-
const repoPath =
|
|
79322
|
+
const repoPath = path53.resolve(argv.repo);
|
|
78949
79323
|
const available = listPluginIds();
|
|
78950
79324
|
if (argv.list) {
|
|
78951
79325
|
warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
|
|
@@ -79011,7 +79385,7 @@ async function handleAddStage(argv) {
|
|
|
79011
79385
|
});
|
|
79012
79386
|
}
|
|
79013
79387
|
async function handlePreflight(argv) {
|
|
79014
|
-
const repo =
|
|
79388
|
+
const repo = path53.resolve(argv.repo);
|
|
79015
79389
|
const agentId = validateAgentId(argv.id, repo);
|
|
79016
79390
|
const result = await preflightEnvironment({
|
|
79017
79391
|
repoPath: repo,
|
|
@@ -79027,7 +79401,7 @@ async function handlePreflight(argv) {
|
|
|
79027
79401
|
return finishCommand(result.code);
|
|
79028
79402
|
}
|
|
79029
79403
|
async function handleLaunch(argv) {
|
|
79030
|
-
const repo =
|
|
79404
|
+
const repo = path53.resolve(argv.repo);
|
|
79031
79405
|
const agentId = validateAgentId(argv.id, repo);
|
|
79032
79406
|
if (!argv.resume) {
|
|
79033
79407
|
const guard = checkLaunchGuard2(repo, agentId, {});
|
|
@@ -79082,7 +79456,7 @@ async function handleRecover(argv) {
|
|
|
79082
79456
|
});
|
|
79083
79457
|
}
|
|
79084
79458
|
async function handleVerify(argv) {
|
|
79085
|
-
const repo =
|
|
79459
|
+
const repo = path53.resolve(argv.repo);
|
|
79086
79460
|
const agentId = validateAgentId(argv.id, repo);
|
|
79087
79461
|
const result = await runVerification({
|
|
79088
79462
|
repoPath: repo,
|
|
@@ -79094,7 +79468,7 @@ async function handleVerify(argv) {
|
|
|
79094
79468
|
return finishCommand(result.code);
|
|
79095
79469
|
}
|
|
79096
79470
|
async function handleTeardown(argv) {
|
|
79097
|
-
const repo =
|
|
79471
|
+
const repo = path53.resolve(argv.repo);
|
|
79098
79472
|
const agentId = validateAgentId(argv.id, repo);
|
|
79099
79473
|
const result = await teardownEnvironment({
|
|
79100
79474
|
repoPath: repo,
|
|
@@ -79105,7 +79479,7 @@ async function handleTeardown(argv) {
|
|
|
79105
79479
|
return finishCommand(result.code);
|
|
79106
79480
|
}
|
|
79107
79481
|
async function handleComplete(argv) {
|
|
79108
|
-
const repo =
|
|
79482
|
+
const repo = path53.resolve(argv.repo);
|
|
79109
79483
|
const agentId = validateAgentId(argv.id, repo);
|
|
79110
79484
|
const result = await completeEnvironment({
|
|
79111
79485
|
repoPath: repo,
|
|
@@ -79126,7 +79500,7 @@ async function handleComplete(argv) {
|
|
|
79126
79500
|
return finishCommand(result.code);
|
|
79127
79501
|
}
|
|
79128
79502
|
async function handleStatus(argv) {
|
|
79129
|
-
const repoPath =
|
|
79503
|
+
const repoPath = path53.resolve(argv.repo);
|
|
79130
79504
|
if (argv.json) {
|
|
79131
79505
|
const status = collectEnvironmentStatus(repoPath);
|
|
79132
79506
|
const output = EnvironmentStatusSchema.parse(status);
|
|
@@ -79139,7 +79513,7 @@ async function handleStatus(argv) {
|
|
|
79139
79513
|
});
|
|
79140
79514
|
}
|
|
79141
79515
|
async function handleRunsList(argv) {
|
|
79142
|
-
const repoPath =
|
|
79516
|
+
const repoPath = path53.resolve(argv.repo);
|
|
79143
79517
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
79144
79518
|
if (argv.json) {
|
|
79145
79519
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -79156,7 +79530,7 @@ async function handleRunsList(argv) {
|
|
|
79156
79530
|
}
|
|
79157
79531
|
}
|
|
79158
79532
|
async function handleRunsGet(argv) {
|
|
79159
|
-
const run2 = getRun(
|
|
79533
|
+
const run2 = getRun(path53.resolve(argv.repo), argv.runId);
|
|
79160
79534
|
if (!run2) {
|
|
79161
79535
|
error(`Run not found: ${argv.runId}`);
|
|
79162
79536
|
return finishCommand(1);
|
|
@@ -79231,7 +79605,7 @@ function printNextSteps(auto2) {
|
|
|
79231
79605
|
console.error(" Adapt: paste clipboard / prompt above into your coding agent");
|
|
79232
79606
|
console.error(" Prompt file: .har/ADAPT-PROMPT.md");
|
|
79233
79607
|
} else {
|
|
79234
|
-
console.error(" Agent guide:
|
|
79608
|
+
console.error(" Agent guide: AGENTS.md (repo root, if applied)");
|
|
79235
79609
|
}
|
|
79236
79610
|
console.error(" Setup infra: ./.har/setup-infra.sh # when Docker infra is enabled");
|
|
79237
79611
|
console.error(" Launch: har env launch 1 # preferred; or ./.har/launch.sh 1");
|
|
@@ -79242,7 +79616,7 @@ function printNextSteps(auto2) {
|
|
|
79242
79616
|
}
|
|
79243
79617
|
|
|
79244
79618
|
// src/cli/commands/control.ts
|
|
79245
|
-
var
|
|
79619
|
+
var path57 = __toESM(require("path"));
|
|
79246
79620
|
|
|
79247
79621
|
// node_modules/@inquirer/core/dist/esm/lib/key.mjs
|
|
79248
79622
|
var isUpKey = (key) => (
|
|
@@ -79323,7 +79697,7 @@ function getStore() {
|
|
|
79323
79697
|
}
|
|
79324
79698
|
return store;
|
|
79325
79699
|
}
|
|
79326
|
-
function
|
|
79700
|
+
function readline8() {
|
|
79327
79701
|
return getStore().rl;
|
|
79328
79702
|
}
|
|
79329
79703
|
function withUpdates(fn) {
|
|
@@ -79368,7 +79742,7 @@ var effectScheduler = {
|
|
|
79368
79742
|
const { index } = store;
|
|
79369
79743
|
store.hooksEffect.push(() => {
|
|
79370
79744
|
store.hooksCleanup[index]?.();
|
|
79371
|
-
const cleanFn = cb(
|
|
79745
|
+
const cleanFn = cb(readline8());
|
|
79372
79746
|
if (cleanFn != null && typeof cleanFn !== "function") {
|
|
79373
79747
|
throw new ValidationError("useEffect return value must be a cleanup function or nothing.");
|
|
79374
79748
|
}
|
|
@@ -79844,7 +80218,7 @@ function breakLines(content, width) {
|
|
|
79844
80218
|
return content.split("\n").flatMap((line) => (0, import_wrap_ansi.default)(line, width, { trim: false, hard: true }).split("\n").map((str) => str.trimEnd())).join("\n");
|
|
79845
80219
|
}
|
|
79846
80220
|
function readlineWidth() {
|
|
79847
|
-
return (0, import_cli_width.default)({ defaultWidth: 80, output:
|
|
80221
|
+
return (0, import_cli_width.default)({ defaultWidth: 80, output: readline8().output });
|
|
79848
80222
|
}
|
|
79849
80223
|
|
|
79850
80224
|
// node_modules/@inquirer/core/dist/esm/lib/pagination/lines.mjs
|
|
@@ -79936,7 +80310,7 @@ function usePagination({ items, active, renderItem, pageSize, loop = true }) {
|
|
|
79936
80310
|
}
|
|
79937
80311
|
|
|
79938
80312
|
// node_modules/@inquirer/core/dist/esm/lib/create-prompt.mjs
|
|
79939
|
-
var
|
|
80313
|
+
var readline9 = __toESM(require("node:readline"), 1);
|
|
79940
80314
|
var import_node_async_hooks3 = require("node:async_hooks");
|
|
79941
80315
|
var import_mute_stream = __toESM(require_lib3(), 1);
|
|
79942
80316
|
|
|
@@ -80279,7 +80653,7 @@ function createPrompt(view) {
|
|
|
80279
80653
|
const cleanups = /* @__PURE__ */ new Set();
|
|
80280
80654
|
const output = new import_mute_stream.default();
|
|
80281
80655
|
output.pipe(context.output ?? process.stdout);
|
|
80282
|
-
const rl =
|
|
80656
|
+
const rl = readline9.createInterface({
|
|
80283
80657
|
terminal: true,
|
|
80284
80658
|
input,
|
|
80285
80659
|
output
|
|
@@ -81296,9 +81670,9 @@ var import_run_async = __toESM(require_run_async(), 1);
|
|
|
81296
81670
|
var import_mute_stream2 = __toESM(require_lib3(), 1);
|
|
81297
81671
|
var import_ansi_escapes5 = __toESM(require_ansi_escapes(), 1);
|
|
81298
81672
|
var _2 = {
|
|
81299
|
-
set: (obj,
|
|
81673
|
+
set: (obj, path64 = "", value) => {
|
|
81300
81674
|
let pointer = obj;
|
|
81301
|
-
|
|
81675
|
+
path64.split(".").forEach((key, index, arr) => {
|
|
81302
81676
|
if (key === "__proto__" || key === "constructor")
|
|
81303
81677
|
return;
|
|
81304
81678
|
if (index === arr.length - 1) {
|
|
@@ -81309,8 +81683,8 @@ var _2 = {
|
|
|
81309
81683
|
pointer = pointer[key];
|
|
81310
81684
|
});
|
|
81311
81685
|
},
|
|
81312
|
-
get: (obj,
|
|
81313
|
-
const travel = (regexp) => String.prototype.split.call(
|
|
81686
|
+
get: (obj, path64 = "", defaultValue) => {
|
|
81687
|
+
const travel = (regexp) => String.prototype.split.call(path64, regexp).filter(Boolean).reduce(
|
|
81314
81688
|
// @ts-expect-error implicit any on res[key]
|
|
81315
81689
|
(res, key) => res !== null && res !== void 0 ? res[key] : res,
|
|
81316
81690
|
obj
|
|
@@ -81564,21 +81938,21 @@ init_control_port();
|
|
|
81564
81938
|
init_control_sync();
|
|
81565
81939
|
|
|
81566
81940
|
// src/core/control-sync-selection.ts
|
|
81567
|
-
var
|
|
81568
|
-
var
|
|
81569
|
-
var
|
|
81941
|
+
var fs47 = __toESM(require("fs"));
|
|
81942
|
+
var os18 = __toESM(require("os"));
|
|
81943
|
+
var path54 = __toESM(require("path"));
|
|
81570
81944
|
init_control_repo_path();
|
|
81571
81945
|
function getSelectionPath() {
|
|
81572
81946
|
if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
|
|
81573
|
-
return
|
|
81947
|
+
return path54.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
|
|
81574
81948
|
}
|
|
81575
|
-
return
|
|
81949
|
+
return path54.join(os18.homedir(), ".har", "sync-selection.json");
|
|
81576
81950
|
}
|
|
81577
81951
|
function readSyncSelection() {
|
|
81578
81952
|
const selectionPath = getSelectionPath();
|
|
81579
81953
|
try {
|
|
81580
|
-
if (!
|
|
81581
|
-
const parsed = JSON.parse(
|
|
81954
|
+
if (!fs47.existsSync(selectionPath)) return null;
|
|
81955
|
+
const parsed = JSON.parse(fs47.readFileSync(selectionPath, "utf8"));
|
|
81582
81956
|
if (!Array.isArray(parsed.repos)) return null;
|
|
81583
81957
|
return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
|
|
81584
81958
|
} catch {
|
|
@@ -81588,8 +81962,8 @@ function readSyncSelection() {
|
|
|
81588
81962
|
function writeSyncSelection(repos) {
|
|
81589
81963
|
const selectionPath = getSelectionPath();
|
|
81590
81964
|
const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
|
|
81591
|
-
|
|
81592
|
-
|
|
81965
|
+
fs47.mkdirSync(path54.dirname(selectionPath), { recursive: true });
|
|
81966
|
+
fs47.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
|
|
81593
81967
|
}
|
|
81594
81968
|
function resolveSyncSelection(input) {
|
|
81595
81969
|
const { discovered, stored, forceSelect, isTTY } = input;
|
|
@@ -81696,8 +82070,8 @@ If your browser did not open, paste that URL.
|
|
|
81696
82070
|
}
|
|
81697
82071
|
|
|
81698
82072
|
// src/core/control-unregister.ts
|
|
81699
|
-
var
|
|
81700
|
-
var
|
|
82073
|
+
var fs48 = __toESM(require("fs"));
|
|
82074
|
+
var path55 = __toESM(require("path"));
|
|
81701
82075
|
init_control_repo_path();
|
|
81702
82076
|
init_control_registry();
|
|
81703
82077
|
init_control_config();
|
|
@@ -81707,9 +82081,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
81707
82081
|
const harnessRoot = canonicalizeControlRepoPath(repoPath);
|
|
81708
82082
|
const byPath = /* @__PURE__ */ new Map();
|
|
81709
82083
|
const add = (partial2) => {
|
|
81710
|
-
const resolved =
|
|
82084
|
+
const resolved = path55.resolve(partial2.worktreePath);
|
|
81711
82085
|
if (!resolved || resolved === harnessRoot) return;
|
|
81712
|
-
const exists = partial2.exists ??
|
|
82086
|
+
const exists = partial2.exists ?? fs48.existsSync(resolved);
|
|
81713
82087
|
const prev = byPath.get(resolved);
|
|
81714
82088
|
if (prev) {
|
|
81715
82089
|
byPath.set(resolved, {
|
|
@@ -81756,10 +82130,10 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
81756
82130
|
}
|
|
81757
82131
|
return [...byPath.values()].sort((a2, b3) => a2.agentId - b3.agentId);
|
|
81758
82132
|
}
|
|
81759
|
-
async function
|
|
82133
|
+
async function askYesNo7(question) {
|
|
81760
82134
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
81761
|
-
const
|
|
81762
|
-
const rl =
|
|
82135
|
+
const readline11 = await import("readline");
|
|
82136
|
+
const rl = readline11.createInterface({ input: process.stdin, output: process.stderr });
|
|
81763
82137
|
const answer = await new Promise((resolve47) => {
|
|
81764
82138
|
rl.question(question, resolve47);
|
|
81765
82139
|
});
|
|
@@ -81773,7 +82147,7 @@ async function confirmUnregister(options) {
|
|
|
81773
82147
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
81774
82148
|
throw new Error("Non-interactive terminal \u2014 pass --yes (and optionally --delete-worktrees)");
|
|
81775
82149
|
}
|
|
81776
|
-
const proceed = await
|
|
82150
|
+
const proceed = await askYesNo7("Unregister this repository from Mission Control? [y/N] ");
|
|
81777
82151
|
if (!proceed) return { proceed: false, deleteWorktrees: false };
|
|
81778
82152
|
const existing = options.worktrees.filter((w3) => w3.exists);
|
|
81779
82153
|
if (existing.length === 0) {
|
|
@@ -81785,7 +82159,7 @@ async function confirmUnregister(options) {
|
|
|
81785
82159
|
process.stderr.write(` agent-${wt2.agentId}: ${wt2.worktreePath}${dirty}
|
|
81786
82160
|
`);
|
|
81787
82161
|
}
|
|
81788
|
-
const deleteWorktrees = await
|
|
82162
|
+
const deleteWorktrees = await askYesNo7(
|
|
81789
82163
|
`Also delete ${existing.length} session worktree(s) on disk? [y/N] `
|
|
81790
82164
|
);
|
|
81791
82165
|
return { proceed: true, deleteWorktrees };
|
|
@@ -81823,28 +82197,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
|
|
|
81823
82197
|
trigger: "cli"
|
|
81824
82198
|
});
|
|
81825
82199
|
if (result.code !== 0) {
|
|
81826
|
-
if (
|
|
81827
|
-
|
|
82200
|
+
if (fs48.existsSync(candidate.worktreePath)) {
|
|
82201
|
+
fs48.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
81828
82202
|
}
|
|
81829
82203
|
}
|
|
81830
82204
|
outcomes.push({
|
|
81831
82205
|
path: candidate.worktreePath,
|
|
81832
82206
|
agentId: candidate.agentId,
|
|
81833
|
-
deleted: !
|
|
81834
|
-
error: result.code !== 0 &&
|
|
82207
|
+
deleted: !fs48.existsSync(candidate.worktreePath),
|
|
82208
|
+
error: result.code !== 0 && fs48.existsSync(candidate.worktreePath) ? result.stderr : void 0
|
|
81835
82209
|
});
|
|
81836
82210
|
} catch (err) {
|
|
81837
82211
|
const message = err instanceof Error ? err.message : String(err);
|
|
81838
82212
|
try {
|
|
81839
|
-
if (
|
|
81840
|
-
|
|
82213
|
+
if (fs48.existsSync(candidate.worktreePath)) {
|
|
82214
|
+
fs48.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
81841
82215
|
}
|
|
81842
82216
|
} catch {
|
|
81843
82217
|
}
|
|
81844
82218
|
outcomes.push({
|
|
81845
82219
|
path: candidate.worktreePath,
|
|
81846
82220
|
agentId: candidate.agentId,
|
|
81847
|
-
deleted: !
|
|
82221
|
+
deleted: !fs48.existsSync(candidate.worktreePath),
|
|
81848
82222
|
error: message
|
|
81849
82223
|
});
|
|
81850
82224
|
}
|
|
@@ -81907,16 +82281,16 @@ init_control_config();
|
|
|
81907
82281
|
init_control_registry();
|
|
81908
82282
|
|
|
81909
82283
|
// src/core/harness-scrub.ts
|
|
81910
|
-
var
|
|
81911
|
-
var
|
|
82284
|
+
var fs49 = __toESM(require("fs"));
|
|
82285
|
+
var path56 = __toESM(require("path"));
|
|
81912
82286
|
var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
|
|
81913
82287
|
function scrubLocalHarnessDirs(repoPath) {
|
|
81914
82288
|
const results = [];
|
|
81915
|
-
const resolved =
|
|
81916
|
-
if (!
|
|
82289
|
+
const resolved = path56.resolve(repoPath);
|
|
82290
|
+
if (!fs49.existsSync(resolved)) {
|
|
81917
82291
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
81918
82292
|
results.push({
|
|
81919
|
-
path:
|
|
82293
|
+
path: path56.join(resolved, ".har", directory),
|
|
81920
82294
|
directory,
|
|
81921
82295
|
deleted: false,
|
|
81922
82296
|
error: "repository path does not exist"
|
|
@@ -81925,24 +82299,24 @@ function scrubLocalHarnessDirs(repoPath) {
|
|
|
81925
82299
|
return results;
|
|
81926
82300
|
}
|
|
81927
82301
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
81928
|
-
const target =
|
|
81929
|
-
if (!
|
|
82302
|
+
const target = path56.join(resolved, ".har", directory);
|
|
82303
|
+
if (!fs49.existsSync(target)) {
|
|
81930
82304
|
results.push({ path: target, directory, deleted: true });
|
|
81931
82305
|
continue;
|
|
81932
82306
|
}
|
|
81933
82307
|
try {
|
|
81934
|
-
|
|
82308
|
+
fs49.rmSync(target, { recursive: true, force: true });
|
|
81935
82309
|
results.push({
|
|
81936
82310
|
path: target,
|
|
81937
82311
|
directory,
|
|
81938
|
-
deleted: !
|
|
81939
|
-
error:
|
|
82312
|
+
deleted: !fs49.existsSync(target),
|
|
82313
|
+
error: fs49.existsSync(target) ? "failed to remove directory" : void 0
|
|
81940
82314
|
});
|
|
81941
82315
|
} catch (err) {
|
|
81942
82316
|
results.push({
|
|
81943
82317
|
path: target,
|
|
81944
82318
|
directory,
|
|
81945
|
-
deleted: !
|
|
82319
|
+
deleted: !fs49.existsSync(target),
|
|
81946
82320
|
error: err instanceof Error ? err.message : String(err)
|
|
81947
82321
|
});
|
|
81948
82322
|
}
|
|
@@ -81953,7 +82327,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
81953
82327
|
const results = [];
|
|
81954
82328
|
const seen = /* @__PURE__ */ new Set();
|
|
81955
82329
|
for (const repoPath of repoPaths) {
|
|
81956
|
-
const key =
|
|
82330
|
+
const key = path56.resolve(repoPath);
|
|
81957
82331
|
if (seen.has(key)) continue;
|
|
81958
82332
|
seen.add(key);
|
|
81959
82333
|
results.push(...scrubLocalHarnessDirs(key));
|
|
@@ -81962,10 +82336,10 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
81962
82336
|
}
|
|
81963
82337
|
|
|
81964
82338
|
// src/core/control-reset.ts
|
|
81965
|
-
async function
|
|
82339
|
+
async function askYesNo8(question) {
|
|
81966
82340
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
81967
|
-
const
|
|
81968
|
-
const rl =
|
|
82341
|
+
const readline11 = await import("readline");
|
|
82342
|
+
const rl = readline11.createInterface({ input: process.stdin, output: process.stderr });
|
|
81969
82343
|
const answer = await new Promise((resolve47) => {
|
|
81970
82344
|
rl.question(question, resolve47);
|
|
81971
82345
|
});
|
|
@@ -81977,7 +82351,7 @@ async function confirmControlReset(options) {
|
|
|
81977
82351
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
81978
82352
|
throw new Error("Non-interactive terminal \u2014 pass --yes");
|
|
81979
82353
|
}
|
|
81980
|
-
return
|
|
82354
|
+
return askYesNo8(
|
|
81981
82355
|
`Clear Mission Control data for ${options.repoCount} registered repositor${options.repoCount === 1 ? "y" : "ies"} (and scrub local .har history)? [y/N] `
|
|
81982
82356
|
);
|
|
81983
82357
|
}
|
|
@@ -82209,7 +82583,7 @@ async function handleDown() {
|
|
|
82209
82583
|
return finishCommand(code);
|
|
82210
82584
|
}
|
|
82211
82585
|
async function handleRegister(argv) {
|
|
82212
|
-
const repoPath =
|
|
82586
|
+
const repoPath = path57.resolve(argv.repo);
|
|
82213
82587
|
header("har control register");
|
|
82214
82588
|
info(`Repository: ${repoPath}`);
|
|
82215
82589
|
try {
|
|
@@ -82301,7 +82675,7 @@ async function handleReset(argv) {
|
|
|
82301
82675
|
}
|
|
82302
82676
|
}
|
|
82303
82677
|
async function handleUnregister(argv) {
|
|
82304
|
-
const repoPath =
|
|
82678
|
+
const repoPath = path57.resolve(argv.repo);
|
|
82305
82679
|
const worktrees = listUnregisterWorktreeCandidates(repoPath);
|
|
82306
82680
|
try {
|
|
82307
82681
|
let deleteWorktrees = argv.deleteWorktrees;
|
|
@@ -82480,11 +82854,11 @@ async function handleLogin(argv) {
|
|
|
82480
82854
|
}
|
|
82481
82855
|
|
|
82482
82856
|
// src/cli/commands/hooks.ts
|
|
82483
|
-
var
|
|
82857
|
+
var path59 = __toESM(require("path"));
|
|
82484
82858
|
|
|
82485
82859
|
// src/core/claude-hooks.ts
|
|
82486
|
-
var
|
|
82487
|
-
var
|
|
82860
|
+
var fs50 = __toESM(require("fs"));
|
|
82861
|
+
var path58 = __toESM(require("path"));
|
|
82488
82862
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
82489
82863
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
82490
82864
|
var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
|
|
@@ -82495,8 +82869,8 @@ function isHarGuardEntry(entry) {
|
|
|
82495
82869
|
);
|
|
82496
82870
|
}
|
|
82497
82871
|
function readSettings(settingsPath) {
|
|
82498
|
-
if (!
|
|
82499
|
-
const raw =
|
|
82872
|
+
if (!fs50.existsSync(settingsPath)) return {};
|
|
82873
|
+
const raw = fs50.readFileSync(settingsPath, "utf8").trim();
|
|
82500
82874
|
if (raw === "") return {};
|
|
82501
82875
|
const parsed = JSON.parse(raw);
|
|
82502
82876
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -82505,19 +82879,19 @@ function readSettings(settingsPath) {
|
|
|
82505
82879
|
return parsed;
|
|
82506
82880
|
}
|
|
82507
82881
|
function writeSettings(settingsPath, settings) {
|
|
82508
|
-
|
|
82509
|
-
|
|
82882
|
+
fs50.mkdirSync(path58.dirname(settingsPath), { recursive: true });
|
|
82883
|
+
fs50.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
82510
82884
|
}
|
|
82511
82885
|
function installClaudeGuard(repoPath) {
|
|
82512
82886
|
const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
|
|
82513
82887
|
if (!templatePath) {
|
|
82514
82888
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
82515
82889
|
}
|
|
82516
|
-
const guardScript =
|
|
82517
|
-
|
|
82518
|
-
|
|
82519
|
-
|
|
82520
|
-
const settingsPath =
|
|
82890
|
+
const guardScript = path58.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
82891
|
+
fs50.mkdirSync(path58.dirname(guardScript), { recursive: true });
|
|
82892
|
+
fs50.copyFileSync(templatePath, guardScript);
|
|
82893
|
+
fs50.chmodSync(guardScript, 493);
|
|
82894
|
+
const settingsPath = path58.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
82521
82895
|
const settings = readSettings(settingsPath);
|
|
82522
82896
|
const hooks = settings.hooks ?? {};
|
|
82523
82897
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -82531,15 +82905,15 @@ function installClaudeGuard(repoPath) {
|
|
|
82531
82905
|
}
|
|
82532
82906
|
function uninstallClaudeGuard(repoPath) {
|
|
82533
82907
|
let removed = false;
|
|
82534
|
-
const guardScript =
|
|
82535
|
-
if (
|
|
82536
|
-
|
|
82908
|
+
const guardScript = path58.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
82909
|
+
if (fs50.existsSync(guardScript)) {
|
|
82910
|
+
fs50.rmSync(guardScript);
|
|
82537
82911
|
removed = true;
|
|
82538
|
-
const parent =
|
|
82539
|
-
if (
|
|
82912
|
+
const parent = path58.dirname(guardScript);
|
|
82913
|
+
if (fs50.existsSync(parent) && fs50.readdirSync(parent).length === 0) fs50.rmdirSync(parent);
|
|
82540
82914
|
}
|
|
82541
|
-
const settingsPath =
|
|
82542
|
-
if (
|
|
82915
|
+
const settingsPath = path58.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
82916
|
+
if (fs50.existsSync(settingsPath)) {
|
|
82543
82917
|
const settings = readSettings(settingsPath);
|
|
82544
82918
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
82545
82919
|
if (preToolUse) {
|
|
@@ -82564,8 +82938,8 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
82564
82938
|
return { removed };
|
|
82565
82939
|
}
|
|
82566
82940
|
function claudeGuardInstalled(repoPath) {
|
|
82567
|
-
const settingsPath =
|
|
82568
|
-
if (!
|
|
82941
|
+
const settingsPath = path58.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
82942
|
+
if (!fs50.existsSync(settingsPath)) return false;
|
|
82569
82943
|
try {
|
|
82570
82944
|
const settings = readSettings(settingsPath);
|
|
82571
82945
|
return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
|
|
@@ -82582,7 +82956,7 @@ function repoOption(y2) {
|
|
|
82582
82956
|
function handleInstall2(argv) {
|
|
82583
82957
|
try {
|
|
82584
82958
|
if (argv.claude) {
|
|
82585
|
-
const result2 = installClaudeGuard(
|
|
82959
|
+
const result2 = installClaudeGuard(path59.resolve(argv.repo));
|
|
82586
82960
|
success("Claude Code worktree guard installed.");
|
|
82587
82961
|
info(`Guard script: ${result2.guardScript}`);
|
|
82588
82962
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -82590,7 +82964,7 @@ function handleInstall2(argv) {
|
|
|
82590
82964
|
info("Commit both files so the guard travels with the repo.");
|
|
82591
82965
|
return;
|
|
82592
82966
|
}
|
|
82593
|
-
const result = installHooks({ repoPath:
|
|
82967
|
+
const result = installHooks({ repoPath: path59.resolve(argv.repo), force: argv.force });
|
|
82594
82968
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
82595
82969
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
82596
82970
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -82603,7 +82977,7 @@ function handleInstall2(argv) {
|
|
|
82603
82977
|
function handleUninstall(argv) {
|
|
82604
82978
|
try {
|
|
82605
82979
|
if (argv.claude) {
|
|
82606
|
-
const result2 = uninstallClaudeGuard(
|
|
82980
|
+
const result2 = uninstallClaudeGuard(path59.resolve(argv.repo));
|
|
82607
82981
|
if (result2.removed) {
|
|
82608
82982
|
success("Claude Code worktree guard removed.");
|
|
82609
82983
|
} else {
|
|
@@ -82611,7 +82985,7 @@ function handleUninstall(argv) {
|
|
|
82611
82985
|
}
|
|
82612
82986
|
return;
|
|
82613
82987
|
}
|
|
82614
|
-
const result = uninstallHooks(
|
|
82988
|
+
const result = uninstallHooks(path59.resolve(argv.repo));
|
|
82615
82989
|
if (result.removed) {
|
|
82616
82990
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
82617
82991
|
} else {
|
|
@@ -82624,7 +82998,7 @@ function handleUninstall(argv) {
|
|
|
82624
82998
|
}
|
|
82625
82999
|
function handleStatus2(argv) {
|
|
82626
83000
|
try {
|
|
82627
|
-
const status = getHooksStatus(
|
|
83001
|
+
const status = getHooksStatus(path59.resolve(argv.repo));
|
|
82628
83002
|
if (argv.json) {
|
|
82629
83003
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
82630
83004
|
`);
|
|
@@ -82642,7 +83016,7 @@ function handleStatus2(argv) {
|
|
|
82642
83016
|
);
|
|
82643
83017
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
82644
83018
|
info(
|
|
82645
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
83019
|
+
`Claude guard: ${claudeGuardInstalled(path59.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
82646
83020
|
);
|
|
82647
83021
|
} catch (err) {
|
|
82648
83022
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -82903,10 +83277,10 @@ function assignProp(target, prop, value) {
|
|
|
82903
83277
|
configurable: true
|
|
82904
83278
|
});
|
|
82905
83279
|
}
|
|
82906
|
-
function getElementAtPath(obj,
|
|
82907
|
-
if (!
|
|
83280
|
+
function getElementAtPath(obj, path64) {
|
|
83281
|
+
if (!path64)
|
|
82908
83282
|
return obj;
|
|
82909
|
-
return
|
|
83283
|
+
return path64.reduce((acc, key) => acc?.[key], obj);
|
|
82910
83284
|
}
|
|
82911
83285
|
function promiseAllObject(promisesObj) {
|
|
82912
83286
|
const keys = Object.keys(promisesObj);
|
|
@@ -83226,11 +83600,11 @@ function aborted(x2, startIndex = 0) {
|
|
|
83226
83600
|
}
|
|
83227
83601
|
return false;
|
|
83228
83602
|
}
|
|
83229
|
-
function prefixIssues(
|
|
83603
|
+
function prefixIssues(path64, issues) {
|
|
83230
83604
|
return issues.map((iss) => {
|
|
83231
83605
|
var _a3;
|
|
83232
83606
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
83233
|
-
iss.path.unshift(
|
|
83607
|
+
iss.path.unshift(path64);
|
|
83234
83608
|
return iss;
|
|
83235
83609
|
});
|
|
83236
83610
|
}
|
|
@@ -89704,7 +90078,7 @@ var Server = class extends Protocol {
|
|
|
89704
90078
|
};
|
|
89705
90079
|
|
|
89706
90080
|
// src/mcp/server.ts
|
|
89707
|
-
var
|
|
90081
|
+
var path60 = __toESM(require("path"));
|
|
89708
90082
|
|
|
89709
90083
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
89710
90084
|
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
@@ -90345,7 +90719,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
90345
90719
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
90346
90720
|
const result = await startControlAndSync({
|
|
90347
90721
|
detach: input.detach,
|
|
90348
|
-
cwd:
|
|
90722
|
+
cwd: path60.resolve(input.repo)
|
|
90349
90723
|
});
|
|
90350
90724
|
if (result.code !== 0) {
|
|
90351
90725
|
return {
|
|
@@ -90409,11 +90783,11 @@ var mcpCommand = {
|
|
|
90409
90783
|
};
|
|
90410
90784
|
|
|
90411
90785
|
// src/cli/commands/onboard.ts
|
|
90412
|
-
var
|
|
90786
|
+
var path62 = __toESM(require("path"));
|
|
90413
90787
|
init_stages();
|
|
90414
90788
|
|
|
90415
90789
|
// src/core/onboarding.ts
|
|
90416
|
-
var
|
|
90790
|
+
var path61 = __toESM(require("path"));
|
|
90417
90791
|
init_control_config();
|
|
90418
90792
|
init_control_sync();
|
|
90419
90793
|
init_otel_hooks();
|
|
@@ -90548,7 +90922,7 @@ async function defaultEnsureControl(options) {
|
|
|
90548
90922
|
return { started: true, apiUrl: result.apiUrl };
|
|
90549
90923
|
}
|
|
90550
90924
|
async function runOnboarding(options, deps = {}) {
|
|
90551
|
-
const repoPath =
|
|
90925
|
+
const repoPath = path61.resolve(options.repoPath);
|
|
90552
90926
|
const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
|
|
90553
90927
|
const ensureControl = deps.ensureControl ?? defaultEnsureControl;
|
|
90554
90928
|
const init = deps.initHarness ?? initHarness;
|
|
@@ -90737,7 +91111,7 @@ async function promptChoices(args) {
|
|
|
90737
91111
|
};
|
|
90738
91112
|
}
|
|
90739
91113
|
const pluginChoices = listPluginChoices();
|
|
90740
|
-
const repoPath =
|
|
91114
|
+
const repoPath = path62.resolve(args.repo);
|
|
90741
91115
|
const alreadyPresent = harnessExists(repoPath);
|
|
90742
91116
|
const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
|
|
90743
91117
|
const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
|
|
@@ -90854,7 +91228,7 @@ function printSummary(result) {
|
|
|
90854
91228
|
console.error("");
|
|
90855
91229
|
}
|
|
90856
91230
|
async function handleOnboard(argv) {
|
|
90857
|
-
const repoPath =
|
|
91231
|
+
const repoPath = path62.resolve(argv.repo);
|
|
90858
91232
|
header("har onboard");
|
|
90859
91233
|
info(`Repository: ${repoPath}`);
|
|
90860
91234
|
try {
|
|
@@ -90884,18 +91258,13 @@ async function handleOnboard(argv) {
|
|
|
90884
91258
|
...onboarding.commitGate,
|
|
90885
91259
|
autoYes: argv.yes
|
|
90886
91260
|
});
|
|
90887
|
-
await
|
|
91261
|
+
await applyAgentIntegrations({
|
|
90888
91262
|
repoPath,
|
|
90889
|
-
|
|
90890
|
-
autoYes: argv.yes,
|
|
90891
|
-
mode: result.harnessInitialized ? "init" : "maintain"
|
|
90892
|
-
});
|
|
90893
|
-
await handleAgentSkills({
|
|
90894
|
-
repoPath,
|
|
90895
|
-
...onboarding.agentSkills,
|
|
91263
|
+
mode: result.harnessInitialized ? "init" : "maintain",
|
|
90896
91264
|
autoYes: argv.yes,
|
|
90897
91265
|
force: argv.force,
|
|
90898
|
-
|
|
91266
|
+
cursorRule: onboarding.cursorRule,
|
|
91267
|
+
...onboarding.agentSkills
|
|
90899
91268
|
});
|
|
90900
91269
|
}
|
|
90901
91270
|
if (harnessExists(repoPath)) {
|
|
@@ -91090,7 +91459,7 @@ var preferencesCommand = {
|
|
|
91090
91459
|
};
|
|
91091
91460
|
|
|
91092
91461
|
// src/cli/commands/telemetry.ts
|
|
91093
|
-
var
|
|
91462
|
+
var path63 = __toESM(require("path"));
|
|
91094
91463
|
init_control_config();
|
|
91095
91464
|
init_control_sync();
|
|
91096
91465
|
init_manifest();
|
|
@@ -91183,7 +91552,7 @@ async function handleOff() {
|
|
|
91183
91552
|
info("Mission Control will not auto-start. Existing usage rows are kept.");
|
|
91184
91553
|
}
|
|
91185
91554
|
async function handleWriteEnv(argv) {
|
|
91186
|
-
const repoPath =
|
|
91555
|
+
const repoPath = path63.resolve(argv.repo);
|
|
91187
91556
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
91188
91557
|
const session = readSlotRegistry(harnessRoot, argv.agentId);
|
|
91189
91558
|
const workDir = argv.workDir ?? session?.workDir ?? repoPath;
|
|
@@ -91195,7 +91564,7 @@ async function handleWriteEnv(argv) {
|
|
|
91195
91564
|
suffix,
|
|
91196
91565
|
createdAt: session?.createdAt
|
|
91197
91566
|
});
|
|
91198
|
-
const envFile = argv.envFile ??
|
|
91567
|
+
const envFile = argv.envFile ?? path63.join(workDir, `.env.agent.${argv.agentId}`);
|
|
91199
91568
|
const attrs = {
|
|
91200
91569
|
sessionKey,
|
|
91201
91570
|
agentId: argv.agentId,
|
|
@@ -91211,7 +91580,7 @@ async function handleWriteEnv(argv) {
|
|
|
91211
91580
|
success(`Wrote session attribution to ${envFile}`);
|
|
91212
91581
|
}
|
|
91213
91582
|
function handlePrintEnv(argv) {
|
|
91214
|
-
const repoPath =
|
|
91583
|
+
const repoPath = path63.resolve(argv.repo);
|
|
91215
91584
|
const workDir = argv.workDir ?? repoPath;
|
|
91216
91585
|
const sessionKey = buildSessionKey({
|
|
91217
91586
|
branch: argv.branch,
|