@osfactory/har 0.10.0 → 0.11.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 +12 -2
- package/dist/index.js +563 -365
- package/dist/templates/agent-skills/har-maintain.md +2 -0
- package/dist/templates/agent-skills/setup-har.md +13 -2
- package/dist/templates/har-boilerplate/CLAUDE.agent.md +4 -2
- package/dist/templates/har-boilerplate/STAGES.md +91 -0
- package/dist/templates/har-boilerplate/agent-slot.sh +35 -6
- package/dist/templates/har-boilerplate/stages/README.sh +7 -5
- package/dist/templates/har-boilerplate/verify.sh +9 -2
- package/dist/templates/har-boilerplate-cli/CLAUDE.agent.md +3 -1
- package/dist/templates/har-boilerplate-cli/STAGES.md +91 -0
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +35 -6
- package/dist/templates/har-boilerplate-cli/stages/README.sh +7 -5
- package/dist/templates/har-boilerplate-cli/verify.sh +9 -2
- package/dist/templates/har-boilerplate-ios/CLAUDE.agent.md +2 -0
- package/dist/templates/har-boilerplate-ios/STAGES.md +91 -0
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +35 -6
- package/dist/templates/har-boilerplate-ios/stages/README.sh +6 -7
- package/dist/templates/har-boilerplate-ios/verify.sh +9 -3
- package/dist/templates/stage-templates/custom-stage-skeleton.sh +65 -0
- package/dist/templates/stage-templates/playwright/template.manifest.json +9 -1
- package/dist/templates/stage-templates/rocketsim/template.manifest.json +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -765,14 +765,14 @@ var require_url_state_machine = __commonJS({
|
|
|
765
765
|
return url.replace(/\u0009|\u000A|\u000D/g, "");
|
|
766
766
|
}
|
|
767
767
|
function shortenPath(url) {
|
|
768
|
-
const
|
|
769
|
-
if (
|
|
768
|
+
const path41 = url.path;
|
|
769
|
+
if (path41.length === 0) {
|
|
770
770
|
return;
|
|
771
771
|
}
|
|
772
|
-
if (url.scheme === "file" &&
|
|
772
|
+
if (url.scheme === "file" && path41.length === 1 && isNormalizedWindowsDriveLetter(path41[0])) {
|
|
773
773
|
return;
|
|
774
774
|
}
|
|
775
|
-
|
|
775
|
+
path41.pop();
|
|
776
776
|
}
|
|
777
777
|
function includesCredentials(url) {
|
|
778
778
|
return url.username !== "" || url.password !== "";
|
|
@@ -2092,7 +2092,7 @@ var require_lib2 = __commonJS({
|
|
|
2092
2092
|
let accum = [];
|
|
2093
2093
|
let accumBytes = 0;
|
|
2094
2094
|
let abort = false;
|
|
2095
|
-
return new Body.Promise(function(
|
|
2095
|
+
return new Body.Promise(function(resolve28, reject) {
|
|
2096
2096
|
let resTimeout;
|
|
2097
2097
|
if (_this4.timeout) {
|
|
2098
2098
|
resTimeout = setTimeout(function() {
|
|
@@ -2126,7 +2126,7 @@ var require_lib2 = __commonJS({
|
|
|
2126
2126
|
}
|
|
2127
2127
|
clearTimeout(resTimeout);
|
|
2128
2128
|
try {
|
|
2129
|
-
|
|
2129
|
+
resolve28(Buffer.concat(accum, accumBytes));
|
|
2130
2130
|
} catch (err) {
|
|
2131
2131
|
reject(new FetchError(`Could not create Buffer from response body for ${_this4.url}: ${err.message}`, "system", err));
|
|
2132
2132
|
}
|
|
@@ -2801,7 +2801,7 @@ var require_lib2 = __commonJS({
|
|
|
2801
2801
|
throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
|
|
2802
2802
|
}
|
|
2803
2803
|
Body.Promise = fetch3.Promise;
|
|
2804
|
-
return new fetch3.Promise(function(
|
|
2804
|
+
return new fetch3.Promise(function(resolve28, reject) {
|
|
2805
2805
|
const request = new Request3(url, opts);
|
|
2806
2806
|
const options = getNodeRequestOptions(request);
|
|
2807
2807
|
const send = (options.protocol === "https:" ? https : http).request;
|
|
@@ -2934,7 +2934,7 @@ var require_lib2 = __commonJS({
|
|
|
2934
2934
|
requestOpts.body = void 0;
|
|
2935
2935
|
requestOpts.headers.delete("content-length");
|
|
2936
2936
|
}
|
|
2937
|
-
|
|
2937
|
+
resolve28(fetch3(new Request3(locationURL, requestOpts)));
|
|
2938
2938
|
finalize();
|
|
2939
2939
|
return;
|
|
2940
2940
|
}
|
|
@@ -2955,7 +2955,7 @@ var require_lib2 = __commonJS({
|
|
|
2955
2955
|
const codings = headers.get("Content-Encoding");
|
|
2956
2956
|
if (!request.compress || request.method === "HEAD" || codings === null || res.statusCode === 204 || res.statusCode === 304) {
|
|
2957
2957
|
response = new Response3(body, response_options);
|
|
2958
|
-
|
|
2958
|
+
resolve28(response);
|
|
2959
2959
|
return;
|
|
2960
2960
|
}
|
|
2961
2961
|
const zlibOptions = {
|
|
@@ -2965,7 +2965,7 @@ var require_lib2 = __commonJS({
|
|
|
2965
2965
|
if (codings == "gzip" || codings == "x-gzip") {
|
|
2966
2966
|
body = body.pipe(zlib.createGunzip(zlibOptions));
|
|
2967
2967
|
response = new Response3(body, response_options);
|
|
2968
|
-
|
|
2968
|
+
resolve28(response);
|
|
2969
2969
|
return;
|
|
2970
2970
|
}
|
|
2971
2971
|
if (codings == "deflate" || codings == "x-deflate") {
|
|
@@ -2977,12 +2977,12 @@ var require_lib2 = __commonJS({
|
|
|
2977
2977
|
body = body.pipe(zlib.createInflateRaw());
|
|
2978
2978
|
}
|
|
2979
2979
|
response = new Response3(body, response_options);
|
|
2980
|
-
|
|
2980
|
+
resolve28(response);
|
|
2981
2981
|
});
|
|
2982
2982
|
raw.on("end", function() {
|
|
2983
2983
|
if (!response) {
|
|
2984
2984
|
response = new Response3(body, response_options);
|
|
2985
|
-
|
|
2985
|
+
resolve28(response);
|
|
2986
2986
|
}
|
|
2987
2987
|
});
|
|
2988
2988
|
return;
|
|
@@ -2990,11 +2990,11 @@ var require_lib2 = __commonJS({
|
|
|
2990
2990
|
if (codings == "br" && typeof zlib.createBrotliDecompress === "function") {
|
|
2991
2991
|
body = body.pipe(zlib.createBrotliDecompress());
|
|
2992
2992
|
response = new Response3(body, response_options);
|
|
2993
|
-
|
|
2993
|
+
resolve28(response);
|
|
2994
2994
|
return;
|
|
2995
2995
|
}
|
|
2996
2996
|
response = new Response3(body, response_options);
|
|
2997
|
-
|
|
2997
|
+
resolve28(response);
|
|
2998
2998
|
});
|
|
2999
2999
|
writeToStream(req, request);
|
|
3000
3000
|
});
|
|
@@ -6351,14 +6351,14 @@ __export(fileFromPath_exports, {
|
|
|
6351
6351
|
fileFromPathSync: () => fileFromPathSync,
|
|
6352
6352
|
isFile: () => isFile
|
|
6353
6353
|
});
|
|
6354
|
-
function createFileFromPath(
|
|
6354
|
+
function createFileFromPath(path41, { mtimeMs, size }, filenameOrOptions, options = {}) {
|
|
6355
6355
|
let filename;
|
|
6356
6356
|
if (isPlainObject_default2(filenameOrOptions)) {
|
|
6357
6357
|
[options, filename] = [filenameOrOptions, void 0];
|
|
6358
6358
|
} else {
|
|
6359
6359
|
filename = filenameOrOptions;
|
|
6360
6360
|
}
|
|
6361
|
-
const file = new FileFromPath({ path:
|
|
6361
|
+
const file = new FileFromPath({ path: path41, size, lastModified: mtimeMs });
|
|
6362
6362
|
if (!filename) {
|
|
6363
6363
|
filename = file.name;
|
|
6364
6364
|
}
|
|
@@ -6367,13 +6367,13 @@ function createFileFromPath(path40, { mtimeMs, size }, filenameOrOptions, option
|
|
|
6367
6367
|
lastModified: file.lastModified
|
|
6368
6368
|
});
|
|
6369
6369
|
}
|
|
6370
|
-
function fileFromPathSync(
|
|
6371
|
-
const stats = (0, import_fs5.statSync)(
|
|
6372
|
-
return createFileFromPath(
|
|
6370
|
+
function fileFromPathSync(path41, filenameOrOptions, options = {}) {
|
|
6371
|
+
const stats = (0, import_fs5.statSync)(path41);
|
|
6372
|
+
return createFileFromPath(path41, stats, filenameOrOptions, options);
|
|
6373
6373
|
}
|
|
6374
|
-
async function fileFromPath2(
|
|
6375
|
-
const stats = await import_fs5.promises.stat(
|
|
6376
|
-
return createFileFromPath(
|
|
6374
|
+
async function fileFromPath2(path41, filenameOrOptions, options) {
|
|
6375
|
+
const stats = await import_fs5.promises.stat(path41);
|
|
6376
|
+
return createFileFromPath(path41, stats, filenameOrOptions, options);
|
|
6377
6377
|
}
|
|
6378
6378
|
var import_fs5, import_path5, import_node_domexception, __classPrivateFieldSet5, __classPrivateFieldGet6, _FileFromPath_path, _FileFromPath_start, MESSAGE, FileFromPath;
|
|
6379
6379
|
var init_fileFromPath = __esm({
|
|
@@ -9384,7 +9384,7 @@ var require_compile = __commonJS({
|
|
|
9384
9384
|
const schOrFunc = root.refs[ref];
|
|
9385
9385
|
if (schOrFunc)
|
|
9386
9386
|
return schOrFunc;
|
|
9387
|
-
let _sch =
|
|
9387
|
+
let _sch = resolve28.call(this, root, ref);
|
|
9388
9388
|
if (_sch === void 0) {
|
|
9389
9389
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
9390
9390
|
const { schemaId } = this.opts;
|
|
@@ -9411,7 +9411,7 @@ var require_compile = __commonJS({
|
|
|
9411
9411
|
function sameSchemaEnv(s1, s2) {
|
|
9412
9412
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
9413
9413
|
}
|
|
9414
|
-
function
|
|
9414
|
+
function resolve28(root, ref) {
|
|
9415
9415
|
let sch;
|
|
9416
9416
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
9417
9417
|
ref = sch;
|
|
@@ -9629,8 +9629,8 @@ var require_utils2 = __commonJS({
|
|
|
9629
9629
|
}
|
|
9630
9630
|
return ind;
|
|
9631
9631
|
}
|
|
9632
|
-
function removeDotSegments(
|
|
9633
|
-
let input =
|
|
9632
|
+
function removeDotSegments(path41) {
|
|
9633
|
+
let input = path41;
|
|
9634
9634
|
const output = [];
|
|
9635
9635
|
let nextSlash = -1;
|
|
9636
9636
|
let len = 0;
|
|
@@ -9882,8 +9882,8 @@ var require_schemes = __commonJS({
|
|
|
9882
9882
|
wsComponent.secure = void 0;
|
|
9883
9883
|
}
|
|
9884
9884
|
if (wsComponent.resourceName) {
|
|
9885
|
-
const [
|
|
9886
|
-
wsComponent.path =
|
|
9885
|
+
const [path41, query] = wsComponent.resourceName.split("?");
|
|
9886
|
+
wsComponent.path = path41 && path41 !== "/" ? path41 : void 0;
|
|
9887
9887
|
wsComponent.query = query;
|
|
9888
9888
|
wsComponent.resourceName = void 0;
|
|
9889
9889
|
}
|
|
@@ -10042,7 +10042,7 @@ var require_fast_uri = __commonJS({
|
|
|
10042
10042
|
}
|
|
10043
10043
|
return uri;
|
|
10044
10044
|
}
|
|
10045
|
-
function
|
|
10045
|
+
function resolve28(baseURI, relativeURI, options) {
|
|
10046
10046
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
10047
10047
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
10048
10048
|
schemelessOptions.skipEscape = true;
|
|
@@ -10300,7 +10300,7 @@ var require_fast_uri = __commonJS({
|
|
|
10300
10300
|
var fastUri = {
|
|
10301
10301
|
SCHEMES,
|
|
10302
10302
|
normalize: normalize3,
|
|
10303
|
-
resolve:
|
|
10303
|
+
resolve: resolve28,
|
|
10304
10304
|
resolveComponent,
|
|
10305
10305
|
equal,
|
|
10306
10306
|
serialize,
|
|
@@ -13276,12 +13276,12 @@ var require_dist = __commonJS({
|
|
|
13276
13276
|
throw new Error(`Unknown format "${name}"`);
|
|
13277
13277
|
return f2;
|
|
13278
13278
|
};
|
|
13279
|
-
function addFormats(ajv, list,
|
|
13279
|
+
function addFormats(ajv, list, fs35, exportName) {
|
|
13280
13280
|
var _a3;
|
|
13281
13281
|
var _b2;
|
|
13282
13282
|
(_a3 = (_b2 = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
13283
13283
|
for (const f2 of list)
|
|
13284
|
-
ajv.addFormat(f2,
|
|
13284
|
+
ajv.addFormat(f2, fs35[f2]);
|
|
13285
13285
|
}
|
|
13286
13286
|
module2.exports = exports2 = formatsPlugin;
|
|
13287
13287
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -14565,11 +14565,11 @@ var parser = new YargsParser({
|
|
|
14565
14565
|
resolve: import_path2.resolve,
|
|
14566
14566
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
14567
14567
|
// we can exercise all the lines below:
|
|
14568
|
-
require: (
|
|
14568
|
+
require: (path41) => {
|
|
14569
14569
|
if (typeof require !== "undefined") {
|
|
14570
|
-
return require(
|
|
14571
|
-
} else if (
|
|
14572
|
-
return JSON.parse((0, import_fs2.readFileSync)(
|
|
14570
|
+
return require(path41);
|
|
14571
|
+
} else if (path41.match(/\.json$/)) {
|
|
14572
|
+
return JSON.parse((0, import_fs2.readFileSync)(path41, "utf8"));
|
|
14573
14573
|
} else {
|
|
14574
14574
|
throw Error("only .json config files are supported in ESM");
|
|
14575
14575
|
}
|
|
@@ -17095,12 +17095,12 @@ var YargsInstance = class {
|
|
|
17095
17095
|
async getCompletion(args, done) {
|
|
17096
17096
|
argsert("<array> [function]", [args, done], arguments.length);
|
|
17097
17097
|
if (!done) {
|
|
17098
|
-
return new Promise((
|
|
17098
|
+
return new Promise((resolve28, reject) => {
|
|
17099
17099
|
__classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
|
|
17100
17100
|
if (err)
|
|
17101
17101
|
reject(err);
|
|
17102
17102
|
else
|
|
17103
|
-
|
|
17103
|
+
resolve28(completions);
|
|
17104
17104
|
});
|
|
17105
17105
|
});
|
|
17106
17106
|
} else {
|
|
@@ -19250,8 +19250,8 @@ function getErrorMap() {
|
|
|
19250
19250
|
|
|
19251
19251
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
19252
19252
|
var makeIssue = (params) => {
|
|
19253
|
-
const { data, path:
|
|
19254
|
-
const fullPath = [...
|
|
19253
|
+
const { data, path: path41, errorMaps, issueData } = params;
|
|
19254
|
+
const fullPath = [...path41, ...issueData.path || []];
|
|
19255
19255
|
const fullIssue = {
|
|
19256
19256
|
...issueData,
|
|
19257
19257
|
path: fullPath
|
|
@@ -19367,11 +19367,11 @@ var errorUtil;
|
|
|
19367
19367
|
|
|
19368
19368
|
// node_modules/zod/v3/types.js
|
|
19369
19369
|
var ParseInputLazyPath = class {
|
|
19370
|
-
constructor(parent, value,
|
|
19370
|
+
constructor(parent, value, path41, key) {
|
|
19371
19371
|
this._cachedPath = [];
|
|
19372
19372
|
this.parent = parent;
|
|
19373
19373
|
this.data = value;
|
|
19374
|
-
this._path =
|
|
19374
|
+
this._path = path41;
|
|
19375
19375
|
this._key = key;
|
|
19376
19376
|
}
|
|
19377
19377
|
get path() {
|
|
@@ -23371,16 +23371,16 @@ async function handleAgentSkills(options) {
|
|
|
23371
23371
|
}
|
|
23372
23372
|
async function askYesNo(question) {
|
|
23373
23373
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
23374
|
-
return new Promise((
|
|
23374
|
+
return new Promise((resolve28) => {
|
|
23375
23375
|
process.stderr.write(`${question} `);
|
|
23376
23376
|
rl.once("line", (answer) => {
|
|
23377
23377
|
rl.close();
|
|
23378
23378
|
const trimmed = answer.trim();
|
|
23379
23379
|
if (trimmed === "") {
|
|
23380
|
-
|
|
23380
|
+
resolve28(true);
|
|
23381
23381
|
return;
|
|
23382
23382
|
}
|
|
23383
|
-
|
|
23383
|
+
resolve28(/^y(es)?$/i.test(trimmed));
|
|
23384
23384
|
});
|
|
23385
23385
|
});
|
|
23386
23386
|
}
|
|
@@ -23459,7 +23459,7 @@ function handleRemove(argv) {
|
|
|
23459
23459
|
}
|
|
23460
23460
|
|
|
23461
23461
|
// src/cli/commands/env.ts
|
|
23462
|
-
var
|
|
23462
|
+
var path34 = __toESM(require("path"));
|
|
23463
23463
|
|
|
23464
23464
|
// src/core/harness.ts
|
|
23465
23465
|
var fs19 = __toESM(require("fs"));
|
|
@@ -23965,13 +23965,13 @@ var MultipartBody = class {
|
|
|
23965
23965
|
// node_modules/@anthropic-ai/sdk/_shims/node-runtime.mjs
|
|
23966
23966
|
var import_web = require("node:stream/web");
|
|
23967
23967
|
var fileFromPathWarned = false;
|
|
23968
|
-
async function fileFromPath3(
|
|
23968
|
+
async function fileFromPath3(path41, ...args) {
|
|
23969
23969
|
const { fileFromPath: _fileFromPath } = await Promise.resolve().then(() => (init_fileFromPath(), fileFromPath_exports));
|
|
23970
23970
|
if (!fileFromPathWarned) {
|
|
23971
|
-
console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(
|
|
23971
|
+
console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path41)}) instead`);
|
|
23972
23972
|
fileFromPathWarned = true;
|
|
23973
23973
|
}
|
|
23974
|
-
return await _fileFromPath(
|
|
23974
|
+
return await _fileFromPath(path41, ...args);
|
|
23975
23975
|
}
|
|
23976
23976
|
var defaultHttpAgent = new import_agentkeepalive.default({ keepAlive: true, timeout: 5 * 60 * 1e3 });
|
|
23977
23977
|
var defaultHttpsAgent = new import_agentkeepalive.default.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1e3 });
|
|
@@ -24467,8 +24467,8 @@ async function defaultParseResponse(props) {
|
|
|
24467
24467
|
}
|
|
24468
24468
|
var APIPromise = class _APIPromise extends Promise {
|
|
24469
24469
|
constructor(responsePromise, parseResponse = defaultParseResponse) {
|
|
24470
|
-
super((
|
|
24471
|
-
|
|
24470
|
+
super((resolve28) => {
|
|
24471
|
+
resolve28(null);
|
|
24472
24472
|
});
|
|
24473
24473
|
this.responsePromise = responsePromise;
|
|
24474
24474
|
this.parseResponse = parseResponse;
|
|
@@ -24568,29 +24568,29 @@ var APIClient = class {
|
|
|
24568
24568
|
defaultIdempotencyKey() {
|
|
24569
24569
|
return `stainless-node-retry-${uuid4()}`;
|
|
24570
24570
|
}
|
|
24571
|
-
get(
|
|
24572
|
-
return this.methodRequest("get",
|
|
24571
|
+
get(path41, opts) {
|
|
24572
|
+
return this.methodRequest("get", path41, opts);
|
|
24573
24573
|
}
|
|
24574
|
-
post(
|
|
24575
|
-
return this.methodRequest("post",
|
|
24574
|
+
post(path41, opts) {
|
|
24575
|
+
return this.methodRequest("post", path41, opts);
|
|
24576
24576
|
}
|
|
24577
|
-
patch(
|
|
24578
|
-
return this.methodRequest("patch",
|
|
24577
|
+
patch(path41, opts) {
|
|
24578
|
+
return this.methodRequest("patch", path41, opts);
|
|
24579
24579
|
}
|
|
24580
|
-
put(
|
|
24581
|
-
return this.methodRequest("put",
|
|
24580
|
+
put(path41, opts) {
|
|
24581
|
+
return this.methodRequest("put", path41, opts);
|
|
24582
24582
|
}
|
|
24583
|
-
delete(
|
|
24584
|
-
return this.methodRequest("delete",
|
|
24583
|
+
delete(path41, opts) {
|
|
24584
|
+
return this.methodRequest("delete", path41, opts);
|
|
24585
24585
|
}
|
|
24586
|
-
methodRequest(method,
|
|
24586
|
+
methodRequest(method, path41, opts) {
|
|
24587
24587
|
return this.request(Promise.resolve(opts).then(async (opts2) => {
|
|
24588
24588
|
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;
|
|
24589
|
-
return { method, path:
|
|
24589
|
+
return { method, path: path41, ...opts2, body };
|
|
24590
24590
|
}));
|
|
24591
24591
|
}
|
|
24592
|
-
getAPIList(
|
|
24593
|
-
return this.requestAPIList(Page, { method: "get", path:
|
|
24592
|
+
getAPIList(path41, Page, opts) {
|
|
24593
|
+
return this.requestAPIList(Page, { method: "get", path: path41, ...opts });
|
|
24594
24594
|
}
|
|
24595
24595
|
calculateContentLength(body) {
|
|
24596
24596
|
if (typeof body === "string") {
|
|
@@ -24608,10 +24608,10 @@ var APIClient = class {
|
|
|
24608
24608
|
return null;
|
|
24609
24609
|
}
|
|
24610
24610
|
buildRequest(options) {
|
|
24611
|
-
const { method, path:
|
|
24611
|
+
const { method, path: path41, query, headers = {} } = options;
|
|
24612
24612
|
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;
|
|
24613
24613
|
const contentLength = this.calculateContentLength(body);
|
|
24614
|
-
const url = this.buildURL(
|
|
24614
|
+
const url = this.buildURL(path41, query);
|
|
24615
24615
|
if ("timeout" in options)
|
|
24616
24616
|
validatePositiveInteger("timeout", options.timeout);
|
|
24617
24617
|
const timeout = options.timeout ?? this.timeout;
|
|
@@ -24720,8 +24720,8 @@ var APIClient = class {
|
|
|
24720
24720
|
const request = this.makeRequest(options, null);
|
|
24721
24721
|
return new PagePromise(this, request, Page);
|
|
24722
24722
|
}
|
|
24723
|
-
buildURL(
|
|
24724
|
-
const url = isAbsoluteURL(
|
|
24723
|
+
buildURL(path41, query) {
|
|
24724
|
+
const url = isAbsoluteURL(path41) ? new URL(path41) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path41.startsWith("/") ? path41.slice(1) : path41));
|
|
24725
24725
|
const defaultQuery = this.defaultQuery();
|
|
24726
24726
|
if (!isEmptyObj(defaultQuery)) {
|
|
24727
24727
|
query = { ...defaultQuery, ...query };
|
|
@@ -25006,7 +25006,7 @@ var startsWithSchemeRegexp = new RegExp("^(?:[a-z]+:)?//", "i");
|
|
|
25006
25006
|
var isAbsoluteURL = (url) => {
|
|
25007
25007
|
return startsWithSchemeRegexp.test(url);
|
|
25008
25008
|
};
|
|
25009
|
-
var sleep = (ms) => new Promise((
|
|
25009
|
+
var sleep = (ms) => new Promise((resolve28) => setTimeout(resolve28, ms));
|
|
25010
25010
|
var validatePositiveInteger = (name, n2) => {
|
|
25011
25011
|
if (typeof n2 !== "number" || !Number.isInteger(n2)) {
|
|
25012
25012
|
throw new AnthropicError(`${name} must be an integer`);
|
|
@@ -25497,12 +25497,12 @@ var PromptCachingBetaMessageStream = class _PromptCachingBetaMessageStream {
|
|
|
25497
25497
|
}
|
|
25498
25498
|
return this._emit("error", new AnthropicError(String(error3)));
|
|
25499
25499
|
});
|
|
25500
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_connectedPromise, new Promise((
|
|
25501
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveConnectedPromise,
|
|
25500
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_connectedPromise, new Promise((resolve28, reject) => {
|
|
25501
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveConnectedPromise, resolve28, "f");
|
|
25502
25502
|
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_rejectConnectedPromise, reject, "f");
|
|
25503
25503
|
}), "f");
|
|
25504
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_endPromise, new Promise((
|
|
25505
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveEndPromise,
|
|
25504
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_endPromise, new Promise((resolve28, reject) => {
|
|
25505
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveEndPromise, resolve28, "f");
|
|
25506
25506
|
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_rejectEndPromise, reject, "f");
|
|
25507
25507
|
}), "f");
|
|
25508
25508
|
__classPrivateFieldGet8(this, _PromptCachingBetaMessageStream_connectedPromise, "f").catch(() => {
|
|
@@ -25631,11 +25631,11 @@ var PromptCachingBetaMessageStream = class _PromptCachingBetaMessageStream {
|
|
|
25631
25631
|
* const message = await stream.emitted('message') // rejects if the stream errors
|
|
25632
25632
|
*/
|
|
25633
25633
|
emitted(event) {
|
|
25634
|
-
return new Promise((
|
|
25634
|
+
return new Promise((resolve28, reject) => {
|
|
25635
25635
|
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_catchingPromiseCreated, true, "f");
|
|
25636
25636
|
if (event !== "error")
|
|
25637
25637
|
this.once("error", reject);
|
|
25638
|
-
this.once(event,
|
|
25638
|
+
this.once(event, resolve28);
|
|
25639
25639
|
});
|
|
25640
25640
|
}
|
|
25641
25641
|
async done() {
|
|
@@ -25862,7 +25862,7 @@ var PromptCachingBetaMessageStream = class _PromptCachingBetaMessageStream {
|
|
|
25862
25862
|
if (done) {
|
|
25863
25863
|
return { value: void 0, done: true };
|
|
25864
25864
|
}
|
|
25865
|
-
return new Promise((
|
|
25865
|
+
return new Promise((resolve28, reject) => readQueue.push({ resolve: resolve28, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
|
|
25866
25866
|
}
|
|
25867
25867
|
const chunk = pushQueue.shift();
|
|
25868
25868
|
return { value: chunk, done: false };
|
|
@@ -26010,12 +26010,12 @@ var MessageStream = class _MessageStream {
|
|
|
26010
26010
|
}
|
|
26011
26011
|
return this._emit("error", new AnthropicError(String(error3)));
|
|
26012
26012
|
});
|
|
26013
|
-
__classPrivateFieldSet8(this, _MessageStream_connectedPromise, new Promise((
|
|
26014
|
-
__classPrivateFieldSet8(this, _MessageStream_resolveConnectedPromise,
|
|
26013
|
+
__classPrivateFieldSet8(this, _MessageStream_connectedPromise, new Promise((resolve28, reject) => {
|
|
26014
|
+
__classPrivateFieldSet8(this, _MessageStream_resolveConnectedPromise, resolve28, "f");
|
|
26015
26015
|
__classPrivateFieldSet8(this, _MessageStream_rejectConnectedPromise, reject, "f");
|
|
26016
26016
|
}), "f");
|
|
26017
|
-
__classPrivateFieldSet8(this, _MessageStream_endPromise, new Promise((
|
|
26018
|
-
__classPrivateFieldSet8(this, _MessageStream_resolveEndPromise,
|
|
26017
|
+
__classPrivateFieldSet8(this, _MessageStream_endPromise, new Promise((resolve28, reject) => {
|
|
26018
|
+
__classPrivateFieldSet8(this, _MessageStream_resolveEndPromise, resolve28, "f");
|
|
26019
26019
|
__classPrivateFieldSet8(this, _MessageStream_rejectEndPromise, reject, "f");
|
|
26020
26020
|
}), "f");
|
|
26021
26021
|
__classPrivateFieldGet9(this, _MessageStream_connectedPromise, "f").catch(() => {
|
|
@@ -26144,11 +26144,11 @@ var MessageStream = class _MessageStream {
|
|
|
26144
26144
|
* const message = await stream.emitted('message') // rejects if the stream errors
|
|
26145
26145
|
*/
|
|
26146
26146
|
emitted(event) {
|
|
26147
|
-
return new Promise((
|
|
26147
|
+
return new Promise((resolve28, reject) => {
|
|
26148
26148
|
__classPrivateFieldSet8(this, _MessageStream_catchingPromiseCreated, true, "f");
|
|
26149
26149
|
if (event !== "error")
|
|
26150
26150
|
this.once("error", reject);
|
|
26151
|
-
this.once(event,
|
|
26151
|
+
this.once(event, resolve28);
|
|
26152
26152
|
});
|
|
26153
26153
|
}
|
|
26154
26154
|
async done() {
|
|
@@ -26375,7 +26375,7 @@ var MessageStream = class _MessageStream {
|
|
|
26375
26375
|
if (done) {
|
|
26376
26376
|
return { value: void 0, done: true };
|
|
26377
26377
|
}
|
|
26378
|
-
return new Promise((
|
|
26378
|
+
return new Promise((resolve28, reject) => readQueue.push({ resolve: resolve28, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
|
|
26379
26379
|
}
|
|
26380
26380
|
const chunk = pushQueue.shift();
|
|
26381
26381
|
return { value: chunk, done: false };
|
|
@@ -26635,11 +26635,11 @@ async function promptApplyAgentMdProposal(repoPath) {
|
|
|
26635
26635
|
}
|
|
26636
26636
|
async function askYesNo2(question) {
|
|
26637
26637
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
26638
|
-
return new Promise((
|
|
26638
|
+
return new Promise((resolve28) => {
|
|
26639
26639
|
process.stderr.write(`${question} `);
|
|
26640
26640
|
rl.once("line", (answer) => {
|
|
26641
26641
|
rl.close();
|
|
26642
|
-
|
|
26642
|
+
resolve28(/^y(es)?$/i.test(answer.trim()));
|
|
26643
26643
|
});
|
|
26644
26644
|
});
|
|
26645
26645
|
}
|
|
@@ -26869,7 +26869,7 @@ async function executeAuthoringToolCall(toolName, input, repoPath, harnessDir, c
|
|
|
26869
26869
|
}
|
|
26870
26870
|
async function askUser(question, options) {
|
|
26871
26871
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
26872
|
-
return new Promise((
|
|
26872
|
+
return new Promise((resolve28) => {
|
|
26873
26873
|
process.stderr.write("\n");
|
|
26874
26874
|
process.stderr.write(`\u2753 ${question}
|
|
26875
26875
|
`);
|
|
@@ -26880,7 +26880,7 @@ async function askUser(question, options) {
|
|
|
26880
26880
|
process.stderr.write("> ");
|
|
26881
26881
|
rl.once("line", (answer) => {
|
|
26882
26882
|
rl.close();
|
|
26883
|
-
|
|
26883
|
+
resolve28(answer.trim());
|
|
26884
26884
|
});
|
|
26885
26885
|
});
|
|
26886
26886
|
}
|
|
@@ -27024,7 +27024,7 @@ function runScript(scriptPath, args = [], options = {}) {
|
|
|
27024
27024
|
function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
27025
27025
|
const stream = options.stream ?? false;
|
|
27026
27026
|
const { stream: _stream, ...spawnOptions } = options;
|
|
27027
|
-
return new Promise((
|
|
27027
|
+
return new Promise((resolve28) => {
|
|
27028
27028
|
const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
|
|
27029
27029
|
...spawnOptions,
|
|
27030
27030
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -27039,13 +27039,13 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
27039
27039
|
stderr += d2;
|
|
27040
27040
|
if (stream) process.stderr.write(d2);
|
|
27041
27041
|
});
|
|
27042
|
-
proc.on("close", (code) =>
|
|
27042
|
+
proc.on("close", (code) => resolve28({ stdout, stderr, code: code ?? 0 }));
|
|
27043
27043
|
});
|
|
27044
27044
|
}
|
|
27045
27045
|
function runShellCommand(command2, options = {}) {
|
|
27046
27046
|
const stream = options.stream ?? false;
|
|
27047
27047
|
const { stream: _stream, ...spawnOptions } = options;
|
|
27048
|
-
return new Promise((
|
|
27048
|
+
return new Promise((resolve28) => {
|
|
27049
27049
|
const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
|
|
27050
27050
|
...spawnOptions,
|
|
27051
27051
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -27060,7 +27060,7 @@ function runShellCommand(command2, options = {}) {
|
|
|
27060
27060
|
stderr += d2;
|
|
27061
27061
|
if (stream) process.stderr.write(d2);
|
|
27062
27062
|
});
|
|
27063
|
-
proc.on("close", (code) =>
|
|
27063
|
+
proc.on("close", (code) => resolve28({ stdout, stderr, code: code ?? 0 }));
|
|
27064
27064
|
});
|
|
27065
27065
|
}
|
|
27066
27066
|
|
|
@@ -27849,6 +27849,24 @@ function harnessExists(repoPath) {
|
|
|
27849
27849
|
}
|
|
27850
27850
|
|
|
27851
27851
|
// src/harness/stage-templates.ts
|
|
27852
|
+
var STAGE_TEMPLATE_IDS = ["playwright", "rocketsim"];
|
|
27853
|
+
var TemplateManifestFileSchema = external_exports.object({
|
|
27854
|
+
src: external_exports.string().min(1),
|
|
27855
|
+
dest: external_exports.string().min(1),
|
|
27856
|
+
executable: external_exports.boolean().optional(),
|
|
27857
|
+
skipFlag: external_exports.string().optional()
|
|
27858
|
+
});
|
|
27859
|
+
var StageTemplateManifestSchema = external_exports.object({
|
|
27860
|
+
id: external_exports.enum(STAGE_TEMPLATE_IDS),
|
|
27861
|
+
stageId: external_exports.string().min(1),
|
|
27862
|
+
verificationStages: external_exports.array(external_exports.string().min(1)).min(1),
|
|
27863
|
+
stage: external_exports.record(external_exports.unknown()),
|
|
27864
|
+
files: external_exports.array(TemplateManifestFileSchema).min(1),
|
|
27865
|
+
optionalFiles: external_exports.array(TemplateManifestFileSchema).optional(),
|
|
27866
|
+
merge: external_exports.record(external_exports.string()).optional(),
|
|
27867
|
+
nextSteps: external_exports.array(external_exports.string().min(1)).min(1),
|
|
27868
|
+
docsPath: external_exports.string().min(1)
|
|
27869
|
+
});
|
|
27852
27870
|
function resolveTemplateDir(templateId) {
|
|
27853
27871
|
const dir = path17.join(resolveTemplatesDir(), "stage-templates", templateId);
|
|
27854
27872
|
if (!fs18.existsSync(dir)) {
|
|
@@ -27858,11 +27876,16 @@ function resolveTemplateDir(templateId) {
|
|
|
27858
27876
|
}
|
|
27859
27877
|
function readTemplateManifest(templateId) {
|
|
27860
27878
|
const manifestPath = path17.join(resolveTemplateDir(templateId), "template.manifest.json");
|
|
27861
|
-
const
|
|
27862
|
-
|
|
27863
|
-
|
|
27879
|
+
const parsed = StageTemplateManifestSchema.safeParse(
|
|
27880
|
+
JSON.parse(fs18.readFileSync(manifestPath, "utf8"))
|
|
27881
|
+
);
|
|
27882
|
+
if (!parsed.success) {
|
|
27883
|
+
throw new Error(`Invalid template manifest for ${templateId}: ${parsed.error.message}`);
|
|
27864
27884
|
}
|
|
27865
|
-
|
|
27885
|
+
if (parsed.data.id !== templateId) {
|
|
27886
|
+
throw new Error(`Template manifest id mismatch: expected ${templateId}, got ${parsed.data.id}`);
|
|
27887
|
+
}
|
|
27888
|
+
return parsed.data;
|
|
27866
27889
|
}
|
|
27867
27890
|
function ensureParentDir(filePath) {
|
|
27868
27891
|
const parent = path17.dirname(filePath);
|
|
@@ -27891,7 +27914,7 @@ function copyTemplateFile(templateDir, file, repoPath, force) {
|
|
|
27891
27914
|
function mergePackageJson(repoPath, templateDir, fragmentRelPath, warnings) {
|
|
27892
27915
|
const packagePath = path17.join(repoPath, "package.json");
|
|
27893
27916
|
if (!fs18.existsSync(packagePath)) {
|
|
27894
|
-
throw new Error("No package.json in repo root. Add one before applying
|
|
27917
|
+
throw new Error("No package.json in repo root. Add one before applying this stage template.");
|
|
27895
27918
|
}
|
|
27896
27919
|
const fragmentPath = path17.join(templateDir, fragmentRelPath);
|
|
27897
27920
|
if (!fs18.existsSync(fragmentPath)) {
|
|
@@ -27924,8 +27947,7 @@ function patchStageRegistry(repoPath, manifest, force) {
|
|
|
27924
27947
|
}
|
|
27925
27948
|
const stages = existing ? registry2.stages.map((s2) => s2.id === stage.id ? stage : s2) : [...registry2.stages, stage];
|
|
27926
27949
|
const verificationStages = [...registry2.verificationStages ?? []];
|
|
27927
|
-
const
|
|
27928
|
-
for (const id of toAdd) {
|
|
27950
|
+
for (const id of manifest.verificationStages) {
|
|
27929
27951
|
if (!verificationStages.includes(id)) {
|
|
27930
27952
|
verificationStages.push(id);
|
|
27931
27953
|
}
|
|
@@ -27934,7 +27956,7 @@ function patchStageRegistry(repoPath, manifest, force) {
|
|
|
27934
27956
|
if (verifyIdx >= 0) {
|
|
27935
27957
|
stages[verifyIdx] = {
|
|
27936
27958
|
...stages[verifyIdx],
|
|
27937
|
-
description:
|
|
27959
|
+
description: `Verification pipeline (quick smoke by default; --full runs the registry's verificationStages: ${verificationStages.join(", ")})`,
|
|
27938
27960
|
acceptsArgs: ["--full"]
|
|
27939
27961
|
};
|
|
27940
27962
|
}
|
|
@@ -28010,21 +28032,22 @@ function applyStageTemplate(repoPath, templateId, options = {}) {
|
|
|
28010
28032
|
for (const warning of warnings) {
|
|
28011
28033
|
warn(` \u26A0 ${warning}`);
|
|
28012
28034
|
}
|
|
28013
|
-
const nextSteps = manifest.nextSteps ?? [
|
|
28014
|
-
"npm install",
|
|
28015
|
-
"npx playwright install",
|
|
28016
|
-
"./.har/launch.sh 1",
|
|
28017
|
-
`./.har/stages/${manifest.stageId}.sh 1`,
|
|
28018
|
-
"npx playwright show-report .har/artifacts/browser-e2e/playwright-report"
|
|
28019
|
-
];
|
|
28020
28035
|
return {
|
|
28021
28036
|
templateId,
|
|
28022
28037
|
stageId: manifest.stageId,
|
|
28023
28038
|
filesWritten,
|
|
28024
28039
|
warnings,
|
|
28025
|
-
nextSteps
|
|
28040
|
+
nextSteps: manifest.nextSteps,
|
|
28041
|
+
docsPath: manifest.docsPath
|
|
28026
28042
|
};
|
|
28027
28043
|
}
|
|
28044
|
+
function listStageTemplateIds() {
|
|
28045
|
+
const root = path17.join(resolveTemplatesDir(), "stage-templates");
|
|
28046
|
+
if (!fs18.existsSync(root)) return [...STAGE_TEMPLATE_IDS];
|
|
28047
|
+
return fs18.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter(
|
|
28048
|
+
(name) => STAGE_TEMPLATE_IDS.includes(name)
|
|
28049
|
+
);
|
|
28050
|
+
}
|
|
28028
28051
|
|
|
28029
28052
|
// src/utils/validation.ts
|
|
28030
28053
|
function requireApiKey() {
|
|
@@ -28156,9 +28179,111 @@ function addStageTemplate(repoPath, templateId, options = {}) {
|
|
|
28156
28179
|
return applyStageTemplate(repoPath, templateId, options);
|
|
28157
28180
|
}
|
|
28158
28181
|
|
|
28159
|
-
// src/harness/
|
|
28182
|
+
// src/harness/custom-stage.ts
|
|
28160
28183
|
var fs20 = __toESM(require("fs"));
|
|
28161
28184
|
var path19 = __toESM(require("path"));
|
|
28185
|
+
var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
28186
|
+
function addCustomStage(repoPath, options) {
|
|
28187
|
+
const resolved = path19.resolve(repoPath);
|
|
28188
|
+
if (!harnessExists(resolved)) {
|
|
28189
|
+
throw new Error('No .har/ harness found. Run "har env init" first.');
|
|
28190
|
+
}
|
|
28191
|
+
const id = options.id.trim();
|
|
28192
|
+
if (!STAGE_ID_PATTERN.test(id)) {
|
|
28193
|
+
throw new Error(
|
|
28194
|
+
`Invalid stage id "${id}". Use lowercase letters, digits, dots, dashes (e.g. "unit-tests").`
|
|
28195
|
+
);
|
|
28196
|
+
}
|
|
28197
|
+
const kind2 = options.kind ?? "custom";
|
|
28198
|
+
if (!HarnessStageKindSchema.options.includes(kind2)) {
|
|
28199
|
+
throw new Error(
|
|
28200
|
+
`Invalid stage kind "${kind2}". Available: ${HarnessStageKindSchema.options.join(", ")}`
|
|
28201
|
+
);
|
|
28202
|
+
}
|
|
28203
|
+
if (Boolean(options.command) === Boolean(options.script)) {
|
|
28204
|
+
throw new Error(
|
|
28205
|
+
'Choose exactly one execution mode: --command "<shell command>" for a one-liner, or --script to scaffold .har/stages/<id>.sh.'
|
|
28206
|
+
);
|
|
28207
|
+
}
|
|
28208
|
+
const registry2 = readStageRegistry(resolved);
|
|
28209
|
+
const existing = registry2.stages.find((s2) => s2.id === id);
|
|
28210
|
+
if (existing && !options.force) {
|
|
28211
|
+
throw new Error(`Stage "${id}" already registered in .har/stages.json. Use --force to replace.`);
|
|
28212
|
+
}
|
|
28213
|
+
const filesWritten = [];
|
|
28214
|
+
const stage = {
|
|
28215
|
+
id,
|
|
28216
|
+
kind: kind2,
|
|
28217
|
+
description: options.description ?? `Custom ${kind2} stage`,
|
|
28218
|
+
requiresAgentId: true,
|
|
28219
|
+
artifacts: []
|
|
28220
|
+
};
|
|
28221
|
+
if (options.command) {
|
|
28222
|
+
stage.command = options.command;
|
|
28223
|
+
} else {
|
|
28224
|
+
const scriptRel = path19.join("stages", `${id}.sh`);
|
|
28225
|
+
const scriptAbs = path19.join(resolved, ".har", scriptRel);
|
|
28226
|
+
if (fs20.existsSync(scriptAbs) && !options.force) {
|
|
28227
|
+
throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
|
|
28228
|
+
}
|
|
28229
|
+
const skeletonPath = path19.join(
|
|
28230
|
+
resolveTemplatesDir(),
|
|
28231
|
+
"stage-templates",
|
|
28232
|
+
"custom-stage-skeleton.sh"
|
|
28233
|
+
);
|
|
28234
|
+
const skeleton = fs20.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind2).replace(/__STAGE_DESCRIPTION__/g, stage.description);
|
|
28235
|
+
fs20.mkdirSync(path19.dirname(scriptAbs), { recursive: true });
|
|
28236
|
+
fs20.writeFileSync(scriptAbs, skeleton);
|
|
28237
|
+
fs20.chmodSync(scriptAbs, 493);
|
|
28238
|
+
filesWritten.push(`.har/${scriptRel}`);
|
|
28239
|
+
stage.script = scriptRel;
|
|
28240
|
+
stage.artifacts = [
|
|
28241
|
+
{
|
|
28242
|
+
path: `.har/artifacts/${id}`,
|
|
28243
|
+
kind: "directory",
|
|
28244
|
+
description: `Artifacts for the ${id} stage`
|
|
28245
|
+
}
|
|
28246
|
+
];
|
|
28247
|
+
}
|
|
28248
|
+
const parsedStage = HarnessStageSchema.parse(stage);
|
|
28249
|
+
const stages = existing ? registry2.stages.map((s2) => s2.id === id ? parsedStage : s2) : [...registry2.stages, parsedStage];
|
|
28250
|
+
const verification = options.verification ?? false;
|
|
28251
|
+
const verificationStages = [...registry2.verificationStages ?? []];
|
|
28252
|
+
if (verification && !verificationStages.includes(id)) {
|
|
28253
|
+
verificationStages.push(id);
|
|
28254
|
+
const verifyIdx = stages.findIndex((s2) => s2.id === "verify");
|
|
28255
|
+
if (verifyIdx >= 0) {
|
|
28256
|
+
stages[verifyIdx] = {
|
|
28257
|
+
...stages[verifyIdx],
|
|
28258
|
+
description: `Verification pipeline (quick smoke by default; --full runs the registry's verificationStages: ${verificationStages.join(", ")})`
|
|
28259
|
+
};
|
|
28260
|
+
}
|
|
28261
|
+
}
|
|
28262
|
+
writeStageRegistry(resolved, { ...registry2, stages, verificationStages });
|
|
28263
|
+
filesWritten.push(".har/stages.json");
|
|
28264
|
+
const nextSteps = options.command ? [
|
|
28265
|
+
`Try it: ${options.command.replace(/\{agentId\}/g, "1")}`,
|
|
28266
|
+
`Agents run it via the MCP tool har_run_stage (stageId: "${id}")`,
|
|
28267
|
+
...verification ? ["./.har/verify.sh 1 --full # runs it as part of full verification"] : []
|
|
28268
|
+
] : [
|
|
28269
|
+
`Edit .har/stages/${id}.sh \u2014 replace the TODO block with the real check`,
|
|
28270
|
+
"./.har/launch.sh 1",
|
|
28271
|
+
`./.har/stages/${id}.sh 1`,
|
|
28272
|
+
...verification ? ["./.har/verify.sh 1 --full # runs it as part of full verification"] : []
|
|
28273
|
+
];
|
|
28274
|
+
return {
|
|
28275
|
+
stageId: id,
|
|
28276
|
+
kind: kind2,
|
|
28277
|
+
mode: options.command ? "command" : "script",
|
|
28278
|
+
filesWritten,
|
|
28279
|
+
verification,
|
|
28280
|
+
nextSteps
|
|
28281
|
+
};
|
|
28282
|
+
}
|
|
28283
|
+
|
|
28284
|
+
// src/harness/adaptation-prompt.ts
|
|
28285
|
+
var fs21 = __toESM(require("fs"));
|
|
28286
|
+
var path20 = __toESM(require("path"));
|
|
28162
28287
|
var ADAPTATION_PROMPT_FILE = "ADAPT-PROMPT.md";
|
|
28163
28288
|
var PROFILE_HINTS = {
|
|
28164
28289
|
default: "Web app profile (SaaS/full-stack) \u2014 Docker Compose for shared infra (HARNESS_INFRA_SERVICES), PM2 for the primary application only, git worktree per agent slot by default. Launch provisions toolchain via harness.env (HARNESS_ECOSYSTEM, HARNESS_INSTALL_CMD) and writes paths to .env.agent.<id>. Identify the primary app agents modify; run supporting services shared.",
|
|
@@ -28170,7 +28295,7 @@ function loadTemplate(name) {
|
|
|
28170
28295
|
if (!filePath) {
|
|
28171
28296
|
throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
|
|
28172
28297
|
}
|
|
28173
|
-
return
|
|
28298
|
+
return fs21.readFileSync(filePath, "utf8");
|
|
28174
28299
|
}
|
|
28175
28300
|
function applyProfilePlaceholders(content, profile) {
|
|
28176
28301
|
return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
|
|
@@ -28192,7 +28317,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
|
|
|
28192
28317
|
}
|
|
28193
28318
|
function writeAdaptationPrompt(repoPath, content) {
|
|
28194
28319
|
const harnessDir = getHarnessDir(repoPath);
|
|
28195
|
-
const filePath =
|
|
28320
|
+
const filePath = path20.join(harnessDir, ADAPTATION_PROMPT_FILE);
|
|
28196
28321
|
writeFileSafe(filePath, content);
|
|
28197
28322
|
return filePath;
|
|
28198
28323
|
}
|
|
@@ -28211,25 +28336,25 @@ function printAdaptationPrompt(content) {
|
|
|
28211
28336
|
}
|
|
28212
28337
|
|
|
28213
28338
|
// src/harness/cursor-rule.ts
|
|
28214
|
-
var
|
|
28215
|
-
var
|
|
28339
|
+
var fs22 = __toESM(require("fs"));
|
|
28340
|
+
var path21 = __toESM(require("path"));
|
|
28216
28341
|
var readline4 = __toESM(require("readline"));
|
|
28217
28342
|
var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
|
|
28218
28343
|
function getCursorRulePath(repoPath) {
|
|
28219
|
-
return
|
|
28344
|
+
return path21.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
28220
28345
|
}
|
|
28221
28346
|
function isCursorWorkspace(repoPath) {
|
|
28222
|
-
return
|
|
28347
|
+
return fs22.existsSync(path21.join(repoPath, ".cursor"));
|
|
28223
28348
|
}
|
|
28224
28349
|
function cursorRuleExists(repoPath) {
|
|
28225
|
-
return
|
|
28350
|
+
return fs22.existsSync(getCursorRulePath(repoPath));
|
|
28226
28351
|
}
|
|
28227
28352
|
function scaffoldCursorRule(repoPath) {
|
|
28228
28353
|
const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
|
|
28229
28354
|
if (!templatePath) {
|
|
28230
28355
|
throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
|
|
28231
28356
|
}
|
|
28232
|
-
const content =
|
|
28357
|
+
const content = fs22.readFileSync(templatePath, "utf8");
|
|
28233
28358
|
writeFileSafe(getCursorRulePath(repoPath), content);
|
|
28234
28359
|
}
|
|
28235
28360
|
async function handleCursorRule(options) {
|
|
@@ -28267,16 +28392,16 @@ async function promptScaffoldCursorRule(exists) {
|
|
|
28267
28392
|
}
|
|
28268
28393
|
async function askYesNo3(question) {
|
|
28269
28394
|
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
28270
|
-
return new Promise((
|
|
28395
|
+
return new Promise((resolve28) => {
|
|
28271
28396
|
process.stderr.write(`${question} `);
|
|
28272
28397
|
rl.once("line", (answer) => {
|
|
28273
28398
|
rl.close();
|
|
28274
28399
|
const trimmed = answer.trim();
|
|
28275
28400
|
if (trimmed === "") {
|
|
28276
|
-
|
|
28401
|
+
resolve28(true);
|
|
28277
28402
|
return;
|
|
28278
28403
|
}
|
|
28279
|
-
|
|
28404
|
+
resolve28(/^y(es)?$/i.test(trimmed));
|
|
28280
28405
|
});
|
|
28281
28406
|
});
|
|
28282
28407
|
}
|
|
@@ -28355,26 +28480,26 @@ function buildStageResult(input) {
|
|
|
28355
28480
|
}
|
|
28356
28481
|
|
|
28357
28482
|
// src/core/local-executor.ts
|
|
28358
|
-
var
|
|
28359
|
-
var
|
|
28483
|
+
var fs24 = __toESM(require("fs"));
|
|
28484
|
+
var path23 = __toESM(require("path"));
|
|
28360
28485
|
|
|
28361
28486
|
// src/core/slot-registry.ts
|
|
28362
|
-
var
|
|
28363
|
-
var
|
|
28487
|
+
var fs23 = __toESM(require("fs"));
|
|
28488
|
+
var path22 = __toESM(require("path"));
|
|
28364
28489
|
function getSlotRegistryDir(repoPath) {
|
|
28365
|
-
return
|
|
28490
|
+
return path22.join(getHarnessDir(repoPath), "slots");
|
|
28366
28491
|
}
|
|
28367
28492
|
function getSlotRegistryPath(repoPath, agentId) {
|
|
28368
|
-
return
|
|
28493
|
+
return path22.join(getSlotRegistryDir(repoPath), `agent-${agentId}.json`);
|
|
28369
28494
|
}
|
|
28370
28495
|
function isSlotResumable(session) {
|
|
28371
28496
|
return session?.status === "failed" || session?.status === "starting";
|
|
28372
28497
|
}
|
|
28373
28498
|
function readSlotRegistry(repoPath, agentId) {
|
|
28374
28499
|
const file = getSlotRegistryPath(repoPath, agentId);
|
|
28375
|
-
if (!
|
|
28500
|
+
if (!fs23.existsSync(file)) return void 0;
|
|
28376
28501
|
try {
|
|
28377
|
-
const raw = JSON.parse(
|
|
28502
|
+
const raw = JSON.parse(fs23.readFileSync(file, "utf8"));
|
|
28378
28503
|
const result = SlotRegistryEntrySchema.safeParse(raw);
|
|
28379
28504
|
return result.success ? result.data : void 0;
|
|
28380
28505
|
} catch {
|
|
@@ -28384,7 +28509,7 @@ function readSlotRegistry(repoPath, agentId) {
|
|
|
28384
28509
|
|
|
28385
28510
|
// src/core/local-executor.ts
|
|
28386
28511
|
function resolveRepoPath(repoPath) {
|
|
28387
|
-
return
|
|
28512
|
+
return path23.resolve(repoPath);
|
|
28388
28513
|
}
|
|
28389
28514
|
function buildPreviewUrlsFromPorts(ports, env3) {
|
|
28390
28515
|
const urls = {};
|
|
@@ -28436,14 +28561,14 @@ function substituteAgentId(value, agentId) {
|
|
|
28436
28561
|
function resolveStageScriptPath(repoPath, stage) {
|
|
28437
28562
|
const harnessDir = getHarnessDir(repoPath);
|
|
28438
28563
|
if (stage.script) {
|
|
28439
|
-
return
|
|
28564
|
+
return path23.join(harnessDir, stage.script);
|
|
28440
28565
|
}
|
|
28441
28566
|
if (stage.command) {
|
|
28442
28567
|
const scriptName = stage.command.split(/\s+/)[0].replace(/^\.\/\.har\//, "").replace(/^\.\//, "");
|
|
28443
|
-
return
|
|
28568
|
+
return path23.join(harnessDir, scriptName);
|
|
28444
28569
|
}
|
|
28445
|
-
const stageScript =
|
|
28446
|
-
if (
|
|
28570
|
+
const stageScript = path23.join(harnessDir, "stages", `${stage.id}.sh`);
|
|
28571
|
+
if (fs24.existsSync(stageScript)) {
|
|
28447
28572
|
return stageScript;
|
|
28448
28573
|
}
|
|
28449
28574
|
throw new Error(
|
|
@@ -28458,7 +28583,7 @@ function buildExecutionPlan(repoPath, stage, options) {
|
|
|
28458
28583
|
...harnessEnv,
|
|
28459
28584
|
...stage.env ?? {}
|
|
28460
28585
|
};
|
|
28461
|
-
const cwd = stage.cwd ?
|
|
28586
|
+
const cwd = stage.cwd ? path23.resolve(resolvedRepo, stage.cwd) : resolvedRepo;
|
|
28462
28587
|
const extraArgs = options.args ?? [];
|
|
28463
28588
|
const launchFlagArgs = [];
|
|
28464
28589
|
if (stage.kind === "launch" && options.launchFlags) {
|
|
@@ -28535,19 +28660,19 @@ var LocalScriptExecutor = class {
|
|
|
28535
28660
|
const repoPath = resolveRepoPath(ctx.repoPath);
|
|
28536
28661
|
const harnessDir = getHarnessDir(repoPath);
|
|
28537
28662
|
const artifactsDirName = getArtifactsDir(repoPath);
|
|
28538
|
-
const artifactsDir =
|
|
28539
|
-
if (!
|
|
28663
|
+
const artifactsDir = path23.join(harnessDir, artifactsDirName);
|
|
28664
|
+
if (!fs24.existsSync(artifactsDir)) return [];
|
|
28540
28665
|
const entries = [];
|
|
28541
28666
|
const walk = (dir, prefix) => {
|
|
28542
|
-
for (const entry of
|
|
28543
|
-
const full =
|
|
28544
|
-
const relative2 =
|
|
28667
|
+
for (const entry of fs24.readdirSync(dir, { withFileTypes: true })) {
|
|
28668
|
+
const full = path23.join(dir, entry.name);
|
|
28669
|
+
const relative2 = path23.join(prefix, entry.name);
|
|
28545
28670
|
if (entry.isDirectory()) {
|
|
28546
28671
|
walk(full, relative2);
|
|
28547
28672
|
continue;
|
|
28548
28673
|
}
|
|
28549
28674
|
if (filter?.stageId && !relative2.includes(filter.stageId)) continue;
|
|
28550
|
-
const stat =
|
|
28675
|
+
const stat = fs24.statSync(full);
|
|
28551
28676
|
entries.push({
|
|
28552
28677
|
path: full,
|
|
28553
28678
|
relativePath: relative2,
|
|
@@ -28563,7 +28688,7 @@ var LocalScriptExecutor = class {
|
|
|
28563
28688
|
var localScriptExecutor = new LocalScriptExecutor();
|
|
28564
28689
|
|
|
28565
28690
|
// src/core/control-sync.ts
|
|
28566
|
-
var
|
|
28691
|
+
var path33 = __toESM(require("path"));
|
|
28567
28692
|
|
|
28568
28693
|
// src/core/control-config.ts
|
|
28569
28694
|
var DEFAULT_CONTROL_API_URL = "http://localhost:3847";
|
|
@@ -28575,32 +28700,32 @@ function isControlEnabled() {
|
|
|
28575
28700
|
}
|
|
28576
28701
|
|
|
28577
28702
|
// src/core/control-registry.ts
|
|
28578
|
-
var
|
|
28703
|
+
var fs25 = __toESM(require("fs"));
|
|
28579
28704
|
var os4 = __toESM(require("os"));
|
|
28580
|
-
var
|
|
28705
|
+
var path24 = __toESM(require("path"));
|
|
28581
28706
|
function getRegistryPath() {
|
|
28582
28707
|
if (process.env.HAR_CONTROL_REGISTRY_PATH) {
|
|
28583
|
-
return
|
|
28708
|
+
return path24.resolve(process.env.HAR_CONTROL_REGISTRY_PATH);
|
|
28584
28709
|
}
|
|
28585
|
-
return
|
|
28710
|
+
return path24.join(os4.homedir(), ".har", "repos.json");
|
|
28586
28711
|
}
|
|
28587
28712
|
function readRegistry() {
|
|
28588
28713
|
const registryPath = getRegistryPath();
|
|
28589
28714
|
try {
|
|
28590
|
-
if (!
|
|
28591
|
-
return JSON.parse(
|
|
28715
|
+
if (!fs25.existsSync(registryPath)) return { repos: [] };
|
|
28716
|
+
return JSON.parse(fs25.readFileSync(registryPath, "utf8"));
|
|
28592
28717
|
} catch {
|
|
28593
28718
|
return { repos: [] };
|
|
28594
28719
|
}
|
|
28595
28720
|
}
|
|
28596
28721
|
function writeRegistry(registry2) {
|
|
28597
28722
|
const registryPath = getRegistryPath();
|
|
28598
|
-
|
|
28599
|
-
|
|
28723
|
+
fs25.mkdirSync(path24.dirname(registryPath), { recursive: true });
|
|
28724
|
+
fs25.writeFileSync(registryPath, JSON.stringify(registry2, null, 2) + "\n");
|
|
28600
28725
|
}
|
|
28601
28726
|
function recordRepoForControlSync(repoPath) {
|
|
28602
28727
|
if (process.env.HAR_CONTROL_DISABLED === "true") return;
|
|
28603
|
-
const resolved =
|
|
28728
|
+
const resolved = path24.resolve(repoPath);
|
|
28604
28729
|
if (!readManifest(resolved)) return;
|
|
28605
28730
|
const registry2 = readRegistry();
|
|
28606
28731
|
if (registry2.repos.includes(resolved)) return;
|
|
@@ -28609,7 +28734,7 @@ function recordRepoForControlSync(repoPath) {
|
|
|
28609
28734
|
}
|
|
28610
28735
|
function listRegisteredRepos() {
|
|
28611
28736
|
const registry2 = readRegistry();
|
|
28612
|
-
const kept = registry2.repos.filter((repoPath) =>
|
|
28737
|
+
const kept = registry2.repos.filter((repoPath) => fs25.existsSync(repoPath) && readManifest(repoPath));
|
|
28613
28738
|
if (kept.length !== registry2.repos.length) {
|
|
28614
28739
|
writeRegistry({ repos: kept });
|
|
28615
28740
|
}
|
|
@@ -28617,17 +28742,17 @@ function listRegisteredRepos() {
|
|
|
28617
28742
|
}
|
|
28618
28743
|
|
|
28619
28744
|
// src/core/slot-status.ts
|
|
28620
|
-
var
|
|
28745
|
+
var fs30 = __toESM(require("fs"));
|
|
28621
28746
|
var os7 = __toESM(require("os"));
|
|
28622
|
-
var
|
|
28747
|
+
var path30 = __toESM(require("path"));
|
|
28623
28748
|
var import_child_process7 = require("child_process");
|
|
28624
28749
|
|
|
28625
28750
|
// src/core/runs.ts
|
|
28626
28751
|
var crypto2 = __toESM(require("crypto"));
|
|
28627
28752
|
var import_child_process2 = require("child_process");
|
|
28628
|
-
var
|
|
28753
|
+
var fs26 = __toESM(require("fs"));
|
|
28629
28754
|
var os5 = __toESM(require("os"));
|
|
28630
|
-
var
|
|
28755
|
+
var path25 = __toESM(require("path"));
|
|
28631
28756
|
var RUNS_DIR = "runs";
|
|
28632
28757
|
function gitCommonDir(cwd) {
|
|
28633
28758
|
try {
|
|
@@ -28636,7 +28761,7 @@ function gitCommonDir(cwd) {
|
|
|
28636
28761
|
encoding: "utf8",
|
|
28637
28762
|
stdio: ["pipe", "pipe", "ignore"]
|
|
28638
28763
|
}).trim();
|
|
28639
|
-
return out ?
|
|
28764
|
+
return out ? path25.resolve(cwd, out) : void 0;
|
|
28640
28765
|
} catch {
|
|
28641
28766
|
return void 0;
|
|
28642
28767
|
}
|
|
@@ -28658,7 +28783,7 @@ function gitPrefix(cwd) {
|
|
|
28658
28783
|
}
|
|
28659
28784
|
}
|
|
28660
28785
|
function getRunsDir(harnessRoot) {
|
|
28661
|
-
return
|
|
28786
|
+
return path25.join(getHarnessDir(harnessRoot), RUNS_DIR);
|
|
28662
28787
|
}
|
|
28663
28788
|
function formatLocalDate(d2) {
|
|
28664
28789
|
const y2 = d2.getFullYear();
|
|
@@ -28678,24 +28803,24 @@ function buildRunRelativePath(stageId, agentId, startedAt, runId, runsDir) {
|
|
|
28678
28803
|
const timePart = formatLocalTime(started);
|
|
28679
28804
|
const agentPart = agentId !== void 0 ? `_agent-${agentId}` : "";
|
|
28680
28805
|
let filename = `${timePart}_${stageId}${agentPart}.json`;
|
|
28681
|
-
const fullPath =
|
|
28682
|
-
if (
|
|
28806
|
+
const fullPath = path25.join(runsDir, dateFolder, filename);
|
|
28807
|
+
if (fs26.existsSync(fullPath)) {
|
|
28683
28808
|
filename = `${timePart}_${stageId}${agentPart}-${runId.slice(0, 8)}.json`;
|
|
28684
28809
|
}
|
|
28685
|
-
return
|
|
28810
|
+
return path25.join(dateFolder, filename);
|
|
28686
28811
|
}
|
|
28687
28812
|
function resolveRunFilePath(harnessRoot, run2) {
|
|
28688
28813
|
if (run2.relativePath) {
|
|
28689
|
-
return
|
|
28814
|
+
return path25.join(getRunsDir(harnessRoot), run2.relativePath);
|
|
28690
28815
|
}
|
|
28691
|
-
return
|
|
28816
|
+
return path25.join(getRunsDir(harnessRoot), `${run2.runId}.json`);
|
|
28692
28817
|
}
|
|
28693
28818
|
function collectRunFiles(runsDir) {
|
|
28694
|
-
if (!
|
|
28819
|
+
if (!fs26.existsSync(runsDir)) return [];
|
|
28695
28820
|
const files = [];
|
|
28696
28821
|
const walk = (dir) => {
|
|
28697
|
-
for (const entry of
|
|
28698
|
-
const full =
|
|
28822
|
+
for (const entry of fs26.readdirSync(dir, { withFileTypes: true })) {
|
|
28823
|
+
const full = path25.join(dir, entry.name);
|
|
28699
28824
|
if (entry.isDirectory()) {
|
|
28700
28825
|
walk(full);
|
|
28701
28826
|
} else if (entry.name.endsWith(".json")) {
|
|
@@ -28709,30 +28834,30 @@ function collectRunFiles(runsDir) {
|
|
|
28709
28834
|
function resolveAgentWorkDir(harnessRoot, agentId) {
|
|
28710
28835
|
if (agentId === void 0) return void 0;
|
|
28711
28836
|
const entry = readSlotRegistry(harnessRoot, agentId);
|
|
28712
|
-
if (entry?.workDir &&
|
|
28837
|
+
if (entry?.workDir && fs26.existsSync(entry.workDir)) return entry.workDir;
|
|
28713
28838
|
const env3 = readHarnessEnv(harnessRoot);
|
|
28714
|
-
const projectName = env3.HARNESS_PROJECT_NAME ??
|
|
28715
|
-
const worktreeDir =
|
|
28839
|
+
const projectName = env3.HARNESS_PROJECT_NAME ?? path25.basename(harnessRoot);
|
|
28840
|
+
const worktreeDir = path25.join(os5.homedir(), "worktrees", `${projectName}-agent-${agentId}`);
|
|
28716
28841
|
const relPrefix = gitPrefix(harnessRoot);
|
|
28717
28842
|
const sessionEnvFiles = [];
|
|
28718
|
-
const worktreesRoot =
|
|
28719
|
-
if (
|
|
28843
|
+
const worktreesRoot = path25.join(os5.homedir(), "worktrees");
|
|
28844
|
+
if (fs26.existsSync(worktreesRoot)) {
|
|
28720
28845
|
const suffix = `-har-agent-${agentId}-`;
|
|
28721
|
-
for (const entry2 of
|
|
28846
|
+
for (const entry2 of fs26.readdirSync(worktreesRoot, { withFileTypes: true })) {
|
|
28722
28847
|
if (!entry2.isDirectory() || !entry2.name.includes(suffix)) continue;
|
|
28723
|
-
const sessionDir =
|
|
28848
|
+
const sessionDir = path25.join(worktreesRoot, entry2.name);
|
|
28724
28849
|
if (!sameGitCheckout(harnessRoot, sessionDir)) continue;
|
|
28725
|
-
sessionEnvFiles.push(
|
|
28850
|
+
sessionEnvFiles.push(path25.join(sessionDir, relPrefix, `.env.agent.${agentId}`));
|
|
28726
28851
|
}
|
|
28727
28852
|
}
|
|
28728
28853
|
const candidates = [
|
|
28729
|
-
|
|
28730
|
-
|
|
28854
|
+
path25.join(worktreeDir, `.env.agent.${agentId}`),
|
|
28855
|
+
path25.join(harnessRoot, `.env.agent.${agentId}`),
|
|
28731
28856
|
...sessionEnvFiles.sort()
|
|
28732
28857
|
];
|
|
28733
28858
|
for (const envFile of candidates) {
|
|
28734
|
-
if (!
|
|
28735
|
-
const content =
|
|
28859
|
+
if (!fs26.existsSync(envFile)) continue;
|
|
28860
|
+
const content = fs26.readFileSync(envFile, "utf8");
|
|
28736
28861
|
const match = content.match(/^REPO_ROOT=(.+)$/m);
|
|
28737
28862
|
if (match) return match[1].trim();
|
|
28738
28863
|
}
|
|
@@ -28744,11 +28869,11 @@ function createRun(ctx, meta) {
|
|
|
28744
28869
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28745
28870
|
const runId = crypto2.randomUUID();
|
|
28746
28871
|
const relativePath = buildRunRelativePath(meta.stageId, meta.agentId, startedAt, runId, runsDir);
|
|
28747
|
-
const runFilePath =
|
|
28748
|
-
|
|
28872
|
+
const runFilePath = path25.join(runsDir, relativePath);
|
|
28873
|
+
fs26.mkdirSync(path25.dirname(runFilePath), { recursive: true });
|
|
28749
28874
|
const run2 = RunRecordSchema.parse({
|
|
28750
28875
|
runId,
|
|
28751
|
-
repoPath:
|
|
28876
|
+
repoPath: path25.resolve(ctx.repoPath),
|
|
28752
28877
|
harnessRoot,
|
|
28753
28878
|
stageId: meta.stageId,
|
|
28754
28879
|
kind: meta.kind,
|
|
@@ -28759,7 +28884,7 @@ function createRun(ctx, meta) {
|
|
|
28759
28884
|
relativePath,
|
|
28760
28885
|
trigger: ctx.trigger ?? "cli"
|
|
28761
28886
|
});
|
|
28762
|
-
|
|
28887
|
+
fs26.writeFileSync(runFilePath, JSON.stringify(run2, null, 2) + "\n");
|
|
28763
28888
|
return run2;
|
|
28764
28889
|
}
|
|
28765
28890
|
function finishRun(repoPath, runId, update) {
|
|
@@ -28778,13 +28903,13 @@ function finishRun(repoPath, runId, update) {
|
|
|
28778
28903
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
28779
28904
|
});
|
|
28780
28905
|
const runPath = resolveRunFilePath(harnessRoot, finished);
|
|
28781
|
-
|
|
28906
|
+
fs26.writeFileSync(runPath, JSON.stringify(finished, null, 2) + "\n");
|
|
28782
28907
|
return finished;
|
|
28783
28908
|
}
|
|
28784
28909
|
function findRunRecord(harnessRoot, runId) {
|
|
28785
28910
|
const runsDir = getRunsDir(harnessRoot);
|
|
28786
28911
|
for (const filePath of collectRunFiles(runsDir)) {
|
|
28787
|
-
const parsed = RunRecordSchema.safeParse(JSON.parse(
|
|
28912
|
+
const parsed = RunRecordSchema.safeParse(JSON.parse(fs26.readFileSync(filePath, "utf8")));
|
|
28788
28913
|
if (parsed.success && parsed.data.runId === runId) {
|
|
28789
28914
|
return parsed.data;
|
|
28790
28915
|
}
|
|
@@ -28796,10 +28921,10 @@ function getRun(repoPath, runId) {
|
|
|
28796
28921
|
}
|
|
28797
28922
|
function listRuns(repoPath, filter = {}) {
|
|
28798
28923
|
const runsDir = getRunsDir(resolveHarnessRoot(repoPath));
|
|
28799
|
-
if (!
|
|
28924
|
+
if (!fs26.existsSync(runsDir)) return [];
|
|
28800
28925
|
const runs = [];
|
|
28801
28926
|
for (const filePath of collectRunFiles(runsDir)) {
|
|
28802
|
-
const parsed = RunRecordSchema.safeParse(JSON.parse(
|
|
28927
|
+
const parsed = RunRecordSchema.safeParse(JSON.parse(fs26.readFileSync(filePath, "utf8")));
|
|
28803
28928
|
if (!parsed.success) continue;
|
|
28804
28929
|
if (filter.stageId && parsed.data.stageId !== filter.stageId) continue;
|
|
28805
28930
|
runs.push(parsed.data);
|
|
@@ -28812,17 +28937,17 @@ function listRuns(repoPath, filter = {}) {
|
|
|
28812
28937
|
}
|
|
28813
28938
|
|
|
28814
28939
|
// src/core/slot-preflight.ts
|
|
28815
|
-
var
|
|
28940
|
+
var path29 = __toESM(require("path"));
|
|
28816
28941
|
|
|
28817
28942
|
// src/core/control-port.ts
|
|
28818
28943
|
var import_child_process4 = require("child_process");
|
|
28819
|
-
var
|
|
28820
|
-
var
|
|
28944
|
+
var fs28 = __toESM(require("fs"));
|
|
28945
|
+
var path27 = __toESM(require("path"));
|
|
28821
28946
|
|
|
28822
28947
|
// src/core/slot-ports.ts
|
|
28823
28948
|
var import_child_process3 = require("child_process");
|
|
28824
|
-
var
|
|
28825
|
-
var
|
|
28949
|
+
var fs27 = __toESM(require("fs"));
|
|
28950
|
+
var path26 = __toESM(require("path"));
|
|
28826
28951
|
function portStep(env3) {
|
|
28827
28952
|
return Number(env3.HARNESS_PORT_STEP ?? 10);
|
|
28828
28953
|
}
|
|
@@ -28878,7 +29003,7 @@ function allocateAppPorts(repoPath, agentId) {
|
|
|
28878
29003
|
}
|
|
28879
29004
|
function harnessUsesPm2(repoPath) {
|
|
28880
29005
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
28881
|
-
return
|
|
29006
|
+
return fs27.existsSync(path26.join(harnessRoot, ".har", "ecosystem.agent.template.cjs"));
|
|
28882
29007
|
}
|
|
28883
29008
|
|
|
28884
29009
|
// src/core/control-port.ts
|
|
@@ -28933,13 +29058,13 @@ function controlDefaultPortWarnings(containers, defaultFrontendPort, allocatedFr
|
|
|
28933
29058
|
return [formatControlDefaultPortWarning(control.name, defaultFrontendPort, allocatedFrontend)];
|
|
28934
29059
|
}
|
|
28935
29060
|
function inspectControlUpReadiness(repoPath) {
|
|
28936
|
-
const resolved =
|
|
29061
|
+
const resolved = path27.resolve(repoPath);
|
|
28937
29062
|
const port = parseControlHostPort();
|
|
28938
29063
|
const containers = listDockerContainers();
|
|
28939
29064
|
const control = controlContainerOnPort(containers, port);
|
|
28940
29065
|
const warnings = [];
|
|
28941
|
-
const controlHarnessDir =
|
|
28942
|
-
const harnessSlot1Active =
|
|
29066
|
+
const controlHarnessDir = path27.join(resolved, "control", ".har");
|
|
29067
|
+
const harnessSlot1Active = fs28.existsSync(controlHarnessDir) && readSlotRegistry(path27.join(resolved, "control"), 1)?.status === "active";
|
|
28943
29068
|
if (control) {
|
|
28944
29069
|
return {
|
|
28945
29070
|
warnings,
|
|
@@ -28970,9 +29095,9 @@ function inspectControlUpReadiness(repoPath) {
|
|
|
28970
29095
|
}
|
|
28971
29096
|
|
|
28972
29097
|
// src/core/slot-launch-guard-occupied.ts
|
|
28973
|
-
var
|
|
29098
|
+
var fs29 = __toESM(require("fs"));
|
|
28974
29099
|
var os6 = __toESM(require("os"));
|
|
28975
|
-
var
|
|
29100
|
+
var path28 = __toESM(require("path"));
|
|
28976
29101
|
var import_child_process5 = require("child_process");
|
|
28977
29102
|
function runGit(cwd, args) {
|
|
28978
29103
|
try {
|
|
@@ -28991,7 +29116,7 @@ function worktreeDirty(worktreePath) {
|
|
|
28991
29116
|
}
|
|
28992
29117
|
function gitCommonDir2(cwd) {
|
|
28993
29118
|
const out = runGit(cwd, "rev-parse --git-common-dir");
|
|
28994
|
-
return out ?
|
|
29119
|
+
return out ? path28.resolve(cwd, out) : void 0;
|
|
28995
29120
|
}
|
|
28996
29121
|
function sameGitCheckout2(a2, b2) {
|
|
28997
29122
|
const left2 = gitCommonDir2(a2);
|
|
@@ -29000,20 +29125,20 @@ function sameGitCheckout2(a2, b2) {
|
|
|
29000
29125
|
}
|
|
29001
29126
|
function discoverWorktree(harnessRoot, agentId, projectName) {
|
|
29002
29127
|
const session = readSlotRegistry(harnessRoot, agentId);
|
|
29003
|
-
if (session?.worktreePath &&
|
|
29128
|
+
if (session?.worktreePath && fs29.existsSync(session.worktreePath)) {
|
|
29004
29129
|
return session.worktreePath;
|
|
29005
29130
|
}
|
|
29006
|
-
const legacy =
|
|
29007
|
-
if (
|
|
29008
|
-
const worktreesRoot =
|
|
29009
|
-
if (!
|
|
29131
|
+
const legacy = path28.join(os6.homedir(), "worktrees", `${projectName}-agent-${agentId}`);
|
|
29132
|
+
if (fs29.existsSync(legacy) && sameGitCheckout2(harnessRoot, legacy)) return legacy;
|
|
29133
|
+
const worktreesRoot = path28.join(os6.homedir(), "worktrees");
|
|
29134
|
+
if (!fs29.existsSync(worktreesRoot)) return void 0;
|
|
29010
29135
|
const suffix = `-har-agent-${agentId}-`;
|
|
29011
29136
|
const relPrefix = runGit(harnessRoot, "rev-parse --show-prefix") ?? "";
|
|
29012
|
-
for (const name of
|
|
29137
|
+
for (const name of fs29.readdirSync(worktreesRoot)) {
|
|
29013
29138
|
if (!name.includes(suffix)) continue;
|
|
29014
|
-
const candidate =
|
|
29139
|
+
const candidate = path28.join(worktreesRoot, name);
|
|
29015
29140
|
if (!sameGitCheckout2(harnessRoot, candidate)) continue;
|
|
29016
|
-
if (!
|
|
29141
|
+
if (!fs29.existsSync(path28.join(candidate, relPrefix, `.env.agent.${agentId}`))) continue;
|
|
29017
29142
|
return candidate;
|
|
29018
29143
|
}
|
|
29019
29144
|
return void 0;
|
|
@@ -29021,13 +29146,13 @@ function discoverWorktree(harnessRoot, agentId, projectName) {
|
|
|
29021
29146
|
function collectOccupiedSlot(repoPath, agentId) {
|
|
29022
29147
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
29023
29148
|
const env3 = readHarnessEnv(harnessRoot);
|
|
29024
|
-
const projectName = env3.HARNESS_PROJECT_NAME ??
|
|
29149
|
+
const projectName = env3.HARNESS_PROJECT_NAME ?? path28.basename(harnessRoot);
|
|
29025
29150
|
const session = readSlotRegistry(harnessRoot, agentId);
|
|
29026
29151
|
const worktreePath = discoverWorktree(harnessRoot, agentId, projectName);
|
|
29027
29152
|
const workDir = session?.workDir;
|
|
29028
|
-
const envInWorkDir = workDir ?
|
|
29029
|
-
const envInRoot =
|
|
29030
|
-
const envInWorktree = worktreePath ?
|
|
29153
|
+
const envInWorkDir = workDir ? fs29.existsSync(path28.join(workDir, `.env.agent.${agentId}`)) : false;
|
|
29154
|
+
const envInRoot = fs29.existsSync(path28.join(harnessRoot, `.env.agent.${agentId}`));
|
|
29155
|
+
const envInWorktree = worktreePath ? fs29.existsSync(path28.join(worktreePath, `.env.agent.${agentId}`)) : false;
|
|
29031
29156
|
const active = session !== void 0 && session.status !== "completed" || envInWorkDir || envInRoot || envInWorktree;
|
|
29032
29157
|
if (!active) return void 0;
|
|
29033
29158
|
const dirty = worktreePath ? worktreeDirty(worktreePath) : void 0;
|
|
@@ -29180,7 +29305,7 @@ function checkInfraPort(env3, varName, defaultPort, scanStart, scanEnd) {
|
|
|
29180
29305
|
function inspectSlotReadiness(repoPath, agentId, options = {}) {
|
|
29181
29306
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
29182
29307
|
const env3 = readHarnessEnv(harnessRoot);
|
|
29183
|
-
const projectName = env3.HARNESS_PROJECT_NAME ??
|
|
29308
|
+
const projectName = env3.HARNESS_PROJECT_NAME ?? path29.basename(harnessRoot);
|
|
29184
29309
|
const usesPm2 = harnessUsesPm2(repoPath);
|
|
29185
29310
|
const blockers = [];
|
|
29186
29311
|
const remediations = [];
|
|
@@ -29382,7 +29507,7 @@ function readWorktreeBranch(worktreePath) {
|
|
|
29382
29507
|
}
|
|
29383
29508
|
function gitCommonDir3(cwd) {
|
|
29384
29509
|
const out = runGit2(cwd, "rev-parse --git-common-dir");
|
|
29385
|
-
return out ?
|
|
29510
|
+
return out ? path30.resolve(cwd, out) : void 0;
|
|
29386
29511
|
}
|
|
29387
29512
|
function sameGitCheckout3(a2, b2) {
|
|
29388
29513
|
const left2 = gitCommonDir3(a2);
|
|
@@ -29394,12 +29519,12 @@ function gitPrefix2(cwd) {
|
|
|
29394
29519
|
return out ?? "";
|
|
29395
29520
|
}
|
|
29396
29521
|
function discoverSessionWorktreePath(harnessRoot, agentId) {
|
|
29397
|
-
const worktreesRoot =
|
|
29398
|
-
if (!
|
|
29522
|
+
const worktreesRoot = path30.join(os7.homedir(), "worktrees");
|
|
29523
|
+
if (!fs30.existsSync(worktreesRoot)) return void 0;
|
|
29399
29524
|
const suffix = `-har-agent-${agentId}-`;
|
|
29400
29525
|
const relPrefix = gitPrefix2(harnessRoot);
|
|
29401
|
-
const matches =
|
|
29402
|
-
(candidate) => sameGitCheckout3(harnessRoot, candidate) &&
|
|
29526
|
+
const matches = fs30.readdirSync(worktreesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.includes(suffix)).map((entry) => path30.join(worktreesRoot, entry.name)).filter(
|
|
29527
|
+
(candidate) => sameGitCheckout3(harnessRoot, candidate) && fs30.existsSync(path30.join(candidate, relPrefix, `.env.agent.${agentId}`))
|
|
29403
29528
|
);
|
|
29404
29529
|
return matches.sort()[0];
|
|
29405
29530
|
}
|
|
@@ -29474,18 +29599,18 @@ function detectPm2Issue(projectName, agentId, session, procs) {
|
|
|
29474
29599
|
}
|
|
29475
29600
|
function collectSlotStatus(harnessRoot, agentId, runs, pm2Procs) {
|
|
29476
29601
|
const env3 = readHarnessEnv(harnessRoot);
|
|
29477
|
-
const projectName = env3.HARNESS_PROJECT_NAME ??
|
|
29602
|
+
const projectName = env3.HARNESS_PROJECT_NAME ?? path30.basename(harnessRoot);
|
|
29478
29603
|
const session = readSlotRegistry(harnessRoot, agentId);
|
|
29479
|
-
const legacyWorktreePath =
|
|
29604
|
+
const legacyWorktreePath = path30.join(
|
|
29480
29605
|
os7.homedir(),
|
|
29481
29606
|
"worktrees",
|
|
29482
29607
|
`${projectName}-agent-${agentId}`
|
|
29483
29608
|
);
|
|
29484
|
-
const worktreePath = session?.worktreePath &&
|
|
29609
|
+
const worktreePath = session?.worktreePath && fs30.existsSync(session.worktreePath) ? session.worktreePath : fs30.existsSync(legacyWorktreePath) ? legacyWorktreePath : discoverSessionWorktreePath(harnessRoot, agentId);
|
|
29485
29610
|
const workDir = resolveAgentWorkDir(harnessRoot, agentId);
|
|
29486
|
-
const envInWorkDir = workDir ?
|
|
29487
|
-
const envInRoot =
|
|
29488
|
-
const envInWorktree = worktreePath ?
|
|
29611
|
+
const envInWorkDir = workDir ? fs30.existsSync(path30.join(workDir, `.env.agent.${agentId}`)) : false;
|
|
29612
|
+
const envInRoot = fs30.existsSync(path30.join(harnessRoot, `.env.agent.${agentId}`));
|
|
29613
|
+
const envInWorktree = worktreePath ? fs30.existsSync(path30.join(worktreePath, `.env.agent.${agentId}`)) : false;
|
|
29489
29614
|
const active = session !== void 0 && session.status !== "completed" || envInWorkDir || envInRoot || envInWorktree;
|
|
29490
29615
|
const latest = latestRunForAgent(runs, agentId);
|
|
29491
29616
|
const verifyRun = runs.find((r2) => r2.agentId === agentId && r2.stageId === "verify");
|
|
@@ -29538,7 +29663,7 @@ function collectEnvironmentStatus(repoPath) {
|
|
|
29538
29663
|
const slotIds = getAgentSlotIds(harnessRoot);
|
|
29539
29664
|
const pm2Procs = listPm2Processes2();
|
|
29540
29665
|
return {
|
|
29541
|
-
repoPath:
|
|
29666
|
+
repoPath: path30.resolve(repoPath),
|
|
29542
29667
|
harnessRoot,
|
|
29543
29668
|
gitRemote: readGitRemote(harnessRoot),
|
|
29544
29669
|
profile: manifest?.profile,
|
|
@@ -29549,13 +29674,13 @@ function collectEnvironmentStatus(repoPath) {
|
|
|
29549
29674
|
|
|
29550
29675
|
// src/core/validations.ts
|
|
29551
29676
|
var crypto3 = __toESM(require("crypto"));
|
|
29552
|
-
var
|
|
29553
|
-
var
|
|
29677
|
+
var fs32 = __toESM(require("fs"));
|
|
29678
|
+
var path32 = __toESM(require("path"));
|
|
29554
29679
|
|
|
29555
29680
|
// src/core/change-batch.ts
|
|
29556
|
-
var
|
|
29681
|
+
var fs31 = __toESM(require("fs"));
|
|
29557
29682
|
var os8 = __toESM(require("os"));
|
|
29558
|
-
var
|
|
29683
|
+
var path31 = __toESM(require("path"));
|
|
29559
29684
|
function git(checkoutDir, args, env3) {
|
|
29560
29685
|
const result = run(`git ${args}`, { cwd: checkoutDir, env: env3 });
|
|
29561
29686
|
if (result.code !== 0) {
|
|
@@ -29571,7 +29696,7 @@ function isCheckoutRoot(checkoutDir) {
|
|
|
29571
29696
|
const toplevel = tryGit(checkoutDir, "rev-parse --show-toplevel");
|
|
29572
29697
|
if (!toplevel) return false;
|
|
29573
29698
|
try {
|
|
29574
|
-
return
|
|
29699
|
+
return fs31.realpathSync(toplevel) === fs31.realpathSync(checkoutDir);
|
|
29575
29700
|
} catch {
|
|
29576
29701
|
return false;
|
|
29577
29702
|
}
|
|
@@ -29593,7 +29718,7 @@ function isMergeOrRebaseInProgress(checkoutDir) {
|
|
|
29593
29718
|
if (tryGit(checkoutDir, "rev-parse -q --verify MERGE_HEAD") !== void 0) return true;
|
|
29594
29719
|
for (const dir of ["rebase-merge", "rebase-apply"]) {
|
|
29595
29720
|
const gitPath = tryGit(checkoutDir, `rev-parse --git-path ${dir}`);
|
|
29596
|
-
if (gitPath &&
|
|
29721
|
+
if (gitPath && fs31.existsSync(path31.resolve(checkoutDir, gitPath))) return true;
|
|
29597
29722
|
}
|
|
29598
29723
|
return false;
|
|
29599
29724
|
}
|
|
@@ -29616,8 +29741,8 @@ function parseNameStatus(output) {
|
|
|
29616
29741
|
return files;
|
|
29617
29742
|
}
|
|
29618
29743
|
function computeWorktreeSnapshot(checkoutDir) {
|
|
29619
|
-
const tmpDir =
|
|
29620
|
-
const tmpIndex =
|
|
29744
|
+
const tmpDir = fs31.mkdtempSync(path31.join(os8.tmpdir(), "har-idx-"));
|
|
29745
|
+
const tmpIndex = path31.join(tmpDir, "index");
|
|
29621
29746
|
const env3 = { GIT_INDEX_FILE: tmpIndex };
|
|
29622
29747
|
try {
|
|
29623
29748
|
const headTree = getHeadTree(checkoutDir);
|
|
@@ -29640,35 +29765,35 @@ function computeWorktreeSnapshot(checkoutDir) {
|
|
|
29640
29765
|
changedFiles: parseNameStatus(diffOutput)
|
|
29641
29766
|
};
|
|
29642
29767
|
} finally {
|
|
29643
|
-
|
|
29768
|
+
fs31.rmSync(tmpDir, { recursive: true, force: true });
|
|
29644
29769
|
}
|
|
29645
29770
|
}
|
|
29646
29771
|
|
|
29647
29772
|
// src/core/validations.ts
|
|
29648
29773
|
var VALIDATIONS_DIR = "validations";
|
|
29649
29774
|
function getValidationsDir(checkoutDir) {
|
|
29650
|
-
return
|
|
29775
|
+
return path32.join(checkoutDir, ".har", VALIDATIONS_DIR);
|
|
29651
29776
|
}
|
|
29652
29777
|
function validationPath(checkoutDir, treeHash) {
|
|
29653
|
-
return
|
|
29778
|
+
return path32.join(getValidationsDir(checkoutDir), `${treeHash}.json`);
|
|
29654
29779
|
}
|
|
29655
29780
|
function writeRecord(checkoutDir, record2) {
|
|
29656
29781
|
const dir = getValidationsDir(checkoutDir);
|
|
29657
|
-
|
|
29658
|
-
|
|
29782
|
+
fs32.mkdirSync(dir, { recursive: true });
|
|
29783
|
+
fs32.writeFileSync(
|
|
29659
29784
|
validationPath(checkoutDir, record2.treeHash),
|
|
29660
29785
|
`${JSON.stringify(record2, null, 2)}
|
|
29661
29786
|
`
|
|
29662
29787
|
);
|
|
29663
29788
|
}
|
|
29664
29789
|
function ensureValidationsIgnored(checkoutDir) {
|
|
29665
|
-
const harDir =
|
|
29666
|
-
if (!
|
|
29667
|
-
const gitignorePath =
|
|
29668
|
-
const content =
|
|
29790
|
+
const harDir = path32.join(checkoutDir, ".har");
|
|
29791
|
+
if (!fs32.existsSync(harDir)) return;
|
|
29792
|
+
const gitignorePath = path32.join(harDir, ".gitignore");
|
|
29793
|
+
const content = fs32.existsSync(gitignorePath) ? fs32.readFileSync(gitignorePath, "utf8") : "";
|
|
29669
29794
|
if (content.split("\n").some((line) => line.trim() === `${VALIDATIONS_DIR}/`)) return;
|
|
29670
29795
|
const suffix = content.length === 0 || content.endsWith("\n") ? "" : "\n";
|
|
29671
|
-
|
|
29796
|
+
fs32.writeFileSync(gitignorePath, `${content}${suffix}${VALIDATIONS_DIR}/
|
|
29672
29797
|
`);
|
|
29673
29798
|
}
|
|
29674
29799
|
function recordValidation(input) {
|
|
@@ -29685,8 +29810,8 @@ function recordValidation(input) {
|
|
|
29685
29810
|
treeHash: snapshot.treeHash,
|
|
29686
29811
|
headSha: snapshot.headSha,
|
|
29687
29812
|
branch: snapshot.branch,
|
|
29688
|
-
workDir:
|
|
29689
|
-
harnessRoot:
|
|
29813
|
+
workDir: path32.resolve(input.checkoutDir),
|
|
29814
|
+
harnessRoot: path32.resolve(input.harnessRoot),
|
|
29690
29815
|
agentId: input.agentId,
|
|
29691
29816
|
status: input.status,
|
|
29692
29817
|
full: input.full,
|
|
@@ -29698,16 +29823,16 @@ function recordValidation(input) {
|
|
|
29698
29823
|
committedAt: existing?.committedAt
|
|
29699
29824
|
});
|
|
29700
29825
|
writeRecord(input.checkoutDir, record2);
|
|
29701
|
-
if (
|
|
29826
|
+
if (path32.resolve(input.harnessRoot) !== path32.resolve(input.checkoutDir)) {
|
|
29702
29827
|
writeRecord(input.harnessRoot, record2);
|
|
29703
29828
|
}
|
|
29704
29829
|
return record2;
|
|
29705
29830
|
}
|
|
29706
29831
|
function findValidation(checkoutDir, treeHash) {
|
|
29707
29832
|
const file = validationPath(checkoutDir, treeHash);
|
|
29708
|
-
if (!
|
|
29833
|
+
if (!fs32.existsSync(file)) return void 0;
|
|
29709
29834
|
try {
|
|
29710
|
-
return ValidationRecordSchema.parse(JSON.parse(
|
|
29835
|
+
return ValidationRecordSchema.parse(JSON.parse(fs32.readFileSync(file, "utf8")));
|
|
29711
29836
|
} catch {
|
|
29712
29837
|
return void 0;
|
|
29713
29838
|
}
|
|
@@ -29722,19 +29847,19 @@ function attachCommit(checkoutDir, treeHash, commitSha) {
|
|
|
29722
29847
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29723
29848
|
};
|
|
29724
29849
|
writeRecord(checkoutDir, updated);
|
|
29725
|
-
if (record2.harnessRoot &&
|
|
29850
|
+
if (record2.harnessRoot && path32.resolve(record2.harnessRoot) !== path32.resolve(checkoutDir) && fs32.existsSync(path32.join(record2.harnessRoot, ".har"))) {
|
|
29726
29851
|
writeRecord(record2.harnessRoot, updated);
|
|
29727
29852
|
}
|
|
29728
29853
|
return updated;
|
|
29729
29854
|
}
|
|
29730
29855
|
function listValidations(harnessRoot) {
|
|
29731
29856
|
const dir = getValidationsDir(harnessRoot);
|
|
29732
|
-
if (!
|
|
29857
|
+
if (!fs32.existsSync(dir)) return [];
|
|
29733
29858
|
const records = [];
|
|
29734
|
-
for (const entry of
|
|
29859
|
+
for (const entry of fs32.readdirSync(dir)) {
|
|
29735
29860
|
if (!entry.endsWith(".json")) continue;
|
|
29736
29861
|
try {
|
|
29737
|
-
records.push(ValidationRecordSchema.parse(JSON.parse(
|
|
29862
|
+
records.push(ValidationRecordSchema.parse(JSON.parse(fs32.readFileSync(path32.join(dir, entry), "utf8"))));
|
|
29738
29863
|
} catch {
|
|
29739
29864
|
}
|
|
29740
29865
|
}
|
|
@@ -29792,7 +29917,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
|
|
|
29792
29917
|
const deadline = Date.now() + timeoutMs;
|
|
29793
29918
|
while (Date.now() < deadline) {
|
|
29794
29919
|
if (await isControlApiReachable(apiUrl)) return true;
|
|
29795
|
-
await new Promise((
|
|
29920
|
+
await new Promise((resolve28) => setTimeout(resolve28, intervalMs));
|
|
29796
29921
|
}
|
|
29797
29922
|
return false;
|
|
29798
29923
|
}
|
|
@@ -29804,7 +29929,7 @@ async function syncAllKnownReposWithControl(options) {
|
|
|
29804
29929
|
}
|
|
29805
29930
|
const repoPaths = new Set(listRegisteredRepos());
|
|
29806
29931
|
if (options?.cwd) {
|
|
29807
|
-
const cwd =
|
|
29932
|
+
const cwd = path33.resolve(options.cwd);
|
|
29808
29933
|
if (readManifest(cwd)) repoPaths.add(cwd);
|
|
29809
29934
|
}
|
|
29810
29935
|
try {
|
|
@@ -29812,7 +29937,7 @@ async function syncAllKnownReposWithControl(options) {
|
|
|
29812
29937
|
if (listResponse.ok) {
|
|
29813
29938
|
const repos = await listResponse.json();
|
|
29814
29939
|
for (const repo of repos) {
|
|
29815
|
-
const resolved =
|
|
29940
|
+
const resolved = path33.resolve(repo.path);
|
|
29816
29941
|
if (readManifest(resolved)) repoPaths.add(resolved);
|
|
29817
29942
|
}
|
|
29818
29943
|
}
|
|
@@ -29831,7 +29956,7 @@ async function syncAllKnownReposWithControl(options) {
|
|
|
29831
29956
|
return { synced, failed };
|
|
29832
29957
|
}
|
|
29833
29958
|
async function registerRepoWithControl(options) {
|
|
29834
|
-
const repoPath =
|
|
29959
|
+
const repoPath = path33.resolve(options.repoPath);
|
|
29835
29960
|
const apiUrl = options.apiUrl ?? getControlApiUrl();
|
|
29836
29961
|
const manifest = readManifest(repoPath);
|
|
29837
29962
|
const stagesRegistry = readStageRegistry(repoPath);
|
|
@@ -29844,7 +29969,7 @@ async function registerRepoWithControl(options) {
|
|
|
29844
29969
|
return postJson(`${apiUrl}/api/repos`, body, options.dryRun);
|
|
29845
29970
|
}
|
|
29846
29971
|
async function syncRepoWithControl(options) {
|
|
29847
|
-
const repoPath =
|
|
29972
|
+
const repoPath = path33.resolve(options.repoPath);
|
|
29848
29973
|
const apiUrl = options.apiUrl ?? getControlApiUrl();
|
|
29849
29974
|
if (options.cloud) {
|
|
29850
29975
|
const remote = createRemoteExecutor();
|
|
@@ -29872,7 +29997,7 @@ async function syncRepoWithControl(options) {
|
|
|
29872
29997
|
const listResponse = await fetch(`${apiUrl}/api/repos`);
|
|
29873
29998
|
if (!listResponse.ok) throw new Error("Failed to list repos from Control API");
|
|
29874
29999
|
const repos = await listResponse.json();
|
|
29875
|
-
const existing = repos.find((r2) =>
|
|
30000
|
+
const existing = repos.find((r2) => path33.resolve(r2.path) === repoPath);
|
|
29876
30001
|
if (!existing) throw new Error(`Repo not registered: ${repoPath}`);
|
|
29877
30002
|
await syncRepoRunsAndSlots(apiUrl, existing.id, repoPath, options.dryRun);
|
|
29878
30003
|
return;
|
|
@@ -30320,11 +30445,36 @@ var envCommand = {
|
|
|
30320
30445
|
}),
|
|
30321
30446
|
handleMaintain
|
|
30322
30447
|
).command(
|
|
30323
|
-
"add-stage
|
|
30324
|
-
|
|
30448
|
+
"add-stage [template]",
|
|
30449
|
+
`Add a stage template (${STAGE_TEMPLATE_IDS.join(", ")}) or a custom stage (--custom)`,
|
|
30325
30450
|
(y2) => y2.positional("template", {
|
|
30326
30451
|
type: "string",
|
|
30327
|
-
describe:
|
|
30452
|
+
describe: `Stage template id (${STAGE_TEMPLATE_IDS.join(", ")}), or the new stage id with --custom`
|
|
30453
|
+
}).option("list", {
|
|
30454
|
+
type: "boolean",
|
|
30455
|
+
default: false,
|
|
30456
|
+
describe: "List available stage templates and exit"
|
|
30457
|
+
}).option("custom", {
|
|
30458
|
+
type: "boolean",
|
|
30459
|
+
default: false,
|
|
30460
|
+
describe: "Register a custom stage instead of a shipped template"
|
|
30461
|
+
}).option("kind", {
|
|
30462
|
+
type: "string",
|
|
30463
|
+
describe: "Custom stage kind (setup, launch, verify, test, inspect, reset, teardown, custom)"
|
|
30464
|
+
}).option("command", {
|
|
30465
|
+
type: "string",
|
|
30466
|
+
describe: 'Custom stage shell command ({agentId} is substituted), e.g. "npm test"'
|
|
30467
|
+
}).option("script", {
|
|
30468
|
+
type: "boolean",
|
|
30469
|
+
default: false,
|
|
30470
|
+
describe: "Scaffold .har/stages/<id>.sh from the contract skeleton (see .har/STAGES.md)"
|
|
30471
|
+
}).option("description", {
|
|
30472
|
+
type: "string",
|
|
30473
|
+
describe: "Custom stage description shown in the registry and Mission Control"
|
|
30474
|
+
}).option("verification", {
|
|
30475
|
+
type: "boolean",
|
|
30476
|
+
default: false,
|
|
30477
|
+
describe: "Include the custom stage in verify --full (stages.json verificationStages)"
|
|
30328
30478
|
}).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("force", {
|
|
30329
30479
|
type: "boolean",
|
|
30330
30480
|
default: false,
|
|
@@ -30332,7 +30482,7 @@ var envCommand = {
|
|
|
30332
30482
|
}).option("skip-ci", {
|
|
30333
30483
|
type: "boolean",
|
|
30334
30484
|
default: false,
|
|
30335
|
-
describe: "Do not copy .github/workflows/playwright.yml"
|
|
30485
|
+
describe: "Do not copy optional CI workflow files (e.g. .github/workflows/playwright.yml)"
|
|
30336
30486
|
}),
|
|
30337
30487
|
handleAddStage
|
|
30338
30488
|
).command(
|
|
@@ -30427,7 +30577,7 @@ var envCommand = {
|
|
|
30427
30577
|
}
|
|
30428
30578
|
};
|
|
30429
30579
|
async function handleInit(argv) {
|
|
30430
|
-
const repoPath =
|
|
30580
|
+
const repoPath = path34.resolve(argv.repo);
|
|
30431
30581
|
header("har env init");
|
|
30432
30582
|
info(`Repository: ${repoPath}`);
|
|
30433
30583
|
try {
|
|
@@ -30486,7 +30636,7 @@ async function handleInit(argv) {
|
|
|
30486
30636
|
}
|
|
30487
30637
|
}
|
|
30488
30638
|
async function handleMaintain(argv) {
|
|
30489
|
-
const repoPath =
|
|
30639
|
+
const repoPath = path34.resolve(argv.repo);
|
|
30490
30640
|
header("har env maintain");
|
|
30491
30641
|
info(`Repository: ${repoPath}`);
|
|
30492
30642
|
try {
|
|
@@ -30582,7 +30732,7 @@ async function handleAgentMdProposal(repoPath, autoYes) {
|
|
|
30582
30732
|
if (autoYes) {
|
|
30583
30733
|
const proposal = readAgentMdProposal(repoPath);
|
|
30584
30734
|
if (proposal) {
|
|
30585
|
-
writeFileSafe(
|
|
30735
|
+
writeFileSafe(path34.join(repoPath, "AGENT.md"), proposal.content);
|
|
30586
30736
|
clearAgentMdProposal(repoPath);
|
|
30587
30737
|
info("Applied AGENT.md proposal (--yes)");
|
|
30588
30738
|
}
|
|
@@ -30591,16 +30741,64 @@ async function handleAgentMdProposal(repoPath, autoYes) {
|
|
|
30591
30741
|
await promptApplyAgentMdProposal(repoPath);
|
|
30592
30742
|
}
|
|
30593
30743
|
async function handleAddStage(argv) {
|
|
30594
|
-
const repoPath =
|
|
30595
|
-
|
|
30596
|
-
|
|
30744
|
+
const repoPath = path34.resolve(argv.repo);
|
|
30745
|
+
const available = listStageTemplateIds();
|
|
30746
|
+
if (argv.list) {
|
|
30747
|
+
for (const id of available) {
|
|
30748
|
+
console.log(id);
|
|
30749
|
+
}
|
|
30750
|
+
return;
|
|
30751
|
+
}
|
|
30752
|
+
if (argv.custom) {
|
|
30753
|
+
if (!argv.template) {
|
|
30754
|
+
error(
|
|
30755
|
+
'Missing stage id. Usage: har env add-stage <id> --custom (--command "npm test" | --script) [--kind test] [--verification]'
|
|
30756
|
+
);
|
|
30757
|
+
process.exit(1);
|
|
30758
|
+
}
|
|
30759
|
+
header("har env add-stage --custom");
|
|
30760
|
+
info(`Repository: ${repoPath}`);
|
|
30761
|
+
info(`Stage: ${argv.template}`);
|
|
30762
|
+
try {
|
|
30763
|
+
const result = addCustomStage(repoPath, {
|
|
30764
|
+
id: argv.template,
|
|
30765
|
+
kind: argv.kind,
|
|
30766
|
+
command: argv.command,
|
|
30767
|
+
script: argv.script,
|
|
30768
|
+
description: argv.description,
|
|
30769
|
+
verification: argv.verification,
|
|
30770
|
+
force: argv.force
|
|
30771
|
+
});
|
|
30772
|
+
divider();
|
|
30773
|
+
success(`Custom stage registered: ${result.stageId} (kind: ${result.kind}, ${result.mode})`);
|
|
30774
|
+
for (const file of result.filesWritten) {
|
|
30775
|
+
info(` + ${file}`);
|
|
30776
|
+
}
|
|
30777
|
+
console.error("");
|
|
30778
|
+
console.error(" Next steps:");
|
|
30779
|
+
for (const step of result.nextSteps) {
|
|
30780
|
+
console.error(` ${step}`);
|
|
30781
|
+
}
|
|
30782
|
+
console.error("");
|
|
30783
|
+
console.error(" Docs: .har/STAGES.md");
|
|
30784
|
+
console.error("");
|
|
30785
|
+
} catch (err) {
|
|
30786
|
+
error(err.message);
|
|
30787
|
+
process.exit(1);
|
|
30788
|
+
}
|
|
30789
|
+
return;
|
|
30790
|
+
}
|
|
30791
|
+
if (!argv.template || !available.includes(argv.template)) {
|
|
30792
|
+
error(
|
|
30793
|
+
`Unknown stage template: ${argv.template ?? "(missing)"}. Available: ${available.join(", ")}. For a project-specific stage, use: har env add-stage <id> --custom`
|
|
30794
|
+
);
|
|
30597
30795
|
process.exit(1);
|
|
30598
30796
|
}
|
|
30599
30797
|
header("har env add-stage");
|
|
30600
30798
|
info(`Repository: ${repoPath}`);
|
|
30601
30799
|
info(`Template: ${argv.template}`);
|
|
30602
30800
|
try {
|
|
30603
|
-
const result = addStageTemplate(repoPath,
|
|
30801
|
+
const result = addStageTemplate(repoPath, argv.template, {
|
|
30604
30802
|
force: argv.force,
|
|
30605
30803
|
skipCi: argv.skipCi
|
|
30606
30804
|
});
|
|
@@ -30612,7 +30810,7 @@ async function handleAddStage(argv) {
|
|
|
30612
30810
|
console.error(` ${step}`);
|
|
30613
30811
|
}
|
|
30614
30812
|
console.error("");
|
|
30615
|
-
console.error(
|
|
30813
|
+
console.error(` Docs: ${result.docsPath}`);
|
|
30616
30814
|
console.error("");
|
|
30617
30815
|
} catch (err) {
|
|
30618
30816
|
error(err.message);
|
|
@@ -30620,7 +30818,7 @@ async function handleAddStage(argv) {
|
|
|
30620
30818
|
}
|
|
30621
30819
|
}
|
|
30622
30820
|
async function handlePreflight(argv) {
|
|
30623
|
-
const repo =
|
|
30821
|
+
const repo = path34.resolve(argv.repo);
|
|
30624
30822
|
const agentId = validateAgentId(argv.id, repo);
|
|
30625
30823
|
const result = await preflightEnvironment({
|
|
30626
30824
|
repoPath: repo,
|
|
@@ -30638,7 +30836,7 @@ async function handlePreflight(argv) {
|
|
|
30638
30836
|
process.exit(result.code);
|
|
30639
30837
|
}
|
|
30640
30838
|
async function handleLaunch(argv) {
|
|
30641
|
-
const repo =
|
|
30839
|
+
const repo = path34.resolve(argv.repo);
|
|
30642
30840
|
const agentId = validateAgentId(argv.id, repo);
|
|
30643
30841
|
let confirmReplace = argv.replace;
|
|
30644
30842
|
let force = argv.force;
|
|
@@ -30650,8 +30848,8 @@ async function handleLaunch(argv) {
|
|
|
30650
30848
|
console.error(guard.reason ?? "");
|
|
30651
30849
|
const readline5 = await import("readline");
|
|
30652
30850
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
30653
|
-
const answer = await new Promise((
|
|
30654
|
-
rl.question("Replace this slot? [y/N] ",
|
|
30851
|
+
const answer = await new Promise((resolve28) => {
|
|
30852
|
+
rl.question("Replace this slot? [y/N] ", resolve28);
|
|
30655
30853
|
});
|
|
30656
30854
|
rl.close();
|
|
30657
30855
|
if (!/^[Yy]$/.test(answer.trim())) {
|
|
@@ -30667,8 +30865,8 @@ async function handleLaunch(argv) {
|
|
|
30667
30865
|
warn("Worktree has uncommitted changes.");
|
|
30668
30866
|
const readline5 = await import("readline");
|
|
30669
30867
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
30670
|
-
const answer = await new Promise((
|
|
30671
|
-
rl.question("Discard uncommitted changes? [y/N] ",
|
|
30868
|
+
const answer = await new Promise((resolve28) => {
|
|
30869
|
+
rl.question("Discard uncommitted changes? [y/N] ", resolve28);
|
|
30672
30870
|
});
|
|
30673
30871
|
rl.close();
|
|
30674
30872
|
if (!/^[Yy]$/.test(answer.trim())) {
|
|
@@ -30715,7 +30913,7 @@ async function handleRecover(argv) {
|
|
|
30715
30913
|
});
|
|
30716
30914
|
}
|
|
30717
30915
|
async function handleVerify(argv) {
|
|
30718
|
-
const repo =
|
|
30916
|
+
const repo = path34.resolve(argv.repo);
|
|
30719
30917
|
const agentId = validateAgentId(argv.id, repo);
|
|
30720
30918
|
const result = await runVerification({
|
|
30721
30919
|
repoPath: repo,
|
|
@@ -30727,7 +30925,7 @@ async function handleVerify(argv) {
|
|
|
30727
30925
|
process.exit(result.code);
|
|
30728
30926
|
}
|
|
30729
30927
|
async function handleTeardown(argv) {
|
|
30730
|
-
const repo =
|
|
30928
|
+
const repo = path34.resolve(argv.repo);
|
|
30731
30929
|
const agentId = validateAgentId(argv.id, repo);
|
|
30732
30930
|
const result = await teardownEnvironment({
|
|
30733
30931
|
repoPath: repo,
|
|
@@ -30738,7 +30936,7 @@ async function handleTeardown(argv) {
|
|
|
30738
30936
|
process.exit(result.code);
|
|
30739
30937
|
}
|
|
30740
30938
|
async function handleComplete(argv) {
|
|
30741
|
-
const repo =
|
|
30939
|
+
const repo = path34.resolve(argv.repo);
|
|
30742
30940
|
const agentId = validateAgentId(argv.id, repo);
|
|
30743
30941
|
const result = await completeEnvironment({
|
|
30744
30942
|
repoPath: repo,
|
|
@@ -30759,7 +30957,7 @@ async function handleComplete(argv) {
|
|
|
30759
30957
|
process.exit(result.code);
|
|
30760
30958
|
}
|
|
30761
30959
|
async function handleStatus(argv) {
|
|
30762
|
-
const repoPath =
|
|
30960
|
+
const repoPath = path34.resolve(argv.repo);
|
|
30763
30961
|
if (argv.json) {
|
|
30764
30962
|
const status = collectEnvironmentStatus(repoPath);
|
|
30765
30963
|
const output = EnvironmentStatusSchema.parse(status);
|
|
@@ -30772,7 +30970,7 @@ async function handleStatus(argv) {
|
|
|
30772
30970
|
});
|
|
30773
30971
|
}
|
|
30774
30972
|
async function handleRunsList(argv) {
|
|
30775
|
-
const repoPath =
|
|
30973
|
+
const repoPath = path34.resolve(argv.repo);
|
|
30776
30974
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
30777
30975
|
if (argv.json) {
|
|
30778
30976
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -30789,7 +30987,7 @@ async function handleRunsList(argv) {
|
|
|
30789
30987
|
}
|
|
30790
30988
|
}
|
|
30791
30989
|
async function handleRunsGet(argv) {
|
|
30792
|
-
const run2 = getRun(
|
|
30990
|
+
const run2 = getRun(path34.resolve(argv.repo), argv.runId);
|
|
30793
30991
|
if (!run2) {
|
|
30794
30992
|
error(`Run not found: ${argv.runId}`);
|
|
30795
30993
|
process.exit(1);
|
|
@@ -30862,11 +31060,11 @@ function printNextSteps(auto2) {
|
|
|
30862
31060
|
}
|
|
30863
31061
|
|
|
30864
31062
|
// src/cli/commands/control.ts
|
|
30865
|
-
var
|
|
31063
|
+
var path36 = __toESM(require("path"));
|
|
30866
31064
|
|
|
30867
31065
|
// src/core/control-lifecycle.ts
|
|
30868
31066
|
var import_child_process8 = require("child_process");
|
|
30869
|
-
var
|
|
31067
|
+
var path35 = __toESM(require("path"));
|
|
30870
31068
|
|
|
30871
31069
|
// src/core/control-image.ts
|
|
30872
31070
|
var DEFAULT_CONTROL_IMAGE = "theosfactory/har-control";
|
|
@@ -30885,13 +31083,13 @@ function shouldBuildControlLocally() {
|
|
|
30885
31083
|
|
|
30886
31084
|
// src/core/control-lifecycle.ts
|
|
30887
31085
|
function resolveControlDir() {
|
|
30888
|
-
return
|
|
31086
|
+
return path35.resolve(__dirname, "..", "control");
|
|
30889
31087
|
}
|
|
30890
31088
|
function resolveControlComposeFiles(options) {
|
|
30891
31089
|
const controlDir = resolveControlDir();
|
|
30892
|
-
const files = [
|
|
31090
|
+
const files = [path35.join(controlDir, "docker-compose.yml")];
|
|
30893
31091
|
if (options?.build ?? shouldBuildControlLocally()) {
|
|
30894
|
-
files.push(
|
|
31092
|
+
files.push(path35.join(controlDir, "docker-compose.build.yml"));
|
|
30895
31093
|
}
|
|
30896
31094
|
return files;
|
|
30897
31095
|
}
|
|
@@ -31060,7 +31258,7 @@ async function handleDown() {
|
|
|
31060
31258
|
process.exit(code);
|
|
31061
31259
|
}
|
|
31062
31260
|
async function handleRegister(argv) {
|
|
31063
|
-
const repoPath =
|
|
31261
|
+
const repoPath = path36.resolve(argv.repo);
|
|
31064
31262
|
header("har control register");
|
|
31065
31263
|
info(`Repository: ${repoPath}`);
|
|
31066
31264
|
try {
|
|
@@ -31080,7 +31278,7 @@ async function handleRegister(argv) {
|
|
|
31080
31278
|
}
|
|
31081
31279
|
}
|
|
31082
31280
|
async function handleSync(argv) {
|
|
31083
|
-
const repoPath =
|
|
31281
|
+
const repoPath = path36.resolve(argv.repo);
|
|
31084
31282
|
try {
|
|
31085
31283
|
await syncRepoWithControl({
|
|
31086
31284
|
repoPath,
|
|
@@ -31119,7 +31317,7 @@ async function handleWatch(argv) {
|
|
|
31119
31317
|
};
|
|
31120
31318
|
const tick = async () => {
|
|
31121
31319
|
if (argv.repo) {
|
|
31122
|
-
await syncOne(
|
|
31320
|
+
await syncOne(path36.resolve(argv.repo));
|
|
31123
31321
|
return;
|
|
31124
31322
|
}
|
|
31125
31323
|
try {
|
|
@@ -31150,12 +31348,12 @@ async function handleLogin(argv) {
|
|
|
31150
31348
|
}
|
|
31151
31349
|
|
|
31152
31350
|
// src/cli/commands/hooks.ts
|
|
31153
|
-
var
|
|
31351
|
+
var path39 = __toESM(require("path"));
|
|
31154
31352
|
|
|
31155
31353
|
// src/core/hooks.ts
|
|
31156
|
-
var
|
|
31354
|
+
var fs33 = __toESM(require("fs"));
|
|
31157
31355
|
var os9 = __toESM(require("os"));
|
|
31158
|
-
var
|
|
31356
|
+
var path37 = __toESM(require("path"));
|
|
31159
31357
|
var MARKER_START = "# >>> har commit gate (managed by `har hooks`) >>>";
|
|
31160
31358
|
var MARKER_END = "# <<< har commit gate <<<";
|
|
31161
31359
|
var PRE_COMMIT_BLOCK = [
|
|
@@ -31180,7 +31378,7 @@ function resolveCheckoutRoot(cwd) {
|
|
|
31180
31378
|
function resolveHooksDir(checkoutDir) {
|
|
31181
31379
|
const hooksPath = tryGit2(checkoutDir, "rev-parse --git-path hooks");
|
|
31182
31380
|
if (!hooksPath) throw new Error(`Not a git checkout: ${checkoutDir}`);
|
|
31183
|
-
return
|
|
31381
|
+
return path37.resolve(checkoutDir, hooksPath);
|
|
31184
31382
|
}
|
|
31185
31383
|
function getConfiguredHooksPath(checkoutDir) {
|
|
31186
31384
|
return tryGit2(checkoutDir, "config core.hooksPath") || void 0;
|
|
@@ -31188,9 +31386,9 @@ function getConfiguredHooksPath(checkoutDir) {
|
|
|
31188
31386
|
function defaultHarInvocation() {
|
|
31189
31387
|
const entry = process.argv[1];
|
|
31190
31388
|
if (entry && entry.endsWith(".js")) {
|
|
31191
|
-
return `"${process.execPath}" "${
|
|
31389
|
+
return `"${process.execPath}" "${path37.resolve(entry)}"`;
|
|
31192
31390
|
}
|
|
31193
|
-
if (entry) return `"${
|
|
31391
|
+
if (entry) return `"${path37.resolve(entry)}"`;
|
|
31194
31392
|
return "har";
|
|
31195
31393
|
}
|
|
31196
31394
|
function buildHookScript(harInvocation, subcommand, failOpenNotice) {
|
|
@@ -31211,40 +31409,40 @@ exit 0
|
|
|
31211
31409
|
`;
|
|
31212
31410
|
}
|
|
31213
31411
|
function upsertMarkedBlock(filePath, block) {
|
|
31214
|
-
if (!
|
|
31215
|
-
|
|
31412
|
+
if (!fs33.existsSync(filePath)) {
|
|
31413
|
+
fs33.writeFileSync(filePath, `#!/bin/sh
|
|
31216
31414
|
${block}
|
|
31217
31415
|
`, { mode: 493 });
|
|
31218
31416
|
return "created";
|
|
31219
31417
|
}
|
|
31220
|
-
const content =
|
|
31418
|
+
const content = fs33.readFileSync(filePath, "utf8");
|
|
31221
31419
|
if (content.includes(MARKER_START)) {
|
|
31222
31420
|
const pattern = new RegExp(
|
|
31223
31421
|
`${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}`
|
|
31224
31422
|
);
|
|
31225
|
-
|
|
31226
|
-
|
|
31423
|
+
fs33.writeFileSync(filePath, content.replace(pattern, block));
|
|
31424
|
+
fs33.chmodSync(filePath, 493);
|
|
31227
31425
|
return "updated";
|
|
31228
31426
|
}
|
|
31229
31427
|
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
31230
|
-
|
|
31428
|
+
fs33.writeFileSync(filePath, `${content}${suffix}
|
|
31231
31429
|
${block}
|
|
31232
31430
|
`);
|
|
31233
|
-
|
|
31431
|
+
fs33.chmodSync(filePath, 493);
|
|
31234
31432
|
return "appended";
|
|
31235
31433
|
}
|
|
31236
31434
|
function removeMarkedBlock(filePath) {
|
|
31237
|
-
if (!
|
|
31238
|
-
const content =
|
|
31435
|
+
if (!fs33.existsSync(filePath)) return false;
|
|
31436
|
+
const content = fs33.readFileSync(filePath, "utf8");
|
|
31239
31437
|
if (!content.includes(MARKER_START)) return false;
|
|
31240
31438
|
const pattern = new RegExp(
|
|
31241
31439
|
`\\n?${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}\\n?`
|
|
31242
31440
|
);
|
|
31243
31441
|
const stripped = content.replace(pattern, "\n");
|
|
31244
31442
|
if (stripped.replace(/^#!\/bin\/sh\n?/, "").trim() === "") {
|
|
31245
|
-
|
|
31443
|
+
fs33.rmSync(filePath);
|
|
31246
31444
|
} else {
|
|
31247
|
-
|
|
31445
|
+
fs33.writeFileSync(filePath, stripped);
|
|
31248
31446
|
}
|
|
31249
31447
|
return true;
|
|
31250
31448
|
}
|
|
@@ -31266,20 +31464,20 @@ Or re-run with --force to write into that directory anyway.`
|
|
|
31266
31464
|
);
|
|
31267
31465
|
}
|
|
31268
31466
|
const hooksDir = resolveHooksDir(checkout);
|
|
31269
|
-
|
|
31467
|
+
fs33.mkdirSync(hooksDir, { recursive: true });
|
|
31270
31468
|
const invocation = options.harInvocation ?? defaultHarInvocation();
|
|
31271
|
-
|
|
31272
|
-
|
|
31469
|
+
fs33.writeFileSync(
|
|
31470
|
+
path37.join(hooksDir, "har-pre-commit"),
|
|
31273
31471
|
buildHookScript(invocation, "check", "har: binary not found; skipping commit gate (reinstall with har hooks install)"),
|
|
31274
31472
|
{ mode: 493 }
|
|
31275
31473
|
);
|
|
31276
|
-
|
|
31277
|
-
|
|
31474
|
+
fs33.writeFileSync(
|
|
31475
|
+
path37.join(hooksDir, "har-post-commit"),
|
|
31278
31476
|
buildHookScript(invocation, "record-commit", "har: binary not found; skipping commit association"),
|
|
31279
31477
|
{ mode: 493 }
|
|
31280
31478
|
);
|
|
31281
|
-
const preCommit = upsertMarkedBlock(
|
|
31282
|
-
const postCommit = upsertMarkedBlock(
|
|
31479
|
+
const preCommit = upsertMarkedBlock(path37.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
|
|
31480
|
+
const postCommit = upsertMarkedBlock(path37.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
|
|
31283
31481
|
ensureValidationsIgnored(checkout);
|
|
31284
31482
|
return { hooksDir, preCommit, postCommit };
|
|
31285
31483
|
}
|
|
@@ -31288,12 +31486,12 @@ function uninstallHooks(repoPath) {
|
|
|
31288
31486
|
if (!checkout) throw new Error(`Not a git repository: ${repoPath}`);
|
|
31289
31487
|
const hooksDir = resolveHooksDir(checkout);
|
|
31290
31488
|
let removed = false;
|
|
31291
|
-
removed = removeMarkedBlock(
|
|
31292
|
-
removed = removeMarkedBlock(
|
|
31489
|
+
removed = removeMarkedBlock(path37.join(hooksDir, "pre-commit")) || removed;
|
|
31490
|
+
removed = removeMarkedBlock(path37.join(hooksDir, "post-commit")) || removed;
|
|
31293
31491
|
for (const file of ["har-pre-commit", "har-post-commit"]) {
|
|
31294
|
-
const full =
|
|
31295
|
-
if (
|
|
31296
|
-
|
|
31492
|
+
const full = path37.join(hooksDir, file);
|
|
31493
|
+
if (fs33.existsSync(full)) {
|
|
31494
|
+
fs33.rmSync(full);
|
|
31297
31495
|
removed = true;
|
|
31298
31496
|
}
|
|
31299
31497
|
}
|
|
@@ -31310,9 +31508,9 @@ function getCommitGateConfig(checkoutDir) {
|
|
|
31310
31508
|
function isAgentWorktree(checkoutDir) {
|
|
31311
31509
|
const branch = getCurrentBranch(checkoutDir);
|
|
31312
31510
|
if (branch && /^har-agent-\d+$/.test(branch)) return true;
|
|
31313
|
-
const worktreesRoot =
|
|
31314
|
-
const resolved =
|
|
31315
|
-
return resolved.startsWith(`${worktreesRoot}${
|
|
31511
|
+
const worktreesRoot = path37.join(os9.homedir(), "worktrees");
|
|
31512
|
+
const resolved = path37.resolve(checkoutDir);
|
|
31513
|
+
return resolved.startsWith(`${worktreesRoot}${path37.sep}`) && /-agent-\d+$/.test(path37.basename(resolved));
|
|
31316
31514
|
}
|
|
31317
31515
|
function resolveEffectiveMode(checkoutDir, gate) {
|
|
31318
31516
|
if (!gate.enabled) return "off";
|
|
@@ -31325,15 +31523,15 @@ function getHooksStatus(repoPath) {
|
|
|
31325
31523
|
const hooksDir = resolveHooksDir(checkout);
|
|
31326
31524
|
const gate = getCommitGateConfig(checkout);
|
|
31327
31525
|
const hasBlock = (name) => {
|
|
31328
|
-
const file =
|
|
31329
|
-
return
|
|
31526
|
+
const file = path37.join(hooksDir, name);
|
|
31527
|
+
return fs33.existsSync(file) && fs33.readFileSync(file, "utf8").includes(MARKER_START);
|
|
31330
31528
|
};
|
|
31331
31529
|
return {
|
|
31332
31530
|
checkout,
|
|
31333
31531
|
hooksDir,
|
|
31334
31532
|
configuredHooksPath: getConfiguredHooksPath(checkout),
|
|
31335
|
-
preCommitInstalled: hasBlock("pre-commit") &&
|
|
31336
|
-
postCommitInstalled: hasBlock("post-commit") &&
|
|
31533
|
+
preCommitInstalled: hasBlock("pre-commit") && fs33.existsSync(path37.join(hooksDir, "har-pre-commit")),
|
|
31534
|
+
postCommitInstalled: hasBlock("post-commit") && fs33.existsSync(path37.join(hooksDir, "har-post-commit")),
|
|
31337
31535
|
gate,
|
|
31338
31536
|
effectiveMode: resolveEffectiveMode(checkout, gate)
|
|
31339
31537
|
};
|
|
@@ -31344,7 +31542,7 @@ function checkCommitGate(cwd) {
|
|
|
31344
31542
|
}
|
|
31345
31543
|
const checkout = resolveCheckoutRoot(cwd);
|
|
31346
31544
|
if (!checkout) return { exitCode: 0, messages: [] };
|
|
31347
|
-
if (!
|
|
31545
|
+
if (!fs33.existsSync(path37.join(checkout, ".har", "stages.json"))) {
|
|
31348
31546
|
return { exitCode: 0, messages: [] };
|
|
31349
31547
|
}
|
|
31350
31548
|
const gate = getCommitGateConfig(checkout);
|
|
@@ -31415,8 +31613,8 @@ async function recordCommitAssociation(cwd) {
|
|
|
31415
31613
|
}
|
|
31416
31614
|
|
|
31417
31615
|
// src/core/claude-hooks.ts
|
|
31418
|
-
var
|
|
31419
|
-
var
|
|
31616
|
+
var fs34 = __toESM(require("fs"));
|
|
31617
|
+
var path38 = __toESM(require("path"));
|
|
31420
31618
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
31421
31619
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
31422
31620
|
var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
|
|
@@ -31427,8 +31625,8 @@ function isHarGuardEntry(entry) {
|
|
|
31427
31625
|
);
|
|
31428
31626
|
}
|
|
31429
31627
|
function readSettings(settingsPath) {
|
|
31430
|
-
if (!
|
|
31431
|
-
const raw =
|
|
31628
|
+
if (!fs34.existsSync(settingsPath)) return {};
|
|
31629
|
+
const raw = fs34.readFileSync(settingsPath, "utf8").trim();
|
|
31432
31630
|
if (raw === "") return {};
|
|
31433
31631
|
const parsed = JSON.parse(raw);
|
|
31434
31632
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -31437,19 +31635,19 @@ function readSettings(settingsPath) {
|
|
|
31437
31635
|
return parsed;
|
|
31438
31636
|
}
|
|
31439
31637
|
function writeSettings(settingsPath, settings) {
|
|
31440
|
-
|
|
31441
|
-
|
|
31638
|
+
fs34.mkdirSync(path38.dirname(settingsPath), { recursive: true });
|
|
31639
|
+
fs34.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
31442
31640
|
}
|
|
31443
31641
|
function installClaudeGuard(repoPath) {
|
|
31444
31642
|
const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
|
|
31445
31643
|
if (!templatePath) {
|
|
31446
31644
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
31447
31645
|
}
|
|
31448
|
-
const guardScript =
|
|
31449
|
-
|
|
31450
|
-
|
|
31451
|
-
|
|
31452
|
-
const settingsPath =
|
|
31646
|
+
const guardScript = path38.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
31647
|
+
fs34.mkdirSync(path38.dirname(guardScript), { recursive: true });
|
|
31648
|
+
fs34.copyFileSync(templatePath, guardScript);
|
|
31649
|
+
fs34.chmodSync(guardScript, 493);
|
|
31650
|
+
const settingsPath = path38.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
31453
31651
|
const settings = readSettings(settingsPath);
|
|
31454
31652
|
const hooks = settings.hooks ?? {};
|
|
31455
31653
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -31463,15 +31661,15 @@ function installClaudeGuard(repoPath) {
|
|
|
31463
31661
|
}
|
|
31464
31662
|
function uninstallClaudeGuard(repoPath) {
|
|
31465
31663
|
let removed = false;
|
|
31466
|
-
const guardScript =
|
|
31467
|
-
if (
|
|
31468
|
-
|
|
31664
|
+
const guardScript = path38.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
31665
|
+
if (fs34.existsSync(guardScript)) {
|
|
31666
|
+
fs34.rmSync(guardScript);
|
|
31469
31667
|
removed = true;
|
|
31470
|
-
const parent =
|
|
31471
|
-
if (
|
|
31668
|
+
const parent = path38.dirname(guardScript);
|
|
31669
|
+
if (fs34.existsSync(parent) && fs34.readdirSync(parent).length === 0) fs34.rmdirSync(parent);
|
|
31472
31670
|
}
|
|
31473
|
-
const settingsPath =
|
|
31474
|
-
if (
|
|
31671
|
+
const settingsPath = path38.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
31672
|
+
if (fs34.existsSync(settingsPath)) {
|
|
31475
31673
|
const settings = readSettings(settingsPath);
|
|
31476
31674
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
31477
31675
|
if (preToolUse) {
|
|
@@ -31496,8 +31694,8 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
31496
31694
|
return { removed };
|
|
31497
31695
|
}
|
|
31498
31696
|
function claudeGuardInstalled(repoPath) {
|
|
31499
|
-
const settingsPath =
|
|
31500
|
-
if (!
|
|
31697
|
+
const settingsPath = path38.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
31698
|
+
if (!fs34.existsSync(settingsPath)) return false;
|
|
31501
31699
|
try {
|
|
31502
31700
|
const settings = readSettings(settingsPath);
|
|
31503
31701
|
return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
|
|
@@ -31513,7 +31711,7 @@ function repoOption(y2) {
|
|
|
31513
31711
|
function handleInstall2(argv) {
|
|
31514
31712
|
try {
|
|
31515
31713
|
if (argv.claude) {
|
|
31516
|
-
const result2 = installClaudeGuard(
|
|
31714
|
+
const result2 = installClaudeGuard(path39.resolve(argv.repo));
|
|
31517
31715
|
success("Claude Code worktree guard installed.");
|
|
31518
31716
|
info(`Guard script: ${result2.guardScript}`);
|
|
31519
31717
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -31521,7 +31719,7 @@ function handleInstall2(argv) {
|
|
|
31521
31719
|
info("Commit both files so the guard travels with the repo.");
|
|
31522
31720
|
return;
|
|
31523
31721
|
}
|
|
31524
|
-
const result = installHooks({ repoPath:
|
|
31722
|
+
const result = installHooks({ repoPath: path39.resolve(argv.repo), force: argv.force });
|
|
31525
31723
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
31526
31724
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
31527
31725
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -31534,7 +31732,7 @@ function handleInstall2(argv) {
|
|
|
31534
31732
|
function handleUninstall(argv) {
|
|
31535
31733
|
try {
|
|
31536
31734
|
if (argv.claude) {
|
|
31537
|
-
const result2 = uninstallClaudeGuard(
|
|
31735
|
+
const result2 = uninstallClaudeGuard(path39.resolve(argv.repo));
|
|
31538
31736
|
if (result2.removed) {
|
|
31539
31737
|
success("Claude Code worktree guard removed.");
|
|
31540
31738
|
} else {
|
|
@@ -31542,7 +31740,7 @@ function handleUninstall(argv) {
|
|
|
31542
31740
|
}
|
|
31543
31741
|
return;
|
|
31544
31742
|
}
|
|
31545
|
-
const result = uninstallHooks(
|
|
31743
|
+
const result = uninstallHooks(path39.resolve(argv.repo));
|
|
31546
31744
|
if (result.removed) {
|
|
31547
31745
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
31548
31746
|
} else {
|
|
@@ -31555,7 +31753,7 @@ function handleUninstall(argv) {
|
|
|
31555
31753
|
}
|
|
31556
31754
|
function handleStatus2(argv) {
|
|
31557
31755
|
try {
|
|
31558
|
-
const status = getHooksStatus(
|
|
31756
|
+
const status = getHooksStatus(path39.resolve(argv.repo));
|
|
31559
31757
|
if (argv.json) {
|
|
31560
31758
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
31561
31759
|
`);
|
|
@@ -31573,7 +31771,7 @@ function handleStatus2(argv) {
|
|
|
31573
31771
|
);
|
|
31574
31772
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
31575
31773
|
info(
|
|
31576
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
31774
|
+
`Claude guard: ${claudeGuardInstalled(path39.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
31577
31775
|
);
|
|
31578
31776
|
} catch (err) {
|
|
31579
31777
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -31834,10 +32032,10 @@ function assignProp(target, prop, value) {
|
|
|
31834
32032
|
configurable: true
|
|
31835
32033
|
});
|
|
31836
32034
|
}
|
|
31837
|
-
function getElementAtPath(obj,
|
|
31838
|
-
if (!
|
|
32035
|
+
function getElementAtPath(obj, path41) {
|
|
32036
|
+
if (!path41)
|
|
31839
32037
|
return obj;
|
|
31840
|
-
return
|
|
32038
|
+
return path41.reduce((acc, key) => acc?.[key], obj);
|
|
31841
32039
|
}
|
|
31842
32040
|
function promiseAllObject(promisesObj) {
|
|
31843
32041
|
const keys = Object.keys(promisesObj);
|
|
@@ -32157,11 +32355,11 @@ function aborted(x2, startIndex = 0) {
|
|
|
32157
32355
|
}
|
|
32158
32356
|
return false;
|
|
32159
32357
|
}
|
|
32160
|
-
function prefixIssues(
|
|
32358
|
+
function prefixIssues(path41, issues) {
|
|
32161
32359
|
return issues.map((iss) => {
|
|
32162
32360
|
var _a3;
|
|
32163
32361
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
32164
|
-
iss.path.unshift(
|
|
32362
|
+
iss.path.unshift(path41);
|
|
32165
32363
|
return iss;
|
|
32166
32364
|
});
|
|
32167
32365
|
}
|
|
@@ -37484,7 +37682,7 @@ var Protocol = class {
|
|
|
37484
37682
|
return;
|
|
37485
37683
|
}
|
|
37486
37684
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
37487
|
-
await new Promise((
|
|
37685
|
+
await new Promise((resolve28) => setTimeout(resolve28, pollInterval));
|
|
37488
37686
|
options?.signal?.throwIfAborted();
|
|
37489
37687
|
}
|
|
37490
37688
|
} catch (error3) {
|
|
@@ -37501,7 +37699,7 @@ var Protocol = class {
|
|
|
37501
37699
|
*/
|
|
37502
37700
|
request(request, resultSchema, options) {
|
|
37503
37701
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
37504
|
-
return new Promise((
|
|
37702
|
+
return new Promise((resolve28, reject) => {
|
|
37505
37703
|
const earlyReject = (error3) => {
|
|
37506
37704
|
reject(error3);
|
|
37507
37705
|
};
|
|
@@ -37579,7 +37777,7 @@ var Protocol = class {
|
|
|
37579
37777
|
if (!parseResult.success) {
|
|
37580
37778
|
reject(parseResult.error);
|
|
37581
37779
|
} else {
|
|
37582
|
-
|
|
37780
|
+
resolve28(parseResult.data);
|
|
37583
37781
|
}
|
|
37584
37782
|
} catch (error3) {
|
|
37585
37783
|
reject(error3);
|
|
@@ -37840,12 +38038,12 @@ var Protocol = class {
|
|
|
37840
38038
|
}
|
|
37841
38039
|
} catch {
|
|
37842
38040
|
}
|
|
37843
|
-
return new Promise((
|
|
38041
|
+
return new Promise((resolve28, reject) => {
|
|
37844
38042
|
if (signal.aborted) {
|
|
37845
38043
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
37846
38044
|
return;
|
|
37847
38045
|
}
|
|
37848
|
-
const timeoutId = setTimeout(
|
|
38046
|
+
const timeoutId = setTimeout(resolve28, interval);
|
|
37849
38047
|
signal.addEventListener("abort", () => {
|
|
37850
38048
|
clearTimeout(timeoutId);
|
|
37851
38049
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -38635,7 +38833,7 @@ var Server = class extends Protocol {
|
|
|
38635
38833
|
};
|
|
38636
38834
|
|
|
38637
38835
|
// src/mcp/server.ts
|
|
38638
|
-
var
|
|
38836
|
+
var path40 = __toESM(require("path"));
|
|
38639
38837
|
|
|
38640
38838
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
38641
38839
|
var import_node_process2 = __toESM(require("node:process"), 1);
|
|
@@ -38718,12 +38916,12 @@ var StdioServerTransport = class {
|
|
|
38718
38916
|
this.onclose?.();
|
|
38719
38917
|
}
|
|
38720
38918
|
send(message) {
|
|
38721
|
-
return new Promise((
|
|
38919
|
+
return new Promise((resolve28) => {
|
|
38722
38920
|
const json = serializeMessage(message);
|
|
38723
38921
|
if (this._stdout.write(json)) {
|
|
38724
|
-
|
|
38922
|
+
resolve28();
|
|
38725
38923
|
} else {
|
|
38726
|
-
this._stdout.once("drain",
|
|
38924
|
+
this._stdout.once("drain", resolve28);
|
|
38727
38925
|
}
|
|
38728
38926
|
});
|
|
38729
38927
|
}
|
|
@@ -39267,7 +39465,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
39267
39465
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
39268
39466
|
const result = await startControlAndSync({
|
|
39269
39467
|
detach: input.detach,
|
|
39270
|
-
cwd:
|
|
39468
|
+
cwd: path40.resolve(input.repo)
|
|
39271
39469
|
});
|
|
39272
39470
|
if (result.code !== 0) {
|
|
39273
39471
|
return {
|