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