@osfactory/har 0.16.2 → 0.18.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/dist/index.js +736 -469
- package/dist/templates/cursor-rule.mdc.template +1 -1
- package/dist/templates/har-boilerplate/agent-slot.sh +3 -9
- package/dist/templates/har-boilerplate/launch.sh +1 -8
- package/dist/templates/har-boilerplate-cli/agent-cli.sh +0 -2
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +3 -9
- package/dist/templates/har-boilerplate-cli/launch.sh +1 -8
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +2 -5
- package/dist/templates/har-boilerplate-ios/launch.sh +1 -6
- 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 path49 = url.path;
|
|
769
|
+
if (path49.length === 0) {
|
|
770
770
|
return;
|
|
771
771
|
}
|
|
772
|
-
if (url.scheme === "file" &&
|
|
772
|
+
if (url.scheme === "file" && path49.length === 1 && isNormalizedWindowsDriveLetter(path49[0])) {
|
|
773
773
|
return;
|
|
774
774
|
}
|
|
775
|
-
|
|
775
|
+
path49.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(resolve34, 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
|
+
resolve34(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(resolve34, 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
|
+
resolve34(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
|
+
resolve34(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
|
+
resolve34(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
|
+
resolve34(response);
|
|
2981
2981
|
});
|
|
2982
2982
|
raw.on("end", function() {
|
|
2983
2983
|
if (!response) {
|
|
2984
2984
|
response = new Response3(body, response_options);
|
|
2985
|
-
|
|
2985
|
+
resolve34(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
|
+
resolve34(response);
|
|
2994
2994
|
return;
|
|
2995
2995
|
}
|
|
2996
2996
|
response = new Response3(body, response_options);
|
|
2997
|
-
|
|
2997
|
+
resolve34(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(path49, { 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: path49, size, lastModified: mtimeMs });
|
|
6362
6362
|
if (!filename) {
|
|
6363
6363
|
filename = file.name;
|
|
6364
6364
|
}
|
|
@@ -6367,13 +6367,13 @@ function createFileFromPath(path48, { 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(path49, filenameOrOptions, options = {}) {
|
|
6371
|
+
const stats = (0, import_fs5.statSync)(path49);
|
|
6372
|
+
return createFileFromPath(path49, stats, filenameOrOptions, options);
|
|
6373
6373
|
}
|
|
6374
|
-
async function fileFromPath2(
|
|
6375
|
-
const stats = await import_fs5.promises.stat(
|
|
6376
|
-
return createFileFromPath(
|
|
6374
|
+
async function fileFromPath2(path49, filenameOrOptions, options) {
|
|
6375
|
+
const stats = await import_fs5.promises.stat(path49);
|
|
6376
|
+
return createFileFromPath(path49, 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({
|
|
@@ -6433,6 +6433,412 @@ var init_fileFromPath = __esm({
|
|
|
6433
6433
|
}
|
|
6434
6434
|
});
|
|
6435
6435
|
|
|
6436
|
+
// src/core/control-config.ts
|
|
6437
|
+
function getControlApiUrl() {
|
|
6438
|
+
return process.env.HAR_CONTROL_API_URL ?? DEFAULT_CONTROL_API_URL;
|
|
6439
|
+
}
|
|
6440
|
+
function isControlEnabled() {
|
|
6441
|
+
return process.env.HAR_CONTROL_DISABLED !== "true";
|
|
6442
|
+
}
|
|
6443
|
+
var DEFAULT_CONTROL_API_URL;
|
|
6444
|
+
var init_control_config = __esm({
|
|
6445
|
+
"src/core/control-config.ts"() {
|
|
6446
|
+
"use strict";
|
|
6447
|
+
DEFAULT_CONTROL_API_URL = "http://localhost:3847";
|
|
6448
|
+
}
|
|
6449
|
+
});
|
|
6450
|
+
|
|
6451
|
+
// src/core/telemetry-config.ts
|
|
6452
|
+
function getPreferencePath() {
|
|
6453
|
+
if (process.env.HAR_TELEMETRY_CONFIG_PATH) {
|
|
6454
|
+
return path34.resolve(process.env.HAR_TELEMETRY_CONFIG_PATH);
|
|
6455
|
+
}
|
|
6456
|
+
return path34.join(os9.homedir(), ".har", "telemetry.json");
|
|
6457
|
+
}
|
|
6458
|
+
function parseEnvOverride(raw) {
|
|
6459
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
6460
|
+
const normalized = raw.trim().toLowerCase();
|
|
6461
|
+
if (["0", "false", "off", "no", "disabled"].includes(normalized)) return false;
|
|
6462
|
+
if (["1", "true", "on", "yes", "enabled"].includes(normalized)) return true;
|
|
6463
|
+
return void 0;
|
|
6464
|
+
}
|
|
6465
|
+
function normalizeSignals(enabled, raw) {
|
|
6466
|
+
if (!enabled) return { ...DEFAULT_SIGNALS_OFF };
|
|
6467
|
+
return {
|
|
6468
|
+
metrics: raw?.metrics !== false,
|
|
6469
|
+
logs: raw?.logs !== false,
|
|
6470
|
+
prompts: raw?.prompts === true,
|
|
6471
|
+
traces: raw?.traces !== false
|
|
6472
|
+
};
|
|
6473
|
+
}
|
|
6474
|
+
function readTelemetryPreference() {
|
|
6475
|
+
const preferencePath = getPreferencePath();
|
|
6476
|
+
try {
|
|
6477
|
+
if (!fs34.existsSync(preferencePath)) {
|
|
6478
|
+
return { enabled: true, signals: { ...DEFAULT_SIGNALS_ON } };
|
|
6479
|
+
}
|
|
6480
|
+
const parsed = JSON.parse(fs34.readFileSync(preferencePath, "utf8"));
|
|
6481
|
+
const enabled = parsed.enabled !== false;
|
|
6482
|
+
return {
|
|
6483
|
+
enabled,
|
|
6484
|
+
signals: normalizeSignals(enabled, parsed.signals),
|
|
6485
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : void 0
|
|
6486
|
+
};
|
|
6487
|
+
} catch {
|
|
6488
|
+
return { enabled: true, signals: { ...DEFAULT_SIGNALS_ON } };
|
|
6489
|
+
}
|
|
6490
|
+
}
|
|
6491
|
+
function writeTelemetryPreference(enabled, signals) {
|
|
6492
|
+
const current = readTelemetryPreference();
|
|
6493
|
+
const nextSignals = normalizeSignals(enabled, {
|
|
6494
|
+
...current.signals,
|
|
6495
|
+
...signals
|
|
6496
|
+
});
|
|
6497
|
+
const preference = {
|
|
6498
|
+
enabled,
|
|
6499
|
+
signals: enabled ? nextSignals : { ...DEFAULT_SIGNALS_OFF },
|
|
6500
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6501
|
+
};
|
|
6502
|
+
const preferencePath = getPreferencePath();
|
|
6503
|
+
fs34.mkdirSync(path34.dirname(preferencePath), { recursive: true });
|
|
6504
|
+
fs34.writeFileSync(preferencePath, JSON.stringify(preference, null, 2) + "\n");
|
|
6505
|
+
return preference;
|
|
6506
|
+
}
|
|
6507
|
+
function isTelemetryEnabled() {
|
|
6508
|
+
const envOverride = parseEnvOverride(process.env.HAR_TELEMETRY);
|
|
6509
|
+
if (envOverride !== void 0) return envOverride;
|
|
6510
|
+
return readTelemetryPreference().enabled;
|
|
6511
|
+
}
|
|
6512
|
+
function getTelemetrySignals() {
|
|
6513
|
+
if (!isTelemetryEnabled()) return { ...DEFAULT_SIGNALS_OFF };
|
|
6514
|
+
return readTelemetryPreference().signals;
|
|
6515
|
+
}
|
|
6516
|
+
function getTelemetryPreferencePath() {
|
|
6517
|
+
return getPreferencePath();
|
|
6518
|
+
}
|
|
6519
|
+
var fs34, os9, path34, DEFAULT_SIGNALS_ON, DEFAULT_SIGNALS_OFF, TELEMETRY_SIGNALS;
|
|
6520
|
+
var init_telemetry_config = __esm({
|
|
6521
|
+
"src/core/telemetry-config.ts"() {
|
|
6522
|
+
"use strict";
|
|
6523
|
+
fs34 = __toESM(require("fs"));
|
|
6524
|
+
os9 = __toESM(require("os"));
|
|
6525
|
+
path34 = __toESM(require("path"));
|
|
6526
|
+
DEFAULT_SIGNALS_ON = {
|
|
6527
|
+
metrics: true,
|
|
6528
|
+
logs: true,
|
|
6529
|
+
prompts: false,
|
|
6530
|
+
/** Hooks are traces-first; usage metrics are derived from span gen_ai.usage.* in Mission Control. */
|
|
6531
|
+
traces: true
|
|
6532
|
+
};
|
|
6533
|
+
DEFAULT_SIGNALS_OFF = {
|
|
6534
|
+
metrics: false,
|
|
6535
|
+
logs: false,
|
|
6536
|
+
prompts: false,
|
|
6537
|
+
traces: false
|
|
6538
|
+
};
|
|
6539
|
+
TELEMETRY_SIGNALS = [
|
|
6540
|
+
"Traces (default): Cursor / Claude / Codex activity via opentelemetry-hooks \u2192 Mission Control",
|
|
6541
|
+
"Logs/events (default): hook lifecycle logs without prompt bodies",
|
|
6542
|
+
"Metrics (default): token usage derived from span gen_ai.usage.* attributes",
|
|
6543
|
+
"Prompts (opt-in): user prompt text via IDE_OTEL_CAPTURE_TEXT \u2014 har telemetry on --prompts (also fills Mission Control purpose)",
|
|
6544
|
+
"Fallback: har control sync harvests local Claude/Codex session files when hooks telemetry is missing"
|
|
6545
|
+
];
|
|
6546
|
+
}
|
|
6547
|
+
});
|
|
6548
|
+
|
|
6549
|
+
// src/core/otel-hooks.ts
|
|
6550
|
+
var otel_hooks_exports = {};
|
|
6551
|
+
__export(otel_hooks_exports, {
|
|
6552
|
+
OTEL_HOOKS_AGENTS: () => OTEL_HOOKS_AGENTS,
|
|
6553
|
+
OTEL_HOOKS_PACKAGE: () => OTEL_HOOKS_PACKAGE,
|
|
6554
|
+
buildOtelHooksConfig: () => buildOtelHooksConfig,
|
|
6555
|
+
disableOtelHooksExport: () => disableOtelHooksExport,
|
|
6556
|
+
ensureOtelHooks: () => ensureOtelHooks,
|
|
6557
|
+
getOtelHooksConfigPath: () => getOtelHooksConfigPath,
|
|
6558
|
+
getOtelHooksHome: () => getOtelHooksHome,
|
|
6559
|
+
getOtelHooksWrapperPath: () => getOtelHooksWrapperPath,
|
|
6560
|
+
rewriteHookCommandsToWrapper: () => rewriteHookCommandsToWrapper,
|
|
6561
|
+
writeOtelHooksConfig: () => writeOtelHooksConfig,
|
|
6562
|
+
writeOtelHooksWrapper: () => writeOtelHooksWrapper
|
|
6563
|
+
});
|
|
6564
|
+
function getOtelHooksHome() {
|
|
6565
|
+
if (process.env.HAR_OTEL_HOOKS_HOME) {
|
|
6566
|
+
return path40.resolve(process.env.HAR_OTEL_HOOKS_HOME);
|
|
6567
|
+
}
|
|
6568
|
+
return path40.join(os12.homedir(), ".har", "otel-hooks");
|
|
6569
|
+
}
|
|
6570
|
+
function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
|
|
6571
|
+
return path40.join(hooksHome, "otel_config.json");
|
|
6572
|
+
}
|
|
6573
|
+
function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
|
|
6574
|
+
return path40.join(hooksHome, "run-otel-hook.sh");
|
|
6575
|
+
}
|
|
6576
|
+
function buildOtelHooksConfig(options) {
|
|
6577
|
+
const enabled = options?.enabled ?? isTelemetryEnabled();
|
|
6578
|
+
const signals = getTelemetrySignals();
|
|
6579
|
+
const apiUrl = (options?.apiUrl ?? getControlApiUrl()).replace(/\/$/, "");
|
|
6580
|
+
return {
|
|
6581
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: enabled ? `${apiUrl}/api/otel/v1/traces` : null,
|
|
6582
|
+
OTEL_EXPORTER_OTLP_PROTOCOL: "http/json",
|
|
6583
|
+
OTEL_SERVICE_NAME: "har-ide-agent",
|
|
6584
|
+
IDE_OTEL_BATCH_ON_STOP: "true",
|
|
6585
|
+
IDE_OTEL_ENABLE_LOGS: enabled && signals.logs ? "true" : "false",
|
|
6586
|
+
IDE_OTEL_LOG_ALL_EVENTS: enabled && signals.logs ? "true" : "false",
|
|
6587
|
+
IDE_OTEL_CAPTURE_TEXT: enabled && signals.prompts ? "true" : "false",
|
|
6588
|
+
IDE_OTEL_MASK_PROMPTS: "false",
|
|
6589
|
+
OTEL_RESOURCE_ATTRIBUTES: options?.resourceAttributes ?? null
|
|
6590
|
+
};
|
|
6591
|
+
}
|
|
6592
|
+
function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
|
|
6593
|
+
fs38.mkdirSync(hooksHome, { recursive: true });
|
|
6594
|
+
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
6595
|
+
const payload = {
|
|
6596
|
+
_comment: "Managed by har telemetry \u2014 do not edit by hand; use: har telemetry on|off",
|
|
6597
|
+
...config2
|
|
6598
|
+
};
|
|
6599
|
+
fs38.writeFileSync(configPath, `${JSON.stringify(payload, null, 2)}
|
|
6600
|
+
`);
|
|
6601
|
+
return configPath;
|
|
6602
|
+
}
|
|
6603
|
+
function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
|
|
6604
|
+
fs38.mkdirSync(hooksHome, { recursive: true });
|
|
6605
|
+
const wrapperPath = getOtelHooksWrapperPath(hooksHome);
|
|
6606
|
+
const script = `#!/usr/bin/env bash
|
|
6607
|
+
# Managed by har telemetry \u2014 invokes opentelemetry-hooks with HAR config home.
|
|
6608
|
+
set -euo pipefail
|
|
6609
|
+
export IDE_OTEL_HOOK_HOME="${hooksHome}"
|
|
6610
|
+
exec "${otelHookCommand}" "$@"
|
|
6611
|
+
`;
|
|
6612
|
+
fs38.writeFileSync(wrapperPath, script, { mode: 493 });
|
|
6613
|
+
try {
|
|
6614
|
+
fs38.chmodSync(wrapperPath, 493);
|
|
6615
|
+
} catch {
|
|
6616
|
+
}
|
|
6617
|
+
return wrapperPath;
|
|
6618
|
+
}
|
|
6619
|
+
function commandExists(command2) {
|
|
6620
|
+
const result = (0, import_child_process9.spawnSync)("sh", ["-c", `command -v ${JSON.stringify(command2)}`], {
|
|
6621
|
+
encoding: "utf8"
|
|
6622
|
+
});
|
|
6623
|
+
return result.status === 0 && Boolean(result.stdout?.trim());
|
|
6624
|
+
}
|
|
6625
|
+
function resolveOtelHookCommand() {
|
|
6626
|
+
if (commandExists("otel-hook")) {
|
|
6627
|
+
const which = (0, import_child_process9.spawnSync)("sh", ["-c", "command -v otel-hook"], { encoding: "utf8" });
|
|
6628
|
+
return which.stdout?.trim() || "otel-hook";
|
|
6629
|
+
}
|
|
6630
|
+
return null;
|
|
6631
|
+
}
|
|
6632
|
+
function tryInstallPackage() {
|
|
6633
|
+
if (commandExists("uv")) {
|
|
6634
|
+
const result = (0, import_child_process9.spawnSync)(
|
|
6635
|
+
"uv",
|
|
6636
|
+
["tool", "install", "--force", OTEL_HOOKS_PACKAGE],
|
|
6637
|
+
{ encoding: "utf8", timeout: 18e4 }
|
|
6638
|
+
);
|
|
6639
|
+
if (result.status === 0) {
|
|
6640
|
+
return { ok: true, detail: `uv tool install ${OTEL_HOOKS_PACKAGE}` };
|
|
6641
|
+
}
|
|
6642
|
+
}
|
|
6643
|
+
if (commandExists("pipx")) {
|
|
6644
|
+
const result = (0, import_child_process9.spawnSync)("pipx", ["install", "--force", OTEL_HOOKS_PACKAGE], {
|
|
6645
|
+
encoding: "utf8",
|
|
6646
|
+
timeout: 18e4
|
|
6647
|
+
});
|
|
6648
|
+
if (result.status === 0) {
|
|
6649
|
+
return { ok: true, detail: `pipx install ${OTEL_HOOKS_PACKAGE}` };
|
|
6650
|
+
}
|
|
6651
|
+
return {
|
|
6652
|
+
ok: false,
|
|
6653
|
+
detail: `pipx install failed: ${(result.stderr || result.stdout || "").trim().slice(0, 400)}`
|
|
6654
|
+
};
|
|
6655
|
+
}
|
|
6656
|
+
if (commandExists("pip3") || commandExists("pip")) {
|
|
6657
|
+
const pip = commandExists("pip3") ? "pip3" : "pip";
|
|
6658
|
+
const result = (0, import_child_process9.spawnSync)(
|
|
6659
|
+
pip,
|
|
6660
|
+
["install", "--user", OTEL_HOOKS_PACKAGE],
|
|
6661
|
+
{ encoding: "utf8", timeout: 18e4 }
|
|
6662
|
+
);
|
|
6663
|
+
if (result.status === 0) {
|
|
6664
|
+
return { ok: true, detail: `${pip} install --user ${OTEL_HOOKS_PACKAGE}` };
|
|
6665
|
+
}
|
|
6666
|
+
return {
|
|
6667
|
+
ok: false,
|
|
6668
|
+
detail: `${pip} install failed: ${(result.stderr || result.stdout || "").trim().slice(0, 400)}`
|
|
6669
|
+
};
|
|
6670
|
+
}
|
|
6671
|
+
return {
|
|
6672
|
+
ok: false,
|
|
6673
|
+
detail: "Neither uv, pipx, nor pip3/pip found; install Python tooling to use opentelemetry-hooks"
|
|
6674
|
+
};
|
|
6675
|
+
}
|
|
6676
|
+
function runSetupAgent(agent, otelHookCommand, hooksHome) {
|
|
6677
|
+
const result = (0, import_child_process9.spawnSync)(otelHookCommand, ["setup", "--agent", agent], {
|
|
6678
|
+
encoding: "utf8",
|
|
6679
|
+
env: {
|
|
6680
|
+
...process.env,
|
|
6681
|
+
IDE_OTEL_HOOK_HOME: hooksHome
|
|
6682
|
+
},
|
|
6683
|
+
timeout: 6e4
|
|
6684
|
+
});
|
|
6685
|
+
if (result.status === 0) {
|
|
6686
|
+
return { ok: true, detail: `setup --agent ${agent}` };
|
|
6687
|
+
}
|
|
6688
|
+
return {
|
|
6689
|
+
ok: false,
|
|
6690
|
+
detail: `setup --agent ${agent} failed: ${(result.stderr || result.stdout || "").trim().slice(0, 400)}`
|
|
6691
|
+
};
|
|
6692
|
+
}
|
|
6693
|
+
function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
6694
|
+
if (!fs38.existsSync(filePath)) return false;
|
|
6695
|
+
let raw;
|
|
6696
|
+
try {
|
|
6697
|
+
raw = fs38.readFileSync(filePath, "utf8");
|
|
6698
|
+
} catch {
|
|
6699
|
+
return false;
|
|
6700
|
+
}
|
|
6701
|
+
let parsed;
|
|
6702
|
+
try {
|
|
6703
|
+
parsed = JSON.parse(raw);
|
|
6704
|
+
} catch {
|
|
6705
|
+
return false;
|
|
6706
|
+
}
|
|
6707
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
6708
|
+
const quoted = JSON.stringify(wrapperPath);
|
|
6709
|
+
const rewriteCommand = (command2) => {
|
|
6710
|
+
if (!command2.includes("otel-hook") && !command2.includes("otel_hook.py")) return command2;
|
|
6711
|
+
if (command2.includes(wrapperPath)) return command2;
|
|
6712
|
+
return command2.replace(
|
|
6713
|
+
/(?:^|[;&|]\s*)(?:env\s+[^=\s]+=\S+\s+)*(?:python3?\s+)?(?:\S*otel[_-]hook\S*)/,
|
|
6714
|
+
(match) => match.replace(/(?:python3?\s+)?(?:\S*otel[_-]hook\S*)/, quoted.slice(1, -1))
|
|
6715
|
+
);
|
|
6716
|
+
};
|
|
6717
|
+
const walk = (node) => {
|
|
6718
|
+
let changed = false;
|
|
6719
|
+
if (Array.isArray(node)) {
|
|
6720
|
+
for (const item of node) changed = walk(item) || changed;
|
|
6721
|
+
return changed;
|
|
6722
|
+
}
|
|
6723
|
+
if (!node || typeof node !== "object") return false;
|
|
6724
|
+
const obj = node;
|
|
6725
|
+
if (typeof obj.command === "string") {
|
|
6726
|
+
const next = rewriteCommand(obj.command);
|
|
6727
|
+
if (next !== obj.command) {
|
|
6728
|
+
obj.command = next;
|
|
6729
|
+
changed = true;
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
for (const value of Object.values(obj)) changed = walk(value) || changed;
|
|
6733
|
+
return changed;
|
|
6734
|
+
};
|
|
6735
|
+
if (!walk(parsed)) return false;
|
|
6736
|
+
fs38.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
6737
|
+
`);
|
|
6738
|
+
return true;
|
|
6739
|
+
}
|
|
6740
|
+
function rewriteKnownHookRegistrations(wrapperPath) {
|
|
6741
|
+
const home = os12.homedir();
|
|
6742
|
+
const candidates = [
|
|
6743
|
+
path40.join(home, ".cursor", "hooks.json"),
|
|
6744
|
+
path40.join(home, ".claude", "settings.json"),
|
|
6745
|
+
path40.join(home, ".codex", "hooks.json")
|
|
6746
|
+
];
|
|
6747
|
+
for (const filePath of candidates) {
|
|
6748
|
+
try {
|
|
6749
|
+
rewriteHookCommandsToWrapper(filePath, wrapperPath);
|
|
6750
|
+
} catch {
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
}
|
|
6754
|
+
function ensureOtelHooks(options) {
|
|
6755
|
+
const hooksHome = getOtelHooksHome();
|
|
6756
|
+
const errors = [];
|
|
6757
|
+
const agentsSetup = [];
|
|
6758
|
+
fs38.mkdirSync(hooksHome, { recursive: true });
|
|
6759
|
+
let otelHookCommand = resolveOtelHookCommand();
|
|
6760
|
+
if (!otelHookCommand) {
|
|
6761
|
+
const installed = tryInstallPackage();
|
|
6762
|
+
if (!installed.ok) {
|
|
6763
|
+
errors.push(installed.detail);
|
|
6764
|
+
const configPath2 = writeOtelHooksConfig(
|
|
6765
|
+
buildOtelHooksConfig({ resourceAttributes: options?.resourceAttributes }),
|
|
6766
|
+
hooksHome
|
|
6767
|
+
);
|
|
6768
|
+
return {
|
|
6769
|
+
ok: false,
|
|
6770
|
+
hooksHome,
|
|
6771
|
+
configPath: configPath2,
|
|
6772
|
+
wrapperPath: getOtelHooksWrapperPath(hooksHome),
|
|
6773
|
+
otelHookCommand: null,
|
|
6774
|
+
warning: installed.detail,
|
|
6775
|
+
agentsSetup,
|
|
6776
|
+
errors
|
|
6777
|
+
};
|
|
6778
|
+
}
|
|
6779
|
+
otelHookCommand = resolveOtelHookCommand();
|
|
6780
|
+
if (!otelHookCommand) {
|
|
6781
|
+
errors.push("opentelemetry-hooks installed but otel-hook is not on PATH");
|
|
6782
|
+
const configPath2 = writeOtelHooksConfig(
|
|
6783
|
+
buildOtelHooksConfig({ resourceAttributes: options?.resourceAttributes }),
|
|
6784
|
+
hooksHome
|
|
6785
|
+
);
|
|
6786
|
+
return {
|
|
6787
|
+
ok: false,
|
|
6788
|
+
hooksHome,
|
|
6789
|
+
configPath: configPath2,
|
|
6790
|
+
wrapperPath: getOtelHooksWrapperPath(hooksHome),
|
|
6791
|
+
otelHookCommand: null,
|
|
6792
|
+
warning: errors[errors.length - 1],
|
|
6793
|
+
agentsSetup,
|
|
6794
|
+
errors
|
|
6795
|
+
};
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
const configPath = writeOtelHooksConfig(
|
|
6799
|
+
buildOtelHooksConfig({ resourceAttributes: options?.resourceAttributes }),
|
|
6800
|
+
hooksHome
|
|
6801
|
+
);
|
|
6802
|
+
const wrapperPath = writeOtelHooksWrapper(otelHookCommand, hooksHome);
|
|
6803
|
+
if (options?.setupAgents !== false && isTelemetryEnabled()) {
|
|
6804
|
+
for (const agent of OTEL_HOOKS_AGENTS) {
|
|
6805
|
+
const setup = runSetupAgent(agent, otelHookCommand, hooksHome);
|
|
6806
|
+
if (setup.ok) agentsSetup.push(agent);
|
|
6807
|
+
else errors.push(setup.detail);
|
|
6808
|
+
}
|
|
6809
|
+
rewriteKnownHookRegistrations(wrapperPath);
|
|
6810
|
+
}
|
|
6811
|
+
const ok = errors.length === 0;
|
|
6812
|
+
return {
|
|
6813
|
+
ok,
|
|
6814
|
+
hooksHome,
|
|
6815
|
+
configPath,
|
|
6816
|
+
wrapperPath,
|
|
6817
|
+
otelHookCommand,
|
|
6818
|
+
message: ok ? `opentelemetry-hooks ready (${agentsSetup.join(", ") || "config only"}) \u2192 ${configPath}` : void 0,
|
|
6819
|
+
warning: errors.length ? errors.join("; ") : void 0,
|
|
6820
|
+
agentsSetup,
|
|
6821
|
+
errors
|
|
6822
|
+
};
|
|
6823
|
+
}
|
|
6824
|
+
function disableOtelHooksExport() {
|
|
6825
|
+
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
6826
|
+
}
|
|
6827
|
+
var import_child_process9, fs38, os12, path40, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_AGENTS;
|
|
6828
|
+
var init_otel_hooks = __esm({
|
|
6829
|
+
"src/core/otel-hooks.ts"() {
|
|
6830
|
+
"use strict";
|
|
6831
|
+
import_child_process9 = require("child_process");
|
|
6832
|
+
fs38 = __toESM(require("fs"));
|
|
6833
|
+
os12 = __toESM(require("os"));
|
|
6834
|
+
path40 = __toESM(require("path"));
|
|
6835
|
+
init_control_config();
|
|
6836
|
+
init_telemetry_config();
|
|
6837
|
+
OTEL_HOOKS_PACKAGE = "opentelemetry-hooks==0.14.0";
|
|
6838
|
+
OTEL_HOOKS_AGENTS = ["cursor", "claude", "codex"];
|
|
6839
|
+
}
|
|
6840
|
+
});
|
|
6841
|
+
|
|
6436
6842
|
// node_modules/ajv/dist/compile/codegen/code.js
|
|
6437
6843
|
var require_code = __commonJS({
|
|
6438
6844
|
"node_modules/ajv/dist/compile/codegen/code.js"(exports2) {
|
|
@@ -9384,7 +9790,7 @@ var require_compile = __commonJS({
|
|
|
9384
9790
|
const schOrFunc = root.refs[ref];
|
|
9385
9791
|
if (schOrFunc)
|
|
9386
9792
|
return schOrFunc;
|
|
9387
|
-
let _sch =
|
|
9793
|
+
let _sch = resolve34.call(this, root, ref);
|
|
9388
9794
|
if (_sch === void 0) {
|
|
9389
9795
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
9390
9796
|
const { schemaId } = this.opts;
|
|
@@ -9411,7 +9817,7 @@ var require_compile = __commonJS({
|
|
|
9411
9817
|
function sameSchemaEnv(s1, s2) {
|
|
9412
9818
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
9413
9819
|
}
|
|
9414
|
-
function
|
|
9820
|
+
function resolve34(root, ref) {
|
|
9415
9821
|
let sch;
|
|
9416
9822
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
9417
9823
|
ref = sch;
|
|
@@ -9629,8 +10035,8 @@ var require_utils2 = __commonJS({
|
|
|
9629
10035
|
}
|
|
9630
10036
|
return ind;
|
|
9631
10037
|
}
|
|
9632
|
-
function removeDotSegments(
|
|
9633
|
-
let input =
|
|
10038
|
+
function removeDotSegments(path49) {
|
|
10039
|
+
let input = path49;
|
|
9634
10040
|
const output = [];
|
|
9635
10041
|
let nextSlash = -1;
|
|
9636
10042
|
let len = 0;
|
|
@@ -9882,8 +10288,8 @@ var require_schemes = __commonJS({
|
|
|
9882
10288
|
wsComponent.secure = void 0;
|
|
9883
10289
|
}
|
|
9884
10290
|
if (wsComponent.resourceName) {
|
|
9885
|
-
const [
|
|
9886
|
-
wsComponent.path =
|
|
10291
|
+
const [path49, query] = wsComponent.resourceName.split("?");
|
|
10292
|
+
wsComponent.path = path49 && path49 !== "/" ? path49 : void 0;
|
|
9887
10293
|
wsComponent.query = query;
|
|
9888
10294
|
wsComponent.resourceName = void 0;
|
|
9889
10295
|
}
|
|
@@ -10042,7 +10448,7 @@ var require_fast_uri = __commonJS({
|
|
|
10042
10448
|
}
|
|
10043
10449
|
return uri;
|
|
10044
10450
|
}
|
|
10045
|
-
function
|
|
10451
|
+
function resolve34(baseURI, relativeURI, options) {
|
|
10046
10452
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
10047
10453
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
10048
10454
|
schemelessOptions.skipEscape = true;
|
|
@@ -10300,7 +10706,7 @@ var require_fast_uri = __commonJS({
|
|
|
10300
10706
|
var fastUri = {
|
|
10301
10707
|
SCHEMES,
|
|
10302
10708
|
normalize: normalize3,
|
|
10303
|
-
resolve:
|
|
10709
|
+
resolve: resolve34,
|
|
10304
10710
|
resolveComponent,
|
|
10305
10711
|
equal,
|
|
10306
10712
|
serialize,
|
|
@@ -14565,11 +14971,11 @@ var parser = new YargsParser({
|
|
|
14565
14971
|
resolve: import_path2.resolve,
|
|
14566
14972
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
14567
14973
|
// we can exercise all the lines below:
|
|
14568
|
-
require: (
|
|
14974
|
+
require: (path49) => {
|
|
14569
14975
|
if (typeof require !== "undefined") {
|
|
14570
|
-
return require(
|
|
14571
|
-
} else if (
|
|
14572
|
-
return JSON.parse((0, import_fs2.readFileSync)(
|
|
14976
|
+
return require(path49);
|
|
14977
|
+
} else if (path49.match(/\.json$/)) {
|
|
14978
|
+
return JSON.parse((0, import_fs2.readFileSync)(path49, "utf8"));
|
|
14573
14979
|
} else {
|
|
14574
14980
|
throw Error("only .json config files are supported in ESM");
|
|
14575
14981
|
}
|
|
@@ -17095,12 +17501,12 @@ var YargsInstance = class {
|
|
|
17095
17501
|
async getCompletion(args, done) {
|
|
17096
17502
|
argsert("<array> [function]", [args, done], arguments.length);
|
|
17097
17503
|
if (!done) {
|
|
17098
|
-
return new Promise((
|
|
17504
|
+
return new Promise((resolve34, reject) => {
|
|
17099
17505
|
__classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
|
|
17100
17506
|
if (err)
|
|
17101
17507
|
reject(err);
|
|
17102
17508
|
else
|
|
17103
|
-
|
|
17509
|
+
resolve34(completions);
|
|
17104
17510
|
});
|
|
17105
17511
|
});
|
|
17106
17512
|
} else {
|
|
@@ -19250,8 +19656,8 @@ function getErrorMap() {
|
|
|
19250
19656
|
|
|
19251
19657
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
19252
19658
|
var makeIssue = (params) => {
|
|
19253
|
-
const { data, path:
|
|
19254
|
-
const fullPath = [...
|
|
19659
|
+
const { data, path: path49, errorMaps, issueData } = params;
|
|
19660
|
+
const fullPath = [...path49, ...issueData.path || []];
|
|
19255
19661
|
const fullIssue = {
|
|
19256
19662
|
...issueData,
|
|
19257
19663
|
path: fullPath
|
|
@@ -19367,11 +19773,11 @@ var errorUtil;
|
|
|
19367
19773
|
|
|
19368
19774
|
// node_modules/zod/v3/types.js
|
|
19369
19775
|
var ParseInputLazyPath = class {
|
|
19370
|
-
constructor(parent, value,
|
|
19776
|
+
constructor(parent, value, path49, key) {
|
|
19371
19777
|
this._cachedPath = [];
|
|
19372
19778
|
this.parent = parent;
|
|
19373
19779
|
this.data = value;
|
|
19374
|
-
this._path =
|
|
19780
|
+
this._path = path49;
|
|
19375
19781
|
this._key = key;
|
|
19376
19782
|
}
|
|
19377
19783
|
get path() {
|
|
@@ -22992,7 +23398,6 @@ var SlotRegistryEntrySchema = external_exports.object({
|
|
|
22992
23398
|
/** Random per-session chars; absent in root mode. */
|
|
22993
23399
|
suffix: external_exports.string().optional(),
|
|
22994
23400
|
createdAt: external_exports.string(),
|
|
22995
|
-
purpose: external_exports.string().optional(),
|
|
22996
23401
|
ports: external_exports.record(external_exports.number()).optional(),
|
|
22997
23402
|
previewUrls: external_exports.record(external_exports.string()).optional(),
|
|
22998
23403
|
status: external_exports.enum(["starting", "active", "failed", "completed"]).default("active"),
|
|
@@ -23038,6 +23443,7 @@ var AgentSlotStatusSchema = external_exports.object({
|
|
|
23038
23443
|
baseBranch: external_exports.string().optional(),
|
|
23039
23444
|
baseCommit: external_exports.string().optional(),
|
|
23040
23445
|
sessionCreatedAt: external_exports.string().optional(),
|
|
23446
|
+
/** Derived from first captured user prompt (OTEL hooks); not set at launch. */
|
|
23041
23447
|
purpose: external_exports.string().optional(),
|
|
23042
23448
|
sessionStatus: external_exports.enum(["starting", "active", "failed", "completed"]).optional(),
|
|
23043
23449
|
lastError: external_exports.string().optional(),
|
|
@@ -23106,7 +23512,7 @@ var ValidationRecordSchema = external_exports.object({
|
|
|
23106
23512
|
var SyncValidationsInputSchema = external_exports.object({
|
|
23107
23513
|
validations: external_exports.array(ValidationRecordSchema)
|
|
23108
23514
|
});
|
|
23109
|
-
var AgentToolSchema = external_exports.enum(["claude_code", "codex"]);
|
|
23515
|
+
var AgentToolSchema = external_exports.enum(["claude_code", "codex", "cursor"]);
|
|
23110
23516
|
var UsageSourceSchema = external_exports.enum(["otel", "harvest"]);
|
|
23111
23517
|
var AgentSessionUsageSchema = external_exports.object({
|
|
23112
23518
|
sessionKey: external_exports.string().min(1),
|
|
@@ -23410,16 +23816,16 @@ async function handleAgentSkills(options) {
|
|
|
23410
23816
|
}
|
|
23411
23817
|
async function askYesNo(question) {
|
|
23412
23818
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
23413
|
-
return new Promise((
|
|
23819
|
+
return new Promise((resolve34) => {
|
|
23414
23820
|
process.stderr.write(`${question} `);
|
|
23415
23821
|
rl.once("line", (answer) => {
|
|
23416
23822
|
rl.close();
|
|
23417
23823
|
const trimmed = answer.trim();
|
|
23418
23824
|
if (trimmed === "") {
|
|
23419
|
-
|
|
23825
|
+
resolve34(true);
|
|
23420
23826
|
return;
|
|
23421
23827
|
}
|
|
23422
|
-
|
|
23828
|
+
resolve34(/^y(es)?$/i.test(trimmed));
|
|
23423
23829
|
});
|
|
23424
23830
|
});
|
|
23425
23831
|
}
|
|
@@ -23498,7 +23904,7 @@ function handleRemove(argv) {
|
|
|
23498
23904
|
}
|
|
23499
23905
|
|
|
23500
23906
|
// src/cli/commands/env.ts
|
|
23501
|
-
var
|
|
23907
|
+
var path42 = __toESM(require("path"));
|
|
23502
23908
|
|
|
23503
23909
|
// src/core/harness.ts
|
|
23504
23910
|
var fs20 = __toESM(require("fs"));
|
|
@@ -24277,13 +24683,13 @@ var MultipartBody = class {
|
|
|
24277
24683
|
// node_modules/@anthropic-ai/sdk/_shims/node-runtime.mjs
|
|
24278
24684
|
var import_web = require("node:stream/web");
|
|
24279
24685
|
var fileFromPathWarned = false;
|
|
24280
|
-
async function fileFromPath3(
|
|
24686
|
+
async function fileFromPath3(path49, ...args) {
|
|
24281
24687
|
const { fileFromPath: _fileFromPath } = await Promise.resolve().then(() => (init_fileFromPath(), fileFromPath_exports));
|
|
24282
24688
|
if (!fileFromPathWarned) {
|
|
24283
|
-
console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(
|
|
24689
|
+
console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path49)}) instead`);
|
|
24284
24690
|
fileFromPathWarned = true;
|
|
24285
24691
|
}
|
|
24286
|
-
return await _fileFromPath(
|
|
24692
|
+
return await _fileFromPath(path49, ...args);
|
|
24287
24693
|
}
|
|
24288
24694
|
var defaultHttpAgent = new import_agentkeepalive.default({ keepAlive: true, timeout: 5 * 60 * 1e3 });
|
|
24289
24695
|
var defaultHttpsAgent = new import_agentkeepalive.default.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1e3 });
|
|
@@ -24779,8 +25185,8 @@ async function defaultParseResponse(props) {
|
|
|
24779
25185
|
}
|
|
24780
25186
|
var APIPromise = class _APIPromise extends Promise {
|
|
24781
25187
|
constructor(responsePromise, parseResponse = defaultParseResponse) {
|
|
24782
|
-
super((
|
|
24783
|
-
|
|
25188
|
+
super((resolve34) => {
|
|
25189
|
+
resolve34(null);
|
|
24784
25190
|
});
|
|
24785
25191
|
this.responsePromise = responsePromise;
|
|
24786
25192
|
this.parseResponse = parseResponse;
|
|
@@ -24880,29 +25286,29 @@ var APIClient = class {
|
|
|
24880
25286
|
defaultIdempotencyKey() {
|
|
24881
25287
|
return `stainless-node-retry-${uuid4()}`;
|
|
24882
25288
|
}
|
|
24883
|
-
get(
|
|
24884
|
-
return this.methodRequest("get",
|
|
25289
|
+
get(path49, opts) {
|
|
25290
|
+
return this.methodRequest("get", path49, opts);
|
|
24885
25291
|
}
|
|
24886
|
-
post(
|
|
24887
|
-
return this.methodRequest("post",
|
|
25292
|
+
post(path49, opts) {
|
|
25293
|
+
return this.methodRequest("post", path49, opts);
|
|
24888
25294
|
}
|
|
24889
|
-
patch(
|
|
24890
|
-
return this.methodRequest("patch",
|
|
25295
|
+
patch(path49, opts) {
|
|
25296
|
+
return this.methodRequest("patch", path49, opts);
|
|
24891
25297
|
}
|
|
24892
|
-
put(
|
|
24893
|
-
return this.methodRequest("put",
|
|
25298
|
+
put(path49, opts) {
|
|
25299
|
+
return this.methodRequest("put", path49, opts);
|
|
24894
25300
|
}
|
|
24895
|
-
delete(
|
|
24896
|
-
return this.methodRequest("delete",
|
|
25301
|
+
delete(path49, opts) {
|
|
25302
|
+
return this.methodRequest("delete", path49, opts);
|
|
24897
25303
|
}
|
|
24898
|
-
methodRequest(method,
|
|
25304
|
+
methodRequest(method, path49, opts) {
|
|
24899
25305
|
return this.request(Promise.resolve(opts).then(async (opts2) => {
|
|
24900
25306
|
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;
|
|
24901
|
-
return { method, path:
|
|
25307
|
+
return { method, path: path49, ...opts2, body };
|
|
24902
25308
|
}));
|
|
24903
25309
|
}
|
|
24904
|
-
getAPIList(
|
|
24905
|
-
return this.requestAPIList(Page, { method: "get", path:
|
|
25310
|
+
getAPIList(path49, Page, opts) {
|
|
25311
|
+
return this.requestAPIList(Page, { method: "get", path: path49, ...opts });
|
|
24906
25312
|
}
|
|
24907
25313
|
calculateContentLength(body) {
|
|
24908
25314
|
if (typeof body === "string") {
|
|
@@ -24920,10 +25326,10 @@ var APIClient = class {
|
|
|
24920
25326
|
return null;
|
|
24921
25327
|
}
|
|
24922
25328
|
buildRequest(options) {
|
|
24923
|
-
const { method, path:
|
|
25329
|
+
const { method, path: path49, query, headers = {} } = options;
|
|
24924
25330
|
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;
|
|
24925
25331
|
const contentLength = this.calculateContentLength(body);
|
|
24926
|
-
const url = this.buildURL(
|
|
25332
|
+
const url = this.buildURL(path49, query);
|
|
24927
25333
|
if ("timeout" in options)
|
|
24928
25334
|
validatePositiveInteger("timeout", options.timeout);
|
|
24929
25335
|
const timeout = options.timeout ?? this.timeout;
|
|
@@ -25032,8 +25438,8 @@ var APIClient = class {
|
|
|
25032
25438
|
const request = this.makeRequest(options, null);
|
|
25033
25439
|
return new PagePromise(this, request, Page);
|
|
25034
25440
|
}
|
|
25035
|
-
buildURL(
|
|
25036
|
-
const url = isAbsoluteURL(
|
|
25441
|
+
buildURL(path49, query) {
|
|
25442
|
+
const url = isAbsoluteURL(path49) ? new URL(path49) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path49.startsWith("/") ? path49.slice(1) : path49));
|
|
25037
25443
|
const defaultQuery = this.defaultQuery();
|
|
25038
25444
|
if (!isEmptyObj(defaultQuery)) {
|
|
25039
25445
|
query = { ...defaultQuery, ...query };
|
|
@@ -25318,7 +25724,7 @@ var startsWithSchemeRegexp = new RegExp("^(?:[a-z]+:)?//", "i");
|
|
|
25318
25724
|
var isAbsoluteURL = (url) => {
|
|
25319
25725
|
return startsWithSchemeRegexp.test(url);
|
|
25320
25726
|
};
|
|
25321
|
-
var sleep = (ms) => new Promise((
|
|
25727
|
+
var sleep = (ms) => new Promise((resolve34) => setTimeout(resolve34, ms));
|
|
25322
25728
|
var validatePositiveInteger = (name, n2) => {
|
|
25323
25729
|
if (typeof n2 !== "number" || !Number.isInteger(n2)) {
|
|
25324
25730
|
throw new AnthropicError(`${name} must be an integer`);
|
|
@@ -25809,12 +26215,12 @@ var PromptCachingBetaMessageStream = class _PromptCachingBetaMessageStream {
|
|
|
25809
26215
|
}
|
|
25810
26216
|
return this._emit("error", new AnthropicError(String(error3)));
|
|
25811
26217
|
});
|
|
25812
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_connectedPromise, new Promise((
|
|
25813
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveConnectedPromise,
|
|
26218
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_connectedPromise, new Promise((resolve34, reject) => {
|
|
26219
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveConnectedPromise, resolve34, "f");
|
|
25814
26220
|
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_rejectConnectedPromise, reject, "f");
|
|
25815
26221
|
}), "f");
|
|
25816
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_endPromise, new Promise((
|
|
25817
|
-
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveEndPromise,
|
|
26222
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_endPromise, new Promise((resolve34, reject) => {
|
|
26223
|
+
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_resolveEndPromise, resolve34, "f");
|
|
25818
26224
|
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_rejectEndPromise, reject, "f");
|
|
25819
26225
|
}), "f");
|
|
25820
26226
|
__classPrivateFieldGet8(this, _PromptCachingBetaMessageStream_connectedPromise, "f").catch(() => {
|
|
@@ -25943,11 +26349,11 @@ var PromptCachingBetaMessageStream = class _PromptCachingBetaMessageStream {
|
|
|
25943
26349
|
* const message = await stream.emitted('message') // rejects if the stream errors
|
|
25944
26350
|
*/
|
|
25945
26351
|
emitted(event) {
|
|
25946
|
-
return new Promise((
|
|
26352
|
+
return new Promise((resolve34, reject) => {
|
|
25947
26353
|
__classPrivateFieldSet7(this, _PromptCachingBetaMessageStream_catchingPromiseCreated, true, "f");
|
|
25948
26354
|
if (event !== "error")
|
|
25949
26355
|
this.once("error", reject);
|
|
25950
|
-
this.once(event,
|
|
26356
|
+
this.once(event, resolve34);
|
|
25951
26357
|
});
|
|
25952
26358
|
}
|
|
25953
26359
|
async done() {
|
|
@@ -26174,7 +26580,7 @@ var PromptCachingBetaMessageStream = class _PromptCachingBetaMessageStream {
|
|
|
26174
26580
|
if (done) {
|
|
26175
26581
|
return { value: void 0, done: true };
|
|
26176
26582
|
}
|
|
26177
|
-
return new Promise((
|
|
26583
|
+
return new Promise((resolve34, reject) => readQueue.push({ resolve: resolve34, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
|
|
26178
26584
|
}
|
|
26179
26585
|
const chunk = pushQueue.shift();
|
|
26180
26586
|
return { value: chunk, done: false };
|
|
@@ -26322,12 +26728,12 @@ var MessageStream = class _MessageStream {
|
|
|
26322
26728
|
}
|
|
26323
26729
|
return this._emit("error", new AnthropicError(String(error3)));
|
|
26324
26730
|
});
|
|
26325
|
-
__classPrivateFieldSet8(this, _MessageStream_connectedPromise, new Promise((
|
|
26326
|
-
__classPrivateFieldSet8(this, _MessageStream_resolveConnectedPromise,
|
|
26731
|
+
__classPrivateFieldSet8(this, _MessageStream_connectedPromise, new Promise((resolve34, reject) => {
|
|
26732
|
+
__classPrivateFieldSet8(this, _MessageStream_resolveConnectedPromise, resolve34, "f");
|
|
26327
26733
|
__classPrivateFieldSet8(this, _MessageStream_rejectConnectedPromise, reject, "f");
|
|
26328
26734
|
}), "f");
|
|
26329
|
-
__classPrivateFieldSet8(this, _MessageStream_endPromise, new Promise((
|
|
26330
|
-
__classPrivateFieldSet8(this, _MessageStream_resolveEndPromise,
|
|
26735
|
+
__classPrivateFieldSet8(this, _MessageStream_endPromise, new Promise((resolve34, reject) => {
|
|
26736
|
+
__classPrivateFieldSet8(this, _MessageStream_resolveEndPromise, resolve34, "f");
|
|
26331
26737
|
__classPrivateFieldSet8(this, _MessageStream_rejectEndPromise, reject, "f");
|
|
26332
26738
|
}), "f");
|
|
26333
26739
|
__classPrivateFieldGet9(this, _MessageStream_connectedPromise, "f").catch(() => {
|
|
@@ -26456,11 +26862,11 @@ var MessageStream = class _MessageStream {
|
|
|
26456
26862
|
* const message = await stream.emitted('message') // rejects if the stream errors
|
|
26457
26863
|
*/
|
|
26458
26864
|
emitted(event) {
|
|
26459
|
-
return new Promise((
|
|
26865
|
+
return new Promise((resolve34, reject) => {
|
|
26460
26866
|
__classPrivateFieldSet8(this, _MessageStream_catchingPromiseCreated, true, "f");
|
|
26461
26867
|
if (event !== "error")
|
|
26462
26868
|
this.once("error", reject);
|
|
26463
|
-
this.once(event,
|
|
26869
|
+
this.once(event, resolve34);
|
|
26464
26870
|
});
|
|
26465
26871
|
}
|
|
26466
26872
|
async done() {
|
|
@@ -26687,7 +27093,7 @@ var MessageStream = class _MessageStream {
|
|
|
26687
27093
|
if (done) {
|
|
26688
27094
|
return { value: void 0, done: true };
|
|
26689
27095
|
}
|
|
26690
|
-
return new Promise((
|
|
27096
|
+
return new Promise((resolve34, reject) => readQueue.push({ resolve: resolve34, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
|
|
26691
27097
|
}
|
|
26692
27098
|
const chunk = pushQueue.shift();
|
|
26693
27099
|
return { value: chunk, done: false };
|
|
@@ -26947,11 +27353,11 @@ async function promptApplyAgentMdProposal(repoPath) {
|
|
|
26947
27353
|
}
|
|
26948
27354
|
async function askYesNo2(question) {
|
|
26949
27355
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
26950
|
-
return new Promise((
|
|
27356
|
+
return new Promise((resolve34) => {
|
|
26951
27357
|
process.stderr.write(`${question} `);
|
|
26952
27358
|
rl.once("line", (answer) => {
|
|
26953
27359
|
rl.close();
|
|
26954
|
-
|
|
27360
|
+
resolve34(/^y(es)?$/i.test(answer.trim()));
|
|
26955
27361
|
});
|
|
26956
27362
|
});
|
|
26957
27363
|
}
|
|
@@ -27181,7 +27587,7 @@ async function executeAuthoringToolCall(toolName, input, repoPath, harnessDir, c
|
|
|
27181
27587
|
}
|
|
27182
27588
|
async function askUser(question, options) {
|
|
27183
27589
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
27184
|
-
return new Promise((
|
|
27590
|
+
return new Promise((resolve34) => {
|
|
27185
27591
|
process.stderr.write("\n");
|
|
27186
27592
|
process.stderr.write(`\u2753 ${question}
|
|
27187
27593
|
`);
|
|
@@ -27192,7 +27598,7 @@ async function askUser(question, options) {
|
|
|
27192
27598
|
process.stderr.write("> ");
|
|
27193
27599
|
rl.once("line", (answer) => {
|
|
27194
27600
|
rl.close();
|
|
27195
|
-
|
|
27601
|
+
resolve34(answer.trim());
|
|
27196
27602
|
});
|
|
27197
27603
|
});
|
|
27198
27604
|
}
|
|
@@ -27336,7 +27742,7 @@ function runScript(scriptPath, args = [], options = {}) {
|
|
|
27336
27742
|
function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
27337
27743
|
const stream = options.stream ?? false;
|
|
27338
27744
|
const { stream: _stream, ...spawnOptions } = options;
|
|
27339
|
-
return new Promise((
|
|
27745
|
+
return new Promise((resolve34) => {
|
|
27340
27746
|
const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
|
|
27341
27747
|
...spawnOptions,
|
|
27342
27748
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -27351,13 +27757,13 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
27351
27757
|
stderr += d2;
|
|
27352
27758
|
if (stream) process.stderr.write(d2);
|
|
27353
27759
|
});
|
|
27354
|
-
proc.on("close", (code) =>
|
|
27760
|
+
proc.on("close", (code) => resolve34({ stdout, stderr, code: code ?? 0 }));
|
|
27355
27761
|
});
|
|
27356
27762
|
}
|
|
27357
27763
|
function runShellCommand(command2, options = {}) {
|
|
27358
27764
|
const stream = options.stream ?? false;
|
|
27359
27765
|
const { stream: _stream, ...spawnOptions } = options;
|
|
27360
|
-
return new Promise((
|
|
27766
|
+
return new Promise((resolve34) => {
|
|
27361
27767
|
const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
|
|
27362
27768
|
...spawnOptions,
|
|
27363
27769
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -27372,7 +27778,7 @@ function runShellCommand(command2, options = {}) {
|
|
|
27372
27778
|
stderr += d2;
|
|
27373
27779
|
if (stream) process.stderr.write(d2);
|
|
27374
27780
|
});
|
|
27375
|
-
proc.on("close", (code) =>
|
|
27781
|
+
proc.on("close", (code) => resolve34({ stdout, stderr, code: code ?? 0 }));
|
|
27376
27782
|
});
|
|
27377
27783
|
}
|
|
27378
27784
|
|
|
@@ -28536,16 +28942,16 @@ async function promptScaffoldCursorRule(exists) {
|
|
|
28536
28942
|
}
|
|
28537
28943
|
async function askYesNo3(question) {
|
|
28538
28944
|
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
28539
|
-
return new Promise((
|
|
28945
|
+
return new Promise((resolve34) => {
|
|
28540
28946
|
process.stderr.write(`${question} `);
|
|
28541
28947
|
rl.once("line", (answer) => {
|
|
28542
28948
|
rl.close();
|
|
28543
28949
|
const trimmed = answer.trim();
|
|
28544
28950
|
if (trimmed === "") {
|
|
28545
|
-
|
|
28951
|
+
resolve34(true);
|
|
28546
28952
|
return;
|
|
28547
28953
|
}
|
|
28548
|
-
|
|
28954
|
+
resolve34(/^y(es)?$/i.test(trimmed));
|
|
28549
28955
|
});
|
|
28550
28956
|
});
|
|
28551
28957
|
}
|
|
@@ -28652,6 +29058,19 @@ function readSlotRegistry(repoPath, agentId) {
|
|
|
28652
29058
|
}
|
|
28653
29059
|
|
|
28654
29060
|
// src/core/local-executor.ts
|
|
29061
|
+
function quoteShellArg(arg) {
|
|
29062
|
+
if (/^[A-Za-z0-9_./:=+-]+$/.test(arg)) return arg;
|
|
29063
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
29064
|
+
}
|
|
29065
|
+
function buildLaunchFlagArgs(flags) {
|
|
29066
|
+
const args = [];
|
|
29067
|
+
if (flags.worktree === false) args.push("--no-worktree");
|
|
29068
|
+
if (flags.claude) args.push("--claude");
|
|
29069
|
+
if (flags.confirmReplace) args.push("--replace");
|
|
29070
|
+
if (flags.force) args.push("--force");
|
|
29071
|
+
if (flags.resume) args.push("--resume");
|
|
29072
|
+
return args;
|
|
29073
|
+
}
|
|
28655
29074
|
function resolveRepoPath(repoPath) {
|
|
28656
29075
|
return path24.resolve(repoPath);
|
|
28657
29076
|
}
|
|
@@ -28729,18 +29148,11 @@ function buildExecutionPlan(repoPath, stage, options) {
|
|
|
28729
29148
|
};
|
|
28730
29149
|
const cwd = stage.cwd ? path24.resolve(resolvedRepo, stage.cwd) : resolvedRepo;
|
|
28731
29150
|
const extraArgs = options.args ?? [];
|
|
28732
|
-
const launchFlagArgs = [];
|
|
28733
|
-
if (stage.kind === "launch" && options.launchFlags) {
|
|
28734
|
-
if (options.launchFlags.worktree === false) launchFlagArgs.push("--no-worktree");
|
|
28735
|
-
if (options.launchFlags.claude) launchFlagArgs.push("--claude");
|
|
28736
|
-
if (options.launchFlags.confirmReplace) launchFlagArgs.push("--replace");
|
|
28737
|
-
if (options.launchFlags.force) launchFlagArgs.push("--force");
|
|
28738
|
-
if (options.launchFlags.resume) launchFlagArgs.push("--resume");
|
|
28739
|
-
}
|
|
29151
|
+
const launchFlagArgs = stage.kind === "launch" && options.launchFlags ? buildLaunchFlagArgs(options.launchFlags) : [];
|
|
28740
29152
|
if (stage.command) {
|
|
28741
29153
|
let shellCommand = substituteAgentId(stage.command, options.agentId);
|
|
28742
29154
|
for (const extra of [...extraArgs, ...launchFlagArgs]) {
|
|
28743
|
-
shellCommand = `${shellCommand} ${extra}`;
|
|
29155
|
+
shellCommand = `${shellCommand} ${quoteShellArg(extra)}`;
|
|
28744
29156
|
}
|
|
28745
29157
|
return { mode: "shell", shellCommand, args: [], cwd, env: mergedEnv };
|
|
28746
29158
|
}
|
|
@@ -28833,15 +29245,7 @@ var localScriptExecutor = new LocalScriptExecutor();
|
|
|
28833
29245
|
|
|
28834
29246
|
// src/core/control-sync.ts
|
|
28835
29247
|
var path38 = __toESM(require("path"));
|
|
28836
|
-
|
|
28837
|
-
// src/core/control-config.ts
|
|
28838
|
-
var DEFAULT_CONTROL_API_URL = "http://localhost:3847";
|
|
28839
|
-
function getControlApiUrl() {
|
|
28840
|
-
return process.env.HAR_CONTROL_API_URL ?? DEFAULT_CONTROL_API_URL;
|
|
28841
|
-
}
|
|
28842
|
-
function isControlEnabled() {
|
|
28843
|
-
return process.env.HAR_CONTROL_DISABLED !== "true";
|
|
28844
|
-
}
|
|
29248
|
+
init_control_config();
|
|
28845
29249
|
|
|
28846
29250
|
// src/core/control-registry.ts
|
|
28847
29251
|
var fs26 = __toESM(require("fs"));
|
|
@@ -29087,6 +29491,7 @@ var path30 = __toESM(require("path"));
|
|
|
29087
29491
|
var import_child_process4 = require("child_process");
|
|
29088
29492
|
var fs29 = __toESM(require("fs"));
|
|
29089
29493
|
var path28 = __toESM(require("path"));
|
|
29494
|
+
init_control_config();
|
|
29090
29495
|
|
|
29091
29496
|
// src/core/slot-ports.ts
|
|
29092
29497
|
var import_child_process3 = require("child_process");
|
|
@@ -29793,7 +30198,6 @@ function collectSlotStatus(harnessRoot, agentId, runs, pm2Procs) {
|
|
|
29793
30198
|
baseBranch: session?.baseBranch,
|
|
29794
30199
|
baseCommit: session?.baseCommit,
|
|
29795
30200
|
sessionCreatedAt: session?.createdAt,
|
|
29796
|
-
purpose: session?.purpose,
|
|
29797
30201
|
sessionStatus: session?.status,
|
|
29798
30202
|
lastError: session?.lastError,
|
|
29799
30203
|
resumeHint,
|
|
@@ -30032,105 +30436,19 @@ function createRemoteExecutor(apiUrl, apiKey) {
|
|
|
30032
30436
|
return new RemoteExecutor(url, key);
|
|
30033
30437
|
}
|
|
30034
30438
|
|
|
30035
|
-
// src/core/
|
|
30036
|
-
|
|
30037
|
-
var os9 = __toESM(require("os"));
|
|
30038
|
-
var path34 = __toESM(require("path"));
|
|
30039
|
-
var DEFAULT_SIGNALS_ON = {
|
|
30040
|
-
metrics: true,
|
|
30041
|
-
logs: true,
|
|
30042
|
-
prompts: false,
|
|
30043
|
-
traces: false
|
|
30044
|
-
};
|
|
30045
|
-
var DEFAULT_SIGNALS_OFF = {
|
|
30046
|
-
metrics: false,
|
|
30047
|
-
logs: false,
|
|
30048
|
-
prompts: false,
|
|
30049
|
-
traces: false
|
|
30050
|
-
};
|
|
30051
|
-
function getPreferencePath() {
|
|
30052
|
-
if (process.env.HAR_TELEMETRY_CONFIG_PATH) {
|
|
30053
|
-
return path34.resolve(process.env.HAR_TELEMETRY_CONFIG_PATH);
|
|
30054
|
-
}
|
|
30055
|
-
return path34.join(os9.homedir(), ".har", "telemetry.json");
|
|
30056
|
-
}
|
|
30057
|
-
function parseEnvOverride(raw) {
|
|
30058
|
-
if (raw === void 0 || raw === "") return void 0;
|
|
30059
|
-
const normalized = raw.trim().toLowerCase();
|
|
30060
|
-
if (["0", "false", "off", "no", "disabled"].includes(normalized)) return false;
|
|
30061
|
-
if (["1", "true", "on", "yes", "enabled"].includes(normalized)) return true;
|
|
30062
|
-
return void 0;
|
|
30063
|
-
}
|
|
30064
|
-
function normalizeSignals(enabled, raw) {
|
|
30065
|
-
if (!enabled) return { ...DEFAULT_SIGNALS_OFF };
|
|
30066
|
-
return {
|
|
30067
|
-
metrics: raw?.metrics !== false,
|
|
30068
|
-
logs: raw?.logs !== false,
|
|
30069
|
-
prompts: raw?.prompts === true,
|
|
30070
|
-
traces: raw?.traces === true
|
|
30071
|
-
};
|
|
30072
|
-
}
|
|
30073
|
-
function readTelemetryPreference() {
|
|
30074
|
-
const preferencePath = getPreferencePath();
|
|
30075
|
-
try {
|
|
30076
|
-
if (!fs34.existsSync(preferencePath)) {
|
|
30077
|
-
return { enabled: true, signals: { ...DEFAULT_SIGNALS_ON } };
|
|
30078
|
-
}
|
|
30079
|
-
const parsed = JSON.parse(fs34.readFileSync(preferencePath, "utf8"));
|
|
30080
|
-
const enabled = parsed.enabled !== false;
|
|
30081
|
-
return {
|
|
30082
|
-
enabled,
|
|
30083
|
-
signals: normalizeSignals(enabled, parsed.signals),
|
|
30084
|
-
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : void 0
|
|
30085
|
-
};
|
|
30086
|
-
} catch {
|
|
30087
|
-
return { enabled: true, signals: { ...DEFAULT_SIGNALS_ON } };
|
|
30088
|
-
}
|
|
30089
|
-
}
|
|
30090
|
-
function writeTelemetryPreference(enabled, signals) {
|
|
30091
|
-
const current = readTelemetryPreference();
|
|
30092
|
-
const nextSignals = normalizeSignals(enabled, {
|
|
30093
|
-
...current.signals,
|
|
30094
|
-
...signals
|
|
30095
|
-
});
|
|
30096
|
-
const preference = {
|
|
30097
|
-
enabled,
|
|
30098
|
-
signals: enabled ? nextSignals : { ...DEFAULT_SIGNALS_OFF },
|
|
30099
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
30100
|
-
};
|
|
30101
|
-
const preferencePath = getPreferencePath();
|
|
30102
|
-
fs34.mkdirSync(path34.dirname(preferencePath), { recursive: true });
|
|
30103
|
-
fs34.writeFileSync(preferencePath, JSON.stringify(preference, null, 2) + "\n");
|
|
30104
|
-
return preference;
|
|
30105
|
-
}
|
|
30106
|
-
function isTelemetryEnabled() {
|
|
30107
|
-
const envOverride = parseEnvOverride(process.env.HAR_TELEMETRY);
|
|
30108
|
-
if (envOverride !== void 0) return envOverride;
|
|
30109
|
-
return readTelemetryPreference().enabled;
|
|
30110
|
-
}
|
|
30111
|
-
function getTelemetrySignals() {
|
|
30112
|
-
if (!isTelemetryEnabled()) return { ...DEFAULT_SIGNALS_OFF };
|
|
30113
|
-
return readTelemetryPreference().signals;
|
|
30114
|
-
}
|
|
30115
|
-
function getTelemetryPreferencePath() {
|
|
30116
|
-
return getPreferencePath();
|
|
30117
|
-
}
|
|
30118
|
-
var TELEMETRY_SIGNALS = [
|
|
30119
|
-
"Metrics (default): tokens and estimated USD cost via OTEL metrics",
|
|
30120
|
-
"Logs/events (default): session events (tool calls, api_request) without prompt bodies",
|
|
30121
|
-
"Prompts (opt-in): user/assistant text via OTEL_LOG_USER_PROMPTS \u2014 har telemetry on --prompts",
|
|
30122
|
-
"Traces (opt-in): thin span ingest when CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1",
|
|
30123
|
-
"Fallback: har control sync harvests local Claude/Codex session files when OTEL is missing"
|
|
30124
|
-
];
|
|
30439
|
+
// src/core/control-sync.ts
|
|
30440
|
+
init_telemetry_config();
|
|
30125
30441
|
|
|
30126
30442
|
// src/core/usage-harvest/claude.ts
|
|
30127
30443
|
var fs36 = __toESM(require("fs"));
|
|
30128
30444
|
var os10 = __toESM(require("os"));
|
|
30129
30445
|
var path36 = __toESM(require("path"));
|
|
30446
|
+
init_telemetry_config();
|
|
30130
30447
|
|
|
30131
30448
|
// src/core/telemetry-env.ts
|
|
30132
30449
|
var fs35 = __toESM(require("fs"));
|
|
30133
30450
|
var path35 = __toESM(require("path"));
|
|
30451
|
+
init_control_config();
|
|
30134
30452
|
function escapeAttrValue(value) {
|
|
30135
30453
|
return value.replace(/[,=]/g, "_");
|
|
30136
30454
|
}
|
|
@@ -30143,7 +30461,6 @@ function buildOtelResourceAttributes(attrs) {
|
|
|
30143
30461
|
];
|
|
30144
30462
|
if (attrs.branch) parts.push(`har.branch=${escapeAttrValue(attrs.branch)}`);
|
|
30145
30463
|
if (attrs.suffix) parts.push(`har.suffix=${escapeAttrValue(attrs.suffix)}`);
|
|
30146
|
-
if (attrs.purpose) parts.push(`har.purpose=${escapeAttrValue(attrs.purpose)}`);
|
|
30147
30464
|
return parts.join(",");
|
|
30148
30465
|
}
|
|
30149
30466
|
function buildSessionKey(input) {
|
|
@@ -30151,49 +30468,22 @@ function buildSessionKey(input) {
|
|
|
30151
30468
|
const stamp = (input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()).replace(/[:.]/g, "-");
|
|
30152
30469
|
return `agent-${input.agentId}-${input.suffix ?? stamp}`;
|
|
30153
30470
|
}
|
|
30154
|
-
function buildTelemetryEnvBlock(attrs
|
|
30471
|
+
function buildTelemetryEnvBlock(attrs) {
|
|
30155
30472
|
const apiUrl = getControlApiUrl().replace(/\/$/, "");
|
|
30156
30473
|
const lines = [
|
|
30157
30474
|
"",
|
|
30158
30475
|
"# HAR session attribution (generated)",
|
|
30159
30476
|
`HAR_SESSION_KEY=${attrs.sessionKey}`,
|
|
30160
30477
|
`HAR_CONTROL_API_URL=${apiUrl}`,
|
|
30161
|
-
`OTEL_RESOURCE_ATTRIBUTES=${buildOtelResourceAttributes(attrs)}
|
|
30478
|
+
`OTEL_RESOURCE_ATTRIBUTES=${buildOtelResourceAttributes(attrs)}`,
|
|
30479
|
+
"# Agent telemetry: opentelemetry-hooks \u2192 Mission Control (har telemetry on|off)"
|
|
30162
30480
|
];
|
|
30163
|
-
const injectOtel = isTelemetryEnabled() && options?.otelReady !== false;
|
|
30164
|
-
if (injectOtel) {
|
|
30165
|
-
const signals = getTelemetrySignals();
|
|
30166
|
-
lines.push(
|
|
30167
|
-
"# HAR telemetry \u2192 Mission Control OTLP (disable: har telemetry off)",
|
|
30168
|
-
"CLAUDE_CODE_ENABLE_TELEMETRY=1",
|
|
30169
|
-
"OTEL_EXPORTER_OTLP_PROTOCOL=http/json",
|
|
30170
|
-
`OTEL_EXPORTER_OTLP_ENDPOINT=${apiUrl}/api/otel`
|
|
30171
|
-
);
|
|
30172
|
-
if (signals.metrics) {
|
|
30173
|
-
lines.push("OTEL_METRICS_EXPORTER=otlp");
|
|
30174
|
-
}
|
|
30175
|
-
if (signals.logs) {
|
|
30176
|
-
lines.push("OTEL_LOGS_EXPORTER=otlp");
|
|
30177
|
-
}
|
|
30178
|
-
if (signals.prompts) {
|
|
30179
|
-
lines.push(
|
|
30180
|
-
"OTEL_LOG_USER_PROMPTS=1",
|
|
30181
|
-
"OTEL_LOG_ASSISTANT_RESPONSES=1"
|
|
30182
|
-
);
|
|
30183
|
-
}
|
|
30184
|
-
if (signals.traces) {
|
|
30185
|
-
lines.push(
|
|
30186
|
-
"OTEL_TRACES_EXPORTER=otlp",
|
|
30187
|
-
"CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1"
|
|
30188
|
-
);
|
|
30189
|
-
}
|
|
30190
|
-
}
|
|
30191
30481
|
return lines.join("\n") + "\n";
|
|
30192
30482
|
}
|
|
30193
30483
|
var TELEMETRY_MARKER_START = "# HAR session attribution (generated)";
|
|
30194
30484
|
var TELEMETRY_MARKER_END = "# end HAR telemetry";
|
|
30195
|
-
function appendTelemetryEnvToFile(envFilePath, attrs
|
|
30196
|
-
const block = buildTelemetryEnvBlock(attrs
|
|
30485
|
+
function appendTelemetryEnvToFile(envFilePath, attrs) {
|
|
30486
|
+
const block = buildTelemetryEnvBlock(attrs).trimEnd() + `
|
|
30197
30487
|
${TELEMETRY_MARKER_END}
|
|
30198
30488
|
`;
|
|
30199
30489
|
let existing = "";
|
|
@@ -30213,22 +30503,6 @@ ${TELEMETRY_MARKER_END}
|
|
|
30213
30503
|
const combined = (existing.replace(/\n+$/, "\n") + block).replace(/^\n+/, "");
|
|
30214
30504
|
fs35.writeFileSync(envFilePath, combined.endsWith("\n") ? combined : combined + "\n");
|
|
30215
30505
|
}
|
|
30216
|
-
function buildCodexOtelSnippet(attrs) {
|
|
30217
|
-
const apiUrl = getControlApiUrl().replace(/\/$/, "");
|
|
30218
|
-
const resource = buildOtelResourceAttributes(attrs);
|
|
30219
|
-
return `# Merge into ~/.codex/config.toml (HAR does not overwrite your config)
|
|
30220
|
-
# Generated for session ${attrs.sessionKey}
|
|
30221
|
-
|
|
30222
|
-
[otel]
|
|
30223
|
-
exporter = "otlp-http"
|
|
30224
|
-
endpoint = "${apiUrl}/api/otel"
|
|
30225
|
-
metrics_exporter = "otlp-http"
|
|
30226
|
-
|
|
30227
|
-
# Optional: set resource attributes via environment when starting Codex:
|
|
30228
|
-
# export OTEL_RESOURCE_ATTRIBUTES="${resource}"
|
|
30229
|
-
# export HAR_SESSION_KEY="${attrs.sessionKey}"
|
|
30230
|
-
`;
|
|
30231
|
-
}
|
|
30232
30506
|
|
|
30233
30507
|
// src/core/usage-harvest/claude.ts
|
|
30234
30508
|
function pathsMatch(candidate, targets) {
|
|
@@ -30566,7 +30840,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
|
|
|
30566
30840
|
const deadline = Date.now() + timeoutMs;
|
|
30567
30841
|
while (Date.now() < deadline) {
|
|
30568
30842
|
if (await isControlApiReachable(apiUrl)) return true;
|
|
30569
|
-
await new Promise((
|
|
30843
|
+
await new Promise((resolve34) => setTimeout(resolve34, intervalMs));
|
|
30570
30844
|
}
|
|
30571
30845
|
return false;
|
|
30572
30846
|
}
|
|
@@ -30763,6 +31037,9 @@ function checkLaunchGuard2(repoPath, agentId, options = {}) {
|
|
|
30763
31037
|
return { allowed: true, slot: occupied.slot, readiness };
|
|
30764
31038
|
}
|
|
30765
31039
|
|
|
31040
|
+
// src/core/telemetry-ensure.ts
|
|
31041
|
+
init_control_config();
|
|
31042
|
+
|
|
30766
31043
|
// src/core/control-lifecycle.ts
|
|
30767
31044
|
var import_child_process8 = require("child_process");
|
|
30768
31045
|
var path39 = __toESM(require("path"));
|
|
@@ -30783,6 +31060,7 @@ function shouldBuildControlLocally() {
|
|
|
30783
31060
|
}
|
|
30784
31061
|
|
|
30785
31062
|
// src/core/control-lifecycle.ts
|
|
31063
|
+
init_control_config();
|
|
30786
31064
|
var CONTROL_CONTAINER_NAME = "har-control";
|
|
30787
31065
|
var CONTROL_DATA_VOLUME = "har_control_data";
|
|
30788
31066
|
var CONTROL_CONTAINER_PORT = 3847;
|
|
@@ -30891,6 +31169,7 @@ async function startControlAndSync(options) {
|
|
|
30891
31169
|
}
|
|
30892
31170
|
|
|
30893
31171
|
// src/core/telemetry-ensure.ts
|
|
31172
|
+
init_telemetry_config();
|
|
30894
31173
|
async function ensureTelemetryInfrastructure(options) {
|
|
30895
31174
|
const apiUrl = getControlApiUrl();
|
|
30896
31175
|
const telemetryEnabled = isTelemetryEnabled();
|
|
@@ -30989,7 +31268,8 @@ async function ensureTelemetryInfrastructure(options) {
|
|
|
30989
31268
|
}
|
|
30990
31269
|
|
|
30991
31270
|
// src/core/run-service.ts
|
|
30992
|
-
|
|
31271
|
+
init_telemetry_config();
|
|
31272
|
+
var path41 = __toESM(require("path"));
|
|
30993
31273
|
function extractShellOutput(result) {
|
|
30994
31274
|
const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
|
|
30995
31275
|
const stderr = result.logs?.find((log) => log.stream === "stderr")?.content ?? "";
|
|
@@ -31110,17 +31390,26 @@ var RunService = class {
|
|
|
31110
31390
|
};
|
|
31111
31391
|
}
|
|
31112
31392
|
let telemetryBanner = "";
|
|
31113
|
-
let otelReady = false;
|
|
31114
31393
|
if (isTelemetryEnabled() && process.env.NODE_ENV !== "test") {
|
|
31115
31394
|
const ensured = await ensureTelemetryInfrastructure({ startIfNeeded: true });
|
|
31116
|
-
otelReady = ensured.otelReady;
|
|
31117
31395
|
if (ensured.message) {
|
|
31118
31396
|
telemetryBanner += `${ensured.message}
|
|
31119
|
-
Usage from Claude
|
|
31397
|
+
Usage from Cursor / Claude / Codex (opentelemetry-hooks) will appear under Worktrees. Disable: har telemetry off
|
|
31120
31398
|
`;
|
|
31121
31399
|
}
|
|
31122
31400
|
if (ensured.warning) {
|
|
31123
31401
|
telemetryBanner += `${ensured.warning}
|
|
31402
|
+
`;
|
|
31403
|
+
}
|
|
31404
|
+
try {
|
|
31405
|
+
const { ensureOtelHooks: ensureOtelHooks2 } = await Promise.resolve().then(() => (init_otel_hooks(), otel_hooks_exports));
|
|
31406
|
+
const hooks = ensureOtelHooks2({ setupAgents: true });
|
|
31407
|
+
if (hooks.message) telemetryBanner += `${hooks.message}
|
|
31408
|
+
`;
|
|
31409
|
+
if (hooks.warning) telemetryBanner += `${hooks.warning}
|
|
31410
|
+
`;
|
|
31411
|
+
} catch (err) {
|
|
31412
|
+
telemetryBanner += `opentelemetry-hooks setup skipped: ${err instanceof Error ? err.message : String(err)}
|
|
31124
31413
|
`;
|
|
31125
31414
|
}
|
|
31126
31415
|
}
|
|
@@ -31153,21 +31442,16 @@ Usage from Claude Code / Codex will appear under Worktrees. Disable: har telemet
|
|
|
31153
31442
|
suffix: session.suffix,
|
|
31154
31443
|
createdAt: session.createdAt
|
|
31155
31444
|
});
|
|
31156
|
-
const envFile =
|
|
31445
|
+
const envFile = path41.join(session.workDir, `.env.agent.${options.agentId}`);
|
|
31157
31446
|
try {
|
|
31158
|
-
appendTelemetryEnvToFile(
|
|
31159
|
-
|
|
31160
|
-
|
|
31161
|
-
|
|
31162
|
-
|
|
31163
|
-
|
|
31164
|
-
|
|
31165
|
-
|
|
31166
|
-
suffix: session.suffix,
|
|
31167
|
-
purpose: session.purpose
|
|
31168
|
-
},
|
|
31169
|
-
{ otelReady: otelReady && isTelemetryEnabled() }
|
|
31170
|
-
);
|
|
31447
|
+
appendTelemetryEnvToFile(envFile, {
|
|
31448
|
+
sessionKey,
|
|
31449
|
+
agentId: options.agentId,
|
|
31450
|
+
repoPath: path41.resolve(options.repoPath),
|
|
31451
|
+
workDir: session.workDir,
|
|
31452
|
+
branch: session.branch,
|
|
31453
|
+
suffix: session.suffix
|
|
31454
|
+
});
|
|
31171
31455
|
} catch {
|
|
31172
31456
|
}
|
|
31173
31457
|
}
|
|
@@ -31526,7 +31810,7 @@ var envCommand = {
|
|
|
31526
31810
|
}
|
|
31527
31811
|
};
|
|
31528
31812
|
async function handleInit(argv) {
|
|
31529
|
-
const repoPath =
|
|
31813
|
+
const repoPath = path42.resolve(argv.repo);
|
|
31530
31814
|
header("har env init");
|
|
31531
31815
|
info(`Repository: ${repoPath}`);
|
|
31532
31816
|
try {
|
|
@@ -31584,7 +31868,7 @@ async function handleInit(argv) {
|
|
|
31584
31868
|
}
|
|
31585
31869
|
}
|
|
31586
31870
|
async function handleMaintain(argv) {
|
|
31587
|
-
const repoPath =
|
|
31871
|
+
const repoPath = path42.resolve(argv.repo);
|
|
31588
31872
|
header("har env maintain");
|
|
31589
31873
|
info(`Repository: ${repoPath}`);
|
|
31590
31874
|
try {
|
|
@@ -31682,7 +31966,7 @@ async function handleAgentMdProposal(repoPath, autoYes) {
|
|
|
31682
31966
|
if (autoYes) {
|
|
31683
31967
|
const proposal = readAgentMdProposal(repoPath);
|
|
31684
31968
|
if (proposal) {
|
|
31685
|
-
writeFileSafe(
|
|
31969
|
+
writeFileSafe(path42.join(repoPath, "AGENT.md"), proposal.content);
|
|
31686
31970
|
clearAgentMdProposal(repoPath);
|
|
31687
31971
|
info("Applied AGENT.md proposal (--yes)");
|
|
31688
31972
|
}
|
|
@@ -31691,7 +31975,7 @@ async function handleAgentMdProposal(repoPath, autoYes) {
|
|
|
31691
31975
|
await promptApplyAgentMdProposal(repoPath);
|
|
31692
31976
|
}
|
|
31693
31977
|
async function handleAddStage(argv) {
|
|
31694
|
-
const repoPath =
|
|
31978
|
+
const repoPath = path42.resolve(argv.repo);
|
|
31695
31979
|
const available = listStageTemplateIds();
|
|
31696
31980
|
if (argv.list) {
|
|
31697
31981
|
for (const id of available) {
|
|
@@ -31768,7 +32052,7 @@ async function handleAddStage(argv) {
|
|
|
31768
32052
|
}
|
|
31769
32053
|
}
|
|
31770
32054
|
async function handlePreflight(argv) {
|
|
31771
|
-
const repo =
|
|
32055
|
+
const repo = path42.resolve(argv.repo);
|
|
31772
32056
|
const agentId = validateAgentId(argv.id, repo);
|
|
31773
32057
|
const result = await preflightEnvironment({
|
|
31774
32058
|
repoPath: repo,
|
|
@@ -31786,7 +32070,7 @@ async function handlePreflight(argv) {
|
|
|
31786
32070
|
process.exit(result.code);
|
|
31787
32071
|
}
|
|
31788
32072
|
async function handleLaunch(argv) {
|
|
31789
|
-
const repo =
|
|
32073
|
+
const repo = path42.resolve(argv.repo);
|
|
31790
32074
|
const agentId = validateAgentId(argv.id, repo);
|
|
31791
32075
|
let confirmReplace = argv.replace;
|
|
31792
32076
|
let force = argv.force;
|
|
@@ -31798,8 +32082,8 @@ async function handleLaunch(argv) {
|
|
|
31798
32082
|
console.error(guard.reason ?? "");
|
|
31799
32083
|
const readline5 = await import("readline");
|
|
31800
32084
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
31801
|
-
const answer = await new Promise((
|
|
31802
|
-
rl.question("Replace this slot? [y/N] ",
|
|
32085
|
+
const answer = await new Promise((resolve34) => {
|
|
32086
|
+
rl.question("Replace this slot? [y/N] ", resolve34);
|
|
31803
32087
|
});
|
|
31804
32088
|
rl.close();
|
|
31805
32089
|
if (!/^[Yy]$/.test(answer.trim())) {
|
|
@@ -31815,8 +32099,8 @@ async function handleLaunch(argv) {
|
|
|
31815
32099
|
warn("Worktree has uncommitted changes.");
|
|
31816
32100
|
const readline5 = await import("readline");
|
|
31817
32101
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
31818
|
-
const answer = await new Promise((
|
|
31819
|
-
rl.question("Discard uncommitted changes? [y/N] ",
|
|
32102
|
+
const answer = await new Promise((resolve34) => {
|
|
32103
|
+
rl.question("Discard uncommitted changes? [y/N] ", resolve34);
|
|
31820
32104
|
});
|
|
31821
32105
|
rl.close();
|
|
31822
32106
|
if (!/^[Yy]$/.test(answer.trim())) {
|
|
@@ -31870,7 +32154,7 @@ async function handleRecover(argv) {
|
|
|
31870
32154
|
});
|
|
31871
32155
|
}
|
|
31872
32156
|
async function handleVerify(argv) {
|
|
31873
|
-
const repo =
|
|
32157
|
+
const repo = path42.resolve(argv.repo);
|
|
31874
32158
|
const agentId = validateAgentId(argv.id, repo);
|
|
31875
32159
|
const result = await runVerification({
|
|
31876
32160
|
repoPath: repo,
|
|
@@ -31882,7 +32166,7 @@ async function handleVerify(argv) {
|
|
|
31882
32166
|
process.exit(result.code);
|
|
31883
32167
|
}
|
|
31884
32168
|
async function handleTeardown(argv) {
|
|
31885
|
-
const repo =
|
|
32169
|
+
const repo = path42.resolve(argv.repo);
|
|
31886
32170
|
const agentId = validateAgentId(argv.id, repo);
|
|
31887
32171
|
const result = await teardownEnvironment({
|
|
31888
32172
|
repoPath: repo,
|
|
@@ -31893,7 +32177,7 @@ async function handleTeardown(argv) {
|
|
|
31893
32177
|
process.exit(result.code);
|
|
31894
32178
|
}
|
|
31895
32179
|
async function handleComplete(argv) {
|
|
31896
|
-
const repo =
|
|
32180
|
+
const repo = path42.resolve(argv.repo);
|
|
31897
32181
|
const agentId = validateAgentId(argv.id, repo);
|
|
31898
32182
|
const result = await completeEnvironment({
|
|
31899
32183
|
repoPath: repo,
|
|
@@ -31914,7 +32198,7 @@ async function handleComplete(argv) {
|
|
|
31914
32198
|
process.exit(result.code);
|
|
31915
32199
|
}
|
|
31916
32200
|
async function handleStatus(argv) {
|
|
31917
|
-
const repoPath =
|
|
32201
|
+
const repoPath = path42.resolve(argv.repo);
|
|
31918
32202
|
if (argv.json) {
|
|
31919
32203
|
const status = collectEnvironmentStatus(repoPath);
|
|
31920
32204
|
const output = EnvironmentStatusSchema.parse(status);
|
|
@@ -31927,7 +32211,7 @@ async function handleStatus(argv) {
|
|
|
31927
32211
|
});
|
|
31928
32212
|
}
|
|
31929
32213
|
async function handleRunsList(argv) {
|
|
31930
|
-
const repoPath =
|
|
32214
|
+
const repoPath = path42.resolve(argv.repo);
|
|
31931
32215
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
31932
32216
|
if (argv.json) {
|
|
31933
32217
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -31944,7 +32228,7 @@ async function handleRunsList(argv) {
|
|
|
31944
32228
|
}
|
|
31945
32229
|
}
|
|
31946
32230
|
async function handleRunsGet(argv) {
|
|
31947
|
-
const run2 = getRun(
|
|
32231
|
+
const run2 = getRun(path42.resolve(argv.repo), argv.runId);
|
|
31948
32232
|
if (!run2) {
|
|
31949
32233
|
error(`Run not found: ${argv.runId}`);
|
|
31950
32234
|
process.exit(1);
|
|
@@ -32023,7 +32307,8 @@ function printNextSteps(auto2) {
|
|
|
32023
32307
|
}
|
|
32024
32308
|
|
|
32025
32309
|
// src/cli/commands/control.ts
|
|
32026
|
-
var
|
|
32310
|
+
var path43 = __toESM(require("path"));
|
|
32311
|
+
init_control_config();
|
|
32027
32312
|
var controlCommand = {
|
|
32028
32313
|
command: "control <subcommand>",
|
|
32029
32314
|
describe: "Mission Control dashboard (local)",
|
|
@@ -32126,7 +32411,7 @@ async function handleDown() {
|
|
|
32126
32411
|
process.exit(code);
|
|
32127
32412
|
}
|
|
32128
32413
|
async function handleRegister(argv) {
|
|
32129
|
-
const repoPath =
|
|
32414
|
+
const repoPath = path43.resolve(argv.repo);
|
|
32130
32415
|
header("har control register");
|
|
32131
32416
|
info(`Repository: ${repoPath}`);
|
|
32132
32417
|
try {
|
|
@@ -32146,7 +32431,7 @@ async function handleRegister(argv) {
|
|
|
32146
32431
|
}
|
|
32147
32432
|
}
|
|
32148
32433
|
async function handleSync(argv) {
|
|
32149
|
-
const repoPath =
|
|
32434
|
+
const repoPath = path43.resolve(argv.repo);
|
|
32150
32435
|
try {
|
|
32151
32436
|
await syncRepoWithControl({
|
|
32152
32437
|
repoPath,
|
|
@@ -32185,7 +32470,7 @@ async function handleWatch(argv) {
|
|
|
32185
32470
|
};
|
|
32186
32471
|
const tick = async () => {
|
|
32187
32472
|
if (argv.repo) {
|
|
32188
|
-
await syncOne(
|
|
32473
|
+
await syncOne(path43.resolve(argv.repo));
|
|
32189
32474
|
return;
|
|
32190
32475
|
}
|
|
32191
32476
|
try {
|
|
@@ -32216,12 +32501,12 @@ async function handleLogin(argv) {
|
|
|
32216
32501
|
}
|
|
32217
32502
|
|
|
32218
32503
|
// src/cli/commands/hooks.ts
|
|
32219
|
-
var
|
|
32504
|
+
var path46 = __toESM(require("path"));
|
|
32220
32505
|
|
|
32221
32506
|
// src/core/hooks.ts
|
|
32222
|
-
var
|
|
32223
|
-
var
|
|
32224
|
-
var
|
|
32507
|
+
var fs39 = __toESM(require("fs"));
|
|
32508
|
+
var os13 = __toESM(require("os"));
|
|
32509
|
+
var path44 = __toESM(require("path"));
|
|
32225
32510
|
var MARKER_START = "# >>> har commit gate (managed by `har hooks`) >>>";
|
|
32226
32511
|
var MARKER_END = "# <<< har commit gate <<<";
|
|
32227
32512
|
var PRE_COMMIT_BLOCK = [
|
|
@@ -32246,7 +32531,7 @@ function resolveCheckoutRoot(cwd) {
|
|
|
32246
32531
|
function resolveHooksDir(checkoutDir) {
|
|
32247
32532
|
const hooksPath = tryGit2(checkoutDir, "rev-parse --git-path hooks");
|
|
32248
32533
|
if (!hooksPath) throw new Error(`Not a git checkout: ${checkoutDir}`);
|
|
32249
|
-
return
|
|
32534
|
+
return path44.resolve(checkoutDir, hooksPath);
|
|
32250
32535
|
}
|
|
32251
32536
|
function getConfiguredHooksPath(checkoutDir) {
|
|
32252
32537
|
return tryGit2(checkoutDir, "config core.hooksPath") || void 0;
|
|
@@ -32254,9 +32539,9 @@ function getConfiguredHooksPath(checkoutDir) {
|
|
|
32254
32539
|
function defaultHarInvocation() {
|
|
32255
32540
|
const entry = process.argv[1];
|
|
32256
32541
|
if (entry && entry.endsWith(".js")) {
|
|
32257
|
-
return `"${process.execPath}" "${
|
|
32542
|
+
return `"${process.execPath}" "${path44.resolve(entry)}"`;
|
|
32258
32543
|
}
|
|
32259
|
-
if (entry) return `"${
|
|
32544
|
+
if (entry) return `"${path44.resolve(entry)}"`;
|
|
32260
32545
|
return "har";
|
|
32261
32546
|
}
|
|
32262
32547
|
function buildHookScript(harInvocation, subcommand, failOpenNotice) {
|
|
@@ -32277,40 +32562,40 @@ exit 0
|
|
|
32277
32562
|
`;
|
|
32278
32563
|
}
|
|
32279
32564
|
function upsertMarkedBlock(filePath, block) {
|
|
32280
|
-
if (!
|
|
32281
|
-
|
|
32565
|
+
if (!fs39.existsSync(filePath)) {
|
|
32566
|
+
fs39.writeFileSync(filePath, `#!/bin/sh
|
|
32282
32567
|
${block}
|
|
32283
32568
|
`, { mode: 493 });
|
|
32284
32569
|
return "created";
|
|
32285
32570
|
}
|
|
32286
|
-
const content =
|
|
32571
|
+
const content = fs39.readFileSync(filePath, "utf8");
|
|
32287
32572
|
if (content.includes(MARKER_START)) {
|
|
32288
32573
|
const pattern = new RegExp(
|
|
32289
32574
|
`${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}`
|
|
32290
32575
|
);
|
|
32291
|
-
|
|
32292
|
-
|
|
32576
|
+
fs39.writeFileSync(filePath, content.replace(pattern, block));
|
|
32577
|
+
fs39.chmodSync(filePath, 493);
|
|
32293
32578
|
return "updated";
|
|
32294
32579
|
}
|
|
32295
32580
|
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
32296
|
-
|
|
32581
|
+
fs39.writeFileSync(filePath, `${content}${suffix}
|
|
32297
32582
|
${block}
|
|
32298
32583
|
`);
|
|
32299
|
-
|
|
32584
|
+
fs39.chmodSync(filePath, 493);
|
|
32300
32585
|
return "appended";
|
|
32301
32586
|
}
|
|
32302
32587
|
function removeMarkedBlock(filePath) {
|
|
32303
|
-
if (!
|
|
32304
|
-
const content =
|
|
32588
|
+
if (!fs39.existsSync(filePath)) return false;
|
|
32589
|
+
const content = fs39.readFileSync(filePath, "utf8");
|
|
32305
32590
|
if (!content.includes(MARKER_START)) return false;
|
|
32306
32591
|
const pattern = new RegExp(
|
|
32307
32592
|
`\\n?${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}\\n?`
|
|
32308
32593
|
);
|
|
32309
32594
|
const stripped = content.replace(pattern, "\n");
|
|
32310
32595
|
if (stripped.replace(/^#!\/bin\/sh\n?/, "").trim() === "") {
|
|
32311
|
-
|
|
32596
|
+
fs39.rmSync(filePath);
|
|
32312
32597
|
} else {
|
|
32313
|
-
|
|
32598
|
+
fs39.writeFileSync(filePath, stripped);
|
|
32314
32599
|
}
|
|
32315
32600
|
return true;
|
|
32316
32601
|
}
|
|
@@ -32332,20 +32617,20 @@ Or re-run with --force to write into that directory anyway.`
|
|
|
32332
32617
|
);
|
|
32333
32618
|
}
|
|
32334
32619
|
const hooksDir = resolveHooksDir(checkout);
|
|
32335
|
-
|
|
32620
|
+
fs39.mkdirSync(hooksDir, { recursive: true });
|
|
32336
32621
|
const invocation = options.harInvocation ?? defaultHarInvocation();
|
|
32337
|
-
|
|
32338
|
-
|
|
32622
|
+
fs39.writeFileSync(
|
|
32623
|
+
path44.join(hooksDir, "har-pre-commit"),
|
|
32339
32624
|
buildHookScript(invocation, "check", "har: binary not found; skipping commit gate (reinstall with har hooks install)"),
|
|
32340
32625
|
{ mode: 493 }
|
|
32341
32626
|
);
|
|
32342
|
-
|
|
32343
|
-
|
|
32627
|
+
fs39.writeFileSync(
|
|
32628
|
+
path44.join(hooksDir, "har-post-commit"),
|
|
32344
32629
|
buildHookScript(invocation, "record-commit", "har: binary not found; skipping commit association"),
|
|
32345
32630
|
{ mode: 493 }
|
|
32346
32631
|
);
|
|
32347
|
-
const preCommit = upsertMarkedBlock(
|
|
32348
|
-
const postCommit = upsertMarkedBlock(
|
|
32632
|
+
const preCommit = upsertMarkedBlock(path44.join(hooksDir, "pre-commit"), PRE_COMMIT_BLOCK);
|
|
32633
|
+
const postCommit = upsertMarkedBlock(path44.join(hooksDir, "post-commit"), POST_COMMIT_BLOCK);
|
|
32349
32634
|
ensureValidationsIgnored(checkout);
|
|
32350
32635
|
return { hooksDir, preCommit, postCommit };
|
|
32351
32636
|
}
|
|
@@ -32354,12 +32639,12 @@ function uninstallHooks(repoPath) {
|
|
|
32354
32639
|
if (!checkout) throw new Error(`Not a git repository: ${repoPath}`);
|
|
32355
32640
|
const hooksDir = resolveHooksDir(checkout);
|
|
32356
32641
|
let removed = false;
|
|
32357
|
-
removed = removeMarkedBlock(
|
|
32358
|
-
removed = removeMarkedBlock(
|
|
32642
|
+
removed = removeMarkedBlock(path44.join(hooksDir, "pre-commit")) || removed;
|
|
32643
|
+
removed = removeMarkedBlock(path44.join(hooksDir, "post-commit")) || removed;
|
|
32359
32644
|
for (const file of ["har-pre-commit", "har-post-commit"]) {
|
|
32360
|
-
const full =
|
|
32361
|
-
if (
|
|
32362
|
-
|
|
32645
|
+
const full = path44.join(hooksDir, file);
|
|
32646
|
+
if (fs39.existsSync(full)) {
|
|
32647
|
+
fs39.rmSync(full);
|
|
32363
32648
|
removed = true;
|
|
32364
32649
|
}
|
|
32365
32650
|
}
|
|
@@ -32376,9 +32661,9 @@ function getCommitGateConfig(checkoutDir) {
|
|
|
32376
32661
|
function isAgentWorktree(checkoutDir) {
|
|
32377
32662
|
const branch = getCurrentBranch(checkoutDir);
|
|
32378
32663
|
if (branch && /^har-agent-\d+$/.test(branch)) return true;
|
|
32379
|
-
const worktreesRoot =
|
|
32380
|
-
const resolved =
|
|
32381
|
-
return resolved.startsWith(`${worktreesRoot}${
|
|
32664
|
+
const worktreesRoot = path44.join(os13.homedir(), "worktrees");
|
|
32665
|
+
const resolved = path44.resolve(checkoutDir);
|
|
32666
|
+
return resolved.startsWith(`${worktreesRoot}${path44.sep}`) && /-agent-\d+$/.test(path44.basename(resolved));
|
|
32382
32667
|
}
|
|
32383
32668
|
function resolveEffectiveMode(checkoutDir, gate) {
|
|
32384
32669
|
if (!gate.enabled) return "off";
|
|
@@ -32391,15 +32676,15 @@ function getHooksStatus(repoPath) {
|
|
|
32391
32676
|
const hooksDir = resolveHooksDir(checkout);
|
|
32392
32677
|
const gate = getCommitGateConfig(checkout);
|
|
32393
32678
|
const hasBlock = (name) => {
|
|
32394
|
-
const file =
|
|
32395
|
-
return
|
|
32679
|
+
const file = path44.join(hooksDir, name);
|
|
32680
|
+
return fs39.existsSync(file) && fs39.readFileSync(file, "utf8").includes(MARKER_START);
|
|
32396
32681
|
};
|
|
32397
32682
|
return {
|
|
32398
32683
|
checkout,
|
|
32399
32684
|
hooksDir,
|
|
32400
32685
|
configuredHooksPath: getConfiguredHooksPath(checkout),
|
|
32401
|
-
preCommitInstalled: hasBlock("pre-commit") &&
|
|
32402
|
-
postCommitInstalled: hasBlock("post-commit") &&
|
|
32686
|
+
preCommitInstalled: hasBlock("pre-commit") && fs39.existsSync(path44.join(hooksDir, "har-pre-commit")),
|
|
32687
|
+
postCommitInstalled: hasBlock("post-commit") && fs39.existsSync(path44.join(hooksDir, "har-post-commit")),
|
|
32403
32688
|
gate,
|
|
32404
32689
|
effectiveMode: resolveEffectiveMode(checkout, gate)
|
|
32405
32690
|
};
|
|
@@ -32410,7 +32695,7 @@ function checkCommitGate(cwd) {
|
|
|
32410
32695
|
}
|
|
32411
32696
|
const checkout = resolveCheckoutRoot(cwd);
|
|
32412
32697
|
if (!checkout) return { exitCode: 0, messages: [] };
|
|
32413
|
-
if (!
|
|
32698
|
+
if (!fs39.existsSync(path44.join(checkout, ".har", "stages.json"))) {
|
|
32414
32699
|
return { exitCode: 0, messages: [] };
|
|
32415
32700
|
}
|
|
32416
32701
|
const gate = getCommitGateConfig(checkout);
|
|
@@ -32481,8 +32766,8 @@ async function recordCommitAssociation(cwd) {
|
|
|
32481
32766
|
}
|
|
32482
32767
|
|
|
32483
32768
|
// src/core/claude-hooks.ts
|
|
32484
|
-
var
|
|
32485
|
-
var
|
|
32769
|
+
var fs40 = __toESM(require("fs"));
|
|
32770
|
+
var path45 = __toESM(require("path"));
|
|
32486
32771
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
32487
32772
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
32488
32773
|
var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
|
|
@@ -32493,8 +32778,8 @@ function isHarGuardEntry(entry) {
|
|
|
32493
32778
|
);
|
|
32494
32779
|
}
|
|
32495
32780
|
function readSettings(settingsPath) {
|
|
32496
|
-
if (!
|
|
32497
|
-
const raw =
|
|
32781
|
+
if (!fs40.existsSync(settingsPath)) return {};
|
|
32782
|
+
const raw = fs40.readFileSync(settingsPath, "utf8").trim();
|
|
32498
32783
|
if (raw === "") return {};
|
|
32499
32784
|
const parsed = JSON.parse(raw);
|
|
32500
32785
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -32503,19 +32788,19 @@ function readSettings(settingsPath) {
|
|
|
32503
32788
|
return parsed;
|
|
32504
32789
|
}
|
|
32505
32790
|
function writeSettings(settingsPath, settings) {
|
|
32506
|
-
|
|
32507
|
-
|
|
32791
|
+
fs40.mkdirSync(path45.dirname(settingsPath), { recursive: true });
|
|
32792
|
+
fs40.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
32508
32793
|
}
|
|
32509
32794
|
function installClaudeGuard(repoPath) {
|
|
32510
32795
|
const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
|
|
32511
32796
|
if (!templatePath) {
|
|
32512
32797
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
32513
32798
|
}
|
|
32514
|
-
const guardScript =
|
|
32515
|
-
|
|
32516
|
-
|
|
32517
|
-
|
|
32518
|
-
const settingsPath =
|
|
32799
|
+
const guardScript = path45.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
32800
|
+
fs40.mkdirSync(path45.dirname(guardScript), { recursive: true });
|
|
32801
|
+
fs40.copyFileSync(templatePath, guardScript);
|
|
32802
|
+
fs40.chmodSync(guardScript, 493);
|
|
32803
|
+
const settingsPath = path45.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
32519
32804
|
const settings = readSettings(settingsPath);
|
|
32520
32805
|
const hooks = settings.hooks ?? {};
|
|
32521
32806
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -32529,15 +32814,15 @@ function installClaudeGuard(repoPath) {
|
|
|
32529
32814
|
}
|
|
32530
32815
|
function uninstallClaudeGuard(repoPath) {
|
|
32531
32816
|
let removed = false;
|
|
32532
|
-
const guardScript =
|
|
32533
|
-
if (
|
|
32534
|
-
|
|
32817
|
+
const guardScript = path45.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
32818
|
+
if (fs40.existsSync(guardScript)) {
|
|
32819
|
+
fs40.rmSync(guardScript);
|
|
32535
32820
|
removed = true;
|
|
32536
|
-
const parent =
|
|
32537
|
-
if (
|
|
32821
|
+
const parent = path45.dirname(guardScript);
|
|
32822
|
+
if (fs40.existsSync(parent) && fs40.readdirSync(parent).length === 0) fs40.rmdirSync(parent);
|
|
32538
32823
|
}
|
|
32539
|
-
const settingsPath =
|
|
32540
|
-
if (
|
|
32824
|
+
const settingsPath = path45.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
32825
|
+
if (fs40.existsSync(settingsPath)) {
|
|
32541
32826
|
const settings = readSettings(settingsPath);
|
|
32542
32827
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
32543
32828
|
if (preToolUse) {
|
|
@@ -32562,8 +32847,8 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
32562
32847
|
return { removed };
|
|
32563
32848
|
}
|
|
32564
32849
|
function claudeGuardInstalled(repoPath) {
|
|
32565
|
-
const settingsPath =
|
|
32566
|
-
if (!
|
|
32850
|
+
const settingsPath = path45.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
32851
|
+
if (!fs40.existsSync(settingsPath)) return false;
|
|
32567
32852
|
try {
|
|
32568
32853
|
const settings = readSettings(settingsPath);
|
|
32569
32854
|
return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
|
|
@@ -32579,7 +32864,7 @@ function repoOption(y2) {
|
|
|
32579
32864
|
function handleInstall2(argv) {
|
|
32580
32865
|
try {
|
|
32581
32866
|
if (argv.claude) {
|
|
32582
|
-
const result2 = installClaudeGuard(
|
|
32867
|
+
const result2 = installClaudeGuard(path46.resolve(argv.repo));
|
|
32583
32868
|
success("Claude Code worktree guard installed.");
|
|
32584
32869
|
info(`Guard script: ${result2.guardScript}`);
|
|
32585
32870
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -32587,7 +32872,7 @@ function handleInstall2(argv) {
|
|
|
32587
32872
|
info("Commit both files so the guard travels with the repo.");
|
|
32588
32873
|
return;
|
|
32589
32874
|
}
|
|
32590
|
-
const result = installHooks({ repoPath:
|
|
32875
|
+
const result = installHooks({ repoPath: path46.resolve(argv.repo), force: argv.force });
|
|
32591
32876
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
32592
32877
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
32593
32878
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -32600,7 +32885,7 @@ function handleInstall2(argv) {
|
|
|
32600
32885
|
function handleUninstall(argv) {
|
|
32601
32886
|
try {
|
|
32602
32887
|
if (argv.claude) {
|
|
32603
|
-
const result2 = uninstallClaudeGuard(
|
|
32888
|
+
const result2 = uninstallClaudeGuard(path46.resolve(argv.repo));
|
|
32604
32889
|
if (result2.removed) {
|
|
32605
32890
|
success("Claude Code worktree guard removed.");
|
|
32606
32891
|
} else {
|
|
@@ -32608,7 +32893,7 @@ function handleUninstall(argv) {
|
|
|
32608
32893
|
}
|
|
32609
32894
|
return;
|
|
32610
32895
|
}
|
|
32611
|
-
const result = uninstallHooks(
|
|
32896
|
+
const result = uninstallHooks(path46.resolve(argv.repo));
|
|
32612
32897
|
if (result.removed) {
|
|
32613
32898
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
32614
32899
|
} else {
|
|
@@ -32621,7 +32906,7 @@ function handleUninstall(argv) {
|
|
|
32621
32906
|
}
|
|
32622
32907
|
function handleStatus2(argv) {
|
|
32623
32908
|
try {
|
|
32624
|
-
const status = getHooksStatus(
|
|
32909
|
+
const status = getHooksStatus(path46.resolve(argv.repo));
|
|
32625
32910
|
if (argv.json) {
|
|
32626
32911
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
32627
32912
|
`);
|
|
@@ -32639,7 +32924,7 @@ function handleStatus2(argv) {
|
|
|
32639
32924
|
);
|
|
32640
32925
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
32641
32926
|
info(
|
|
32642
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
32927
|
+
`Claude guard: ${claudeGuardInstalled(path46.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
32643
32928
|
);
|
|
32644
32929
|
} catch (err) {
|
|
32645
32930
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -32900,10 +33185,10 @@ function assignProp(target, prop, value) {
|
|
|
32900
33185
|
configurable: true
|
|
32901
33186
|
});
|
|
32902
33187
|
}
|
|
32903
|
-
function getElementAtPath(obj,
|
|
32904
|
-
if (!
|
|
33188
|
+
function getElementAtPath(obj, path49) {
|
|
33189
|
+
if (!path49)
|
|
32905
33190
|
return obj;
|
|
32906
|
-
return
|
|
33191
|
+
return path49.reduce((acc, key) => acc?.[key], obj);
|
|
32907
33192
|
}
|
|
32908
33193
|
function promiseAllObject(promisesObj) {
|
|
32909
33194
|
const keys = Object.keys(promisesObj);
|
|
@@ -33223,11 +33508,11 @@ function aborted(x2, startIndex = 0) {
|
|
|
33223
33508
|
}
|
|
33224
33509
|
return false;
|
|
33225
33510
|
}
|
|
33226
|
-
function prefixIssues(
|
|
33511
|
+
function prefixIssues(path49, issues) {
|
|
33227
33512
|
return issues.map((iss) => {
|
|
33228
33513
|
var _a3;
|
|
33229
33514
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
33230
|
-
iss.path.unshift(
|
|
33515
|
+
iss.path.unshift(path49);
|
|
33231
33516
|
return iss;
|
|
33232
33517
|
});
|
|
33233
33518
|
}
|
|
@@ -38550,7 +38835,7 @@ var Protocol = class {
|
|
|
38550
38835
|
return;
|
|
38551
38836
|
}
|
|
38552
38837
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
38553
|
-
await new Promise((
|
|
38838
|
+
await new Promise((resolve34) => setTimeout(resolve34, pollInterval));
|
|
38554
38839
|
options?.signal?.throwIfAborted();
|
|
38555
38840
|
}
|
|
38556
38841
|
} catch (error3) {
|
|
@@ -38567,7 +38852,7 @@ var Protocol = class {
|
|
|
38567
38852
|
*/
|
|
38568
38853
|
request(request, resultSchema, options) {
|
|
38569
38854
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
38570
|
-
return new Promise((
|
|
38855
|
+
return new Promise((resolve34, reject) => {
|
|
38571
38856
|
const earlyReject = (error3) => {
|
|
38572
38857
|
reject(error3);
|
|
38573
38858
|
};
|
|
@@ -38645,7 +38930,7 @@ var Protocol = class {
|
|
|
38645
38930
|
if (!parseResult.success) {
|
|
38646
38931
|
reject(parseResult.error);
|
|
38647
38932
|
} else {
|
|
38648
|
-
|
|
38933
|
+
resolve34(parseResult.data);
|
|
38649
38934
|
}
|
|
38650
38935
|
} catch (error3) {
|
|
38651
38936
|
reject(error3);
|
|
@@ -38906,12 +39191,12 @@ var Protocol = class {
|
|
|
38906
39191
|
}
|
|
38907
39192
|
} catch {
|
|
38908
39193
|
}
|
|
38909
|
-
return new Promise((
|
|
39194
|
+
return new Promise((resolve34, reject) => {
|
|
38910
39195
|
if (signal.aborted) {
|
|
38911
39196
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
38912
39197
|
return;
|
|
38913
39198
|
}
|
|
38914
|
-
const timeoutId = setTimeout(
|
|
39199
|
+
const timeoutId = setTimeout(resolve34, interval);
|
|
38915
39200
|
signal.addEventListener("abort", () => {
|
|
38916
39201
|
clearTimeout(timeoutId);
|
|
38917
39202
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -39701,7 +39986,7 @@ var Server = class extends Protocol {
|
|
|
39701
39986
|
};
|
|
39702
39987
|
|
|
39703
39988
|
// src/mcp/server.ts
|
|
39704
|
-
var
|
|
39989
|
+
var path47 = __toESM(require("path"));
|
|
39705
39990
|
|
|
39706
39991
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
39707
39992
|
var import_node_process2 = __toESM(require("node:process"), 1);
|
|
@@ -39784,12 +40069,12 @@ var StdioServerTransport = class {
|
|
|
39784
40069
|
this.onclose?.();
|
|
39785
40070
|
}
|
|
39786
40071
|
send(message) {
|
|
39787
|
-
return new Promise((
|
|
40072
|
+
return new Promise((resolve34) => {
|
|
39788
40073
|
const json = serializeMessage(message);
|
|
39789
40074
|
if (this._stdout.write(json)) {
|
|
39790
|
-
|
|
40075
|
+
resolve34();
|
|
39791
40076
|
} else {
|
|
39792
|
-
this._stdout.once("drain",
|
|
40077
|
+
this._stdout.once("drain", resolve34);
|
|
39793
40078
|
}
|
|
39794
40079
|
});
|
|
39795
40080
|
}
|
|
@@ -40333,7 +40618,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
40333
40618
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
40334
40619
|
const result = await startControlAndSync({
|
|
40335
40620
|
detach: input.detach,
|
|
40336
|
-
cwd:
|
|
40621
|
+
cwd: path47.resolve(input.repo)
|
|
40337
40622
|
});
|
|
40338
40623
|
if (result.code !== 0) {
|
|
40339
40624
|
return {
|
|
@@ -40396,8 +40681,10 @@ var mcpCommand = {
|
|
|
40396
40681
|
};
|
|
40397
40682
|
|
|
40398
40683
|
// src/cli/commands/telemetry.ts
|
|
40399
|
-
var
|
|
40400
|
-
|
|
40684
|
+
var path48 = __toESM(require("path"));
|
|
40685
|
+
init_control_config();
|
|
40686
|
+
init_otel_hooks();
|
|
40687
|
+
init_telemetry_config();
|
|
40401
40688
|
function printSignals() {
|
|
40402
40689
|
info("Collected when enabled (local Mission Control only):");
|
|
40403
40690
|
for (const signal of TELEMETRY_SIGNALS) {
|
|
@@ -40421,6 +40708,8 @@ async function handleStatus3(argv) {
|
|
|
40421
40708
|
controlApiUrl: apiUrl,
|
|
40422
40709
|
controlReachable: reachable,
|
|
40423
40710
|
otelEndpoint: `${apiUrl.replace(/\/$/, "")}/api/otel`,
|
|
40711
|
+
otelHooksHome: getOtelHooksHome(),
|
|
40712
|
+
otelHooksConfig: getOtelHooksConfigPath(),
|
|
40424
40713
|
signalDescriptions: [...TELEMETRY_SIGNALS]
|
|
40425
40714
|
};
|
|
40426
40715
|
if (argv.json) {
|
|
@@ -40436,25 +40725,29 @@ async function handleStatus3(argv) {
|
|
|
40436
40725
|
);
|
|
40437
40726
|
info(`Mission Control: ${apiUrl} (${reachable ? "reachable" : "not reachable"})`);
|
|
40438
40727
|
info(`OTLP endpoint: ${payload.otelEndpoint}`);
|
|
40728
|
+
info(`Hooks home: ${payload.otelHooksHome}`);
|
|
40439
40729
|
printSignals();
|
|
40440
40730
|
}
|
|
40441
40731
|
async function handleOn(argv) {
|
|
40442
40732
|
header("har telemetry on");
|
|
40443
40733
|
const preference = writeTelemetryPreference(true, {
|
|
40444
40734
|
prompts: argv.prompts === true ? true : void 0,
|
|
40445
|
-
traces:
|
|
40735
|
+
traces: true
|
|
40446
40736
|
});
|
|
40447
|
-
success("Telemetry enabled
|
|
40737
|
+
success("Telemetry enabled. Cursor / Claude / Codex export via opentelemetry-hooks \u2192 Mission Control.");
|
|
40448
40738
|
info(
|
|
40449
40739
|
`Signals: metrics=${preference.signals.metrics} logs=${preference.signals.logs} prompts=${preference.signals.prompts} traces=${preference.signals.traces}`
|
|
40450
40740
|
);
|
|
40451
40741
|
if (preference.signals.prompts) {
|
|
40452
|
-
warn("Prompt
|
|
40742
|
+
warn("Prompt text will leave the agent machine for local Mission Control (also used as session purpose).");
|
|
40453
40743
|
}
|
|
40454
40744
|
printSignals();
|
|
40455
40745
|
const result = await ensureTelemetryInfrastructure({ startIfNeeded: true });
|
|
40456
40746
|
if (result.message) success(result.message);
|
|
40457
40747
|
if (result.warning) warn(result.warning);
|
|
40748
|
+
const hooks = ensureOtelHooks({ setupAgents: true });
|
|
40749
|
+
if (hooks.message) success(hooks.message);
|
|
40750
|
+
if (hooks.warning) warn(hooks.warning);
|
|
40458
40751
|
if (result.otelReady) {
|
|
40459
40752
|
info(`OTLP ingest: ${result.apiUrl.replace(/\/$/, "")}/api/otel`);
|
|
40460
40753
|
info("Usage appears under Mission Control \u2192 Worktrees / Usage. Disable: har telemetry off");
|
|
@@ -40463,44 +40756,48 @@ async function handleOn(argv) {
|
|
|
40463
40756
|
async function handleOff() {
|
|
40464
40757
|
header("har telemetry off");
|
|
40465
40758
|
writeTelemetryPreference(false);
|
|
40759
|
+
try {
|
|
40760
|
+
disableOtelHooksExport();
|
|
40761
|
+
} catch (err) {
|
|
40762
|
+
warn(`Could not refresh hooks config: ${err instanceof Error ? err.message : String(err)}`);
|
|
40763
|
+
}
|
|
40466
40764
|
success("Telemetry disabled.");
|
|
40467
|
-
info("
|
|
40468
|
-
info("
|
|
40765
|
+
info("Hooks stay registered but OTLP export is cleared in ~/.har/otel-hooks/otel_config.json.");
|
|
40766
|
+
info("Mission Control will not auto-start. Existing usage rows are kept.");
|
|
40469
40767
|
}
|
|
40470
40768
|
async function handleWriteEnv(argv) {
|
|
40471
|
-
const repoPath =
|
|
40769
|
+
const repoPath = path48.resolve(argv.repo);
|
|
40472
40770
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
40473
40771
|
const session = readSlotRegistry(harnessRoot, argv.agentId);
|
|
40474
40772
|
const workDir = argv.workDir ?? session?.workDir ?? repoPath;
|
|
40475
40773
|
const branch = argv.branch ?? session?.branch;
|
|
40476
40774
|
const suffix = argv.suffix ?? session?.suffix;
|
|
40477
|
-
const purpose = argv.purpose ?? session?.purpose;
|
|
40478
40775
|
const sessionKey = argv.sessionKey ?? buildSessionKey({
|
|
40479
40776
|
branch,
|
|
40480
40777
|
agentId: argv.agentId,
|
|
40481
40778
|
suffix,
|
|
40482
40779
|
createdAt: session?.createdAt
|
|
40483
40780
|
});
|
|
40484
|
-
const envFile = argv.envFile ??
|
|
40485
|
-
let otelReady = argv.otelReady;
|
|
40486
|
-
if (otelReady === void 0 && isTelemetryEnabled()) {
|
|
40487
|
-
const ensured = await ensureTelemetryInfrastructure({ startIfNeeded: false });
|
|
40488
|
-
otelReady = ensured.otelReady;
|
|
40489
|
-
}
|
|
40781
|
+
const envFile = argv.envFile ?? path48.join(workDir, `.env.agent.${argv.agentId}`);
|
|
40490
40782
|
const attrs = {
|
|
40491
40783
|
sessionKey,
|
|
40492
40784
|
agentId: argv.agentId,
|
|
40493
40785
|
repoPath,
|
|
40494
40786
|
workDir,
|
|
40495
40787
|
branch,
|
|
40496
|
-
suffix
|
|
40497
|
-
purpose
|
|
40788
|
+
suffix
|
|
40498
40789
|
};
|
|
40499
|
-
appendTelemetryEnvToFile(envFile, attrs
|
|
40500
|
-
|
|
40790
|
+
appendTelemetryEnvToFile(envFile, attrs);
|
|
40791
|
+
if (isTelemetryEnabled()) {
|
|
40792
|
+
ensureOtelHooks({
|
|
40793
|
+
setupAgents: false,
|
|
40794
|
+
resourceAttributes: buildOtelResourceAttributes(attrs)
|
|
40795
|
+
});
|
|
40796
|
+
}
|
|
40797
|
+
success(`Wrote session attribution to ${envFile}`);
|
|
40501
40798
|
}
|
|
40502
40799
|
function handlePrintEnv(argv) {
|
|
40503
|
-
const repoPath =
|
|
40800
|
+
const repoPath = path48.resolve(argv.repo);
|
|
40504
40801
|
const workDir = argv.workDir ?? repoPath;
|
|
40505
40802
|
const sessionKey = buildSessionKey({
|
|
40506
40803
|
branch: argv.branch,
|
|
@@ -40508,55 +40805,38 @@ function handlePrintEnv(argv) {
|
|
|
40508
40805
|
suffix: argv.suffix
|
|
40509
40806
|
});
|
|
40510
40807
|
process.stdout.write(
|
|
40511
|
-
buildTelemetryEnvBlock(
|
|
40512
|
-
|
|
40513
|
-
|
|
40514
|
-
|
|
40515
|
-
|
|
40516
|
-
|
|
40517
|
-
|
|
40518
|
-
|
|
40519
|
-
},
|
|
40520
|
-
{ otelReady: argv.otelReady && isTelemetryEnabled() }
|
|
40521
|
-
)
|
|
40808
|
+
buildTelemetryEnvBlock({
|
|
40809
|
+
sessionKey,
|
|
40810
|
+
agentId: argv.agentId,
|
|
40811
|
+
repoPath,
|
|
40812
|
+
workDir,
|
|
40813
|
+
branch: argv.branch,
|
|
40814
|
+
suffix: argv.suffix
|
|
40815
|
+
})
|
|
40522
40816
|
);
|
|
40523
40817
|
}
|
|
40524
|
-
function
|
|
40525
|
-
|
|
40526
|
-
|
|
40527
|
-
|
|
40528
|
-
|
|
40529
|
-
|
|
40530
|
-
const
|
|
40531
|
-
|
|
40532
|
-
|
|
40533
|
-
|
|
40534
|
-
|
|
40535
|
-
|
|
40536
|
-
|
|
40537
|
-
|
|
40538
|
-
|
|
40539
|
-
|
|
40540
|
-
|
|
40541
|
-
workDir,
|
|
40542
|
-
branch,
|
|
40543
|
-
suffix,
|
|
40544
|
-
purpose: session?.purpose
|
|
40545
|
-
});
|
|
40546
|
-
if (argv.write) {
|
|
40547
|
-
const outDir = path47.join(harnessRoot, ".har", "telemetry");
|
|
40548
|
-
fs40.mkdirSync(outDir, { recursive: true });
|
|
40549
|
-
const outPath = path47.join(outDir, "codex.otel.toml.snippet");
|
|
40550
|
-
fs40.writeFileSync(outPath, snippet);
|
|
40551
|
-
success(`Wrote ${outPath}`);
|
|
40552
|
-
info("Merge the [otel] table into ~/.codex/config.toml manually.");
|
|
40553
|
-
return;
|
|
40818
|
+
async function handleInstallHooks() {
|
|
40819
|
+
header("har telemetry install-hooks");
|
|
40820
|
+
if (!isTelemetryEnabled()) {
|
|
40821
|
+
warn("Telemetry is off \u2014 enabling preference so hooks can export.");
|
|
40822
|
+
writeTelemetryPreference(true, { traces: true });
|
|
40823
|
+
}
|
|
40824
|
+
const result = await ensureTelemetryInfrastructure({ startIfNeeded: true });
|
|
40825
|
+
if (result.message) success(result.message);
|
|
40826
|
+
if (result.warning) warn(result.warning);
|
|
40827
|
+
const hooks = ensureOtelHooks({ setupAgents: true });
|
|
40828
|
+
if (hooks.ok) {
|
|
40829
|
+
success(hooks.message ?? "opentelemetry-hooks installed and agents registered");
|
|
40830
|
+
info(`Config: ${hooks.configPath}`);
|
|
40831
|
+
info(`Wrapper: ${hooks.wrapperPath}`);
|
|
40832
|
+
} else {
|
|
40833
|
+
error(hooks.warning ?? "Failed to install opentelemetry-hooks");
|
|
40834
|
+
process.exitCode = 1;
|
|
40554
40835
|
}
|
|
40555
|
-
process.stdout.write(snippet);
|
|
40556
40836
|
}
|
|
40557
40837
|
var telemetryCommand = {
|
|
40558
40838
|
command: "telemetry <subcommand>",
|
|
40559
|
-
describe: "Agent usage telemetry (Claude
|
|
40839
|
+
describe: "Agent usage telemetry (Cursor / Claude / Codex via opentelemetry-hooks \u2192 Mission Control)",
|
|
40560
40840
|
builder: (yargs) => yargs.command(
|
|
40561
40841
|
"status",
|
|
40562
40842
|
"Show telemetry preference and Mission Control reachability",
|
|
@@ -40566,34 +40846,40 @@ var telemetryCommand = {
|
|
|
40566
40846
|
}
|
|
40567
40847
|
).command(
|
|
40568
40848
|
"on",
|
|
40569
|
-
"Enable telemetry
|
|
40849
|
+
"Enable telemetry, ensure Mission Control, install/configure opentelemetry-hooks",
|
|
40570
40850
|
(y2) => y2.option("prompts", {
|
|
40571
40851
|
type: "boolean",
|
|
40572
40852
|
default: false,
|
|
40573
|
-
describe: "Opt in to shipping user
|
|
40574
|
-
}).option("traces", {
|
|
40575
|
-
type: "boolean",
|
|
40576
|
-
default: false,
|
|
40577
|
-
describe: "Opt in to thin OTEL traces ingest (Claude beta)"
|
|
40853
|
+
describe: "Opt in to shipping user prompt text (also fills Mission Control purpose)"
|
|
40578
40854
|
}),
|
|
40579
40855
|
(argv) => {
|
|
40580
40856
|
void handleOn({
|
|
40581
|
-
prompts: argv.prompts
|
|
40582
|
-
traces: argv.traces
|
|
40857
|
+
prompts: argv.prompts
|
|
40583
40858
|
});
|
|
40584
40859
|
}
|
|
40585
40860
|
).command(
|
|
40586
40861
|
"off",
|
|
40587
|
-
"Disable telemetry (
|
|
40862
|
+
"Disable telemetry (clear hooks OTLP endpoint, no MC auto-start)",
|
|
40588
40863
|
() => {
|
|
40589
40864
|
},
|
|
40590
40865
|
() => {
|
|
40591
40866
|
void handleOff();
|
|
40592
40867
|
}
|
|
40868
|
+
).command(
|
|
40869
|
+
"install-hooks",
|
|
40870
|
+
"Install opentelemetry-hooks and register Cursor / Claude / Codex",
|
|
40871
|
+
() => {
|
|
40872
|
+
},
|
|
40873
|
+
() => {
|
|
40874
|
+
void handleInstallHooks().catch((err) => {
|
|
40875
|
+
error(err instanceof Error ? err.message : String(err));
|
|
40876
|
+
process.exitCode = 1;
|
|
40877
|
+
});
|
|
40878
|
+
}
|
|
40593
40879
|
).command(
|
|
40594
40880
|
"write-env",
|
|
40595
|
-
"Append session
|
|
40596
|
-
(y2) => y2.option("agent-id", { type: "number", demandOption: true }).option("repo", { type: "string", default: "." }).option("env-file", { type: "string" }).option("work-dir", { type: "string" }).option("branch", { type: "string" }).option("suffix", { type: "string" }).option("
|
|
40881
|
+
"Append HAR session attribution to .env.agent.<id> and refresh hooks config",
|
|
40882
|
+
(y2) => y2.option("agent-id", { type: "number", demandOption: true }).option("repo", { type: "string", default: "." }).option("env-file", { type: "string" }).option("work-dir", { type: "string" }).option("branch", { type: "string" }).option("suffix", { type: "string" }).option("session-key", { type: "string" }),
|
|
40597
40883
|
(argv) => handleWriteEnv({
|
|
40598
40884
|
agentId: argv["agent-id"],
|
|
40599
40885
|
repo: argv.repo,
|
|
@@ -40601,42 +40887,23 @@ var telemetryCommand = {
|
|
|
40601
40887
|
workDir: argv["work-dir"],
|
|
40602
40888
|
branch: argv.branch,
|
|
40603
40889
|
suffix: argv.suffix,
|
|
40604
|
-
|
|
40605
|
-
sessionKey: argv["session-key"],
|
|
40606
|
-
otelReady: argv["otel-ready"]
|
|
40890
|
+
sessionKey: argv["session-key"]
|
|
40607
40891
|
}).catch((err) => {
|
|
40608
40892
|
error(err instanceof Error ? err.message : String(err));
|
|
40609
40893
|
process.exitCode = 1;
|
|
40610
40894
|
})
|
|
40611
40895
|
).command(
|
|
40612
40896
|
"print-env",
|
|
40613
|
-
"Print
|
|
40614
|
-
(y2) => y2.option("agent-id", { type: "number", demandOption: true }).option("repo", { type: "string", default: "." }).option("work-dir", { type: "string" }).option("branch", { type: "string" }).option("suffix", { type: "string" })
|
|
40897
|
+
"Print session attribution env block to stdout",
|
|
40898
|
+
(y2) => y2.option("agent-id", { type: "number", demandOption: true }).option("repo", { type: "string", default: "." }).option("work-dir", { type: "string" }).option("branch", { type: "string" }).option("suffix", { type: "string" }),
|
|
40615
40899
|
(argv) => handlePrintEnv({
|
|
40616
40900
|
agentId: argv["agent-id"],
|
|
40617
40901
|
repo: argv.repo,
|
|
40618
40902
|
workDir: argv["work-dir"],
|
|
40619
40903
|
branch: argv.branch,
|
|
40620
|
-
suffix: argv.suffix
|
|
40621
|
-
otelReady: argv["otel-ready"]
|
|
40622
|
-
})
|
|
40623
|
-
).command(
|
|
40624
|
-
"codex-snippet",
|
|
40625
|
-
"Print or write a Codex [otel] config snippet",
|
|
40626
|
-
(y2) => y2.option("agent-id", { type: "number", demandOption: true }).option("repo", { type: "string", default: "." }).option("work-dir", { type: "string" }).option("branch", { type: "string" }).option("suffix", { type: "string" }).option("write", {
|
|
40627
|
-
type: "boolean",
|
|
40628
|
-
default: false,
|
|
40629
|
-
describe: "Write to .har/telemetry/codex.otel.toml.snippet"
|
|
40630
|
-
}),
|
|
40631
|
-
(argv) => handleCodexSnippet({
|
|
40632
|
-
agentId: argv["agent-id"],
|
|
40633
|
-
repo: argv.repo,
|
|
40634
|
-
workDir: argv["work-dir"],
|
|
40635
|
-
branch: argv.branch,
|
|
40636
|
-
suffix: argv.suffix,
|
|
40637
|
-
write: argv.write
|
|
40904
|
+
suffix: argv.suffix
|
|
40638
40905
|
})
|
|
40639
|
-
).demandCommand(1, "Please specify a subcommand: status, on, off, write-env, print-env
|
|
40906
|
+
).demandCommand(1, "Please specify a subcommand: status, on, off, install-hooks, write-env, print-env"),
|
|
40640
40907
|
handler: () => {
|
|
40641
40908
|
}
|
|
40642
40909
|
};
|