@osfactory/har 0.31.0 → 0.32.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.
Files changed (2) hide show
  1. package/dist/index.js +125 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6621,6 +6621,7 @@ var init_control_config = __esm({
6621
6621
  // src/core/otel-hooks.ts
6622
6622
  var otel_hooks_exports = {};
6623
6623
  __export(otel_hooks_exports, {
6624
+ LEGACY_CURSOR_ONLY_HOOK_EVENTS: () => LEGACY_CURSOR_ONLY_HOOK_EVENTS,
6624
6625
  OTEL_HOOKS_AGENTS: () => OTEL_HOOKS_AGENTS,
6625
6626
  OTEL_HOOKS_PACKAGE: () => OTEL_HOOKS_PACKAGE,
6626
6627
  OTEL_HOOKS_PROVIDERS: () => OTEL_HOOKS_PROVIDERS,
@@ -6632,6 +6633,7 @@ __export(otel_hooks_exports, {
6632
6633
  getOtelHooksStateDir: () => getOtelHooksStateDir,
6633
6634
  getOtelHooksWrapperPath: () => getOtelHooksWrapperPath,
6634
6635
  parseResourceAttributesString: () => parseResourceAttributesString,
6636
+ pruneLegacyCursorHookEvents: () => pruneLegacyCursorHookEvents,
6635
6637
  rewriteHookCommandsToWrapper: () => rewriteHookCommandsToWrapper,
6636
6638
  writeOtelHooksConfig: () => writeOtelHooksConfig,
6637
6639
  writeOtelHooksWrapper: () => writeOtelHooksWrapper
@@ -6777,10 +6779,12 @@ function tryInstallPackage(hooksHome) {
6777
6779
  detail: `npm install ${OTEL_HOOKS_PACKAGE} failed: ${(result.stderr || result.stdout || "").trim().slice(0, 400)}`
6778
6780
  };
6779
6781
  }
6780
- function uninstallLegacyPythonHooks() {
6782
+ function uninstallLegacyPythonHooks(hooksHome) {
6781
6783
  const attempts = [
6782
6784
  ["uv", ["tool", "uninstall", "opentelemetry-hooks"]],
6783
- ["pipx", ["uninstall", "opentelemetry-hooks"]]
6785
+ ["pipx", ["uninstall", "opentelemetry-hooks"]],
6786
+ ["pip", ["uninstall", "-y", "opentelemetry-hooks"]],
6787
+ ["pip3", ["uninstall", "-y", "opentelemetry-hooks"]]
6784
6788
  ];
6785
6789
  for (const [cmd, args] of attempts) {
6786
6790
  if (!commandExists2(cmd)) continue;
@@ -6789,6 +6793,31 @@ function uninstallLegacyPythonHooks() {
6789
6793
  } catch {
6790
6794
  }
6791
6795
  }
6796
+ removeLegacyPythonArtifacts(hooksHome);
6797
+ }
6798
+ function removeLegacyPythonArtifacts(hooksHome) {
6799
+ const legacyPaths = [
6800
+ path45.join(hooksHome, ".venv"),
6801
+ path45.join(hooksHome, "otel_config.yaml"),
6802
+ path45.join(hooksHome, "venv")
6803
+ ];
6804
+ for (const target of legacyPaths) {
6805
+ try {
6806
+ if (fs42.existsSync(target)) {
6807
+ fs42.rmSync(target, { recursive: true, force: true });
6808
+ }
6809
+ } catch {
6810
+ }
6811
+ }
6812
+ }
6813
+ function isOtelHookCommand(command2, wrapperPath) {
6814
+ if (command2.includes("otel-hook") || command2.includes("otel_hook.py") || command2.includes("opentelemetry-hooks")) {
6815
+ return true;
6816
+ }
6817
+ return wrapperPath !== void 0 && command2.includes(wrapperPath);
6818
+ }
6819
+ function normalizeLegacyProviderFlagsInCommand(command2) {
6820
+ return command2.replace(/(^|\s)--cursor(?=\s|$)/g, "$1--provider cursor").replace(/(^|\s)--claude(?=\s|$)/g, "$1--provider claude-code").replace(/(^|\s)--codex(?=\s|$)/g, "$1--provider codex");
6792
6821
  }
6793
6822
  function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
6794
6823
  const hookCommand = `${wrapperPath} --provider ${providerId}`;
@@ -6831,18 +6860,21 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
6831
6860
  }
6832
6861
  if (!parsed || typeof parsed !== "object") return false;
6833
6862
  const rewriteCommand = (command2) => {
6834
- if (!command2.includes("otel-hook") && !command2.includes("otel_hook.py") && !command2.includes("opentelemetry-hooks")) {
6863
+ if (!isOtelHookCommand(command2, wrapperPath)) {
6835
6864
  return command2;
6836
6865
  }
6837
- if (command2.includes(wrapperPath)) return command2;
6838
- const rewritten = command2.replace(
6866
+ const normalized = normalizeLegacyProviderFlagsInCommand(command2);
6867
+ if (command2.includes(wrapperPath)) {
6868
+ return normalized;
6869
+ }
6870
+ const rewritten = normalized.replace(
6839
6871
  /(?:^|[;&|]\s*)(?:env\s+[^=\s]+=\S+\s+)*(?:python3?\s+)?(?:npx\s+)?(?:\S*otel[_-]hook\S*|\S*opentelemetry-hooks\S*)/,
6840
6872
  (match) => match.replace(
6841
6873
  /(?:python3?\s+)?(?:npx\s+)?(?:\S*otel[_-]hook\S*|\S*opentelemetry-hooks\S*)/,
6842
6874
  wrapperPath
6843
6875
  )
6844
6876
  );
6845
- return rewritten.replace(/(^|\s)--cursor(?=\s|$)/g, "$1--provider cursor").replace(/(^|\s)--claude(?=\s|$)/g, "$1--provider claude-code").replace(/(^|\s)--codex(?=\s|$)/g, "$1--provider codex");
6877
+ return normalizeLegacyProviderFlagsInCommand(rewritten);
6846
6878
  };
6847
6879
  const walk = (node) => {
6848
6880
  let changed = false;
@@ -6867,6 +6899,49 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
6867
6899
  `);
6868
6900
  return true;
6869
6901
  }
6902
+ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
6903
+ if (!fs42.existsSync(filePath)) return false;
6904
+ let raw;
6905
+ try {
6906
+ raw = fs42.readFileSync(filePath, "utf8");
6907
+ } catch {
6908
+ return false;
6909
+ }
6910
+ let parsed;
6911
+ try {
6912
+ parsed = JSON.parse(raw);
6913
+ } catch {
6914
+ return false;
6915
+ }
6916
+ if (!parsed || typeof parsed !== "object") return false;
6917
+ const root = parsed;
6918
+ if (!root.hooks || typeof root.hooks !== "object" || Array.isArray(root.hooks)) {
6919
+ return false;
6920
+ }
6921
+ const hooks = root.hooks;
6922
+ let changed = false;
6923
+ for (const event of LEGACY_CURSOR_ONLY_HOOK_EVENTS) {
6924
+ const list = hooks[event];
6925
+ if (!Array.isArray(list)) continue;
6926
+ const kept = list.filter((entry) => {
6927
+ if (!entry || typeof entry !== "object") return true;
6928
+ const command2 = entry.command;
6929
+ if (typeof command2 !== "string") return true;
6930
+ return !isOtelHookCommand(command2, wrapperPath);
6931
+ });
6932
+ if (kept.length === list.length) continue;
6933
+ changed = true;
6934
+ if (kept.length === 0) {
6935
+ delete hooks[event];
6936
+ } else {
6937
+ hooks[event] = kept;
6938
+ }
6939
+ }
6940
+ if (!changed) return false;
6941
+ fs42.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
6942
+ `);
6943
+ return true;
6944
+ }
6870
6945
  function rewriteKnownHookRegistrations(wrapperPath) {
6871
6946
  const home = os14.homedir();
6872
6947
  const candidates = [
@@ -6877,6 +6952,9 @@ function rewriteKnownHookRegistrations(wrapperPath) {
6877
6952
  for (const filePath of candidates) {
6878
6953
  try {
6879
6954
  rewriteHookCommandsToWrapper(filePath, wrapperPath);
6955
+ if (filePath.endsWith(`${path45.sep}.cursor${path45.sep}hooks.json`)) {
6956
+ pruneLegacyCursorHookEvents(filePath, wrapperPath);
6957
+ }
6880
6958
  } catch {
6881
6959
  }
6882
6960
  }
@@ -6957,7 +7035,7 @@ function ensureOtelHooks(options) {
6957
7035
  hooksHome
6958
7036
  );
6959
7037
  const wrapperPath = writeOtelHooksWrapper(resolvedCommand, hooksHome);
6960
- uninstallLegacyPythonHooks();
7038
+ uninstallLegacyPythonHooks(hooksHome);
6961
7039
  if (options?.setupAgents !== false && isTelemetryEnabled()) {
6962
7040
  for (const provider of OTEL_HOOKS_PROVIDERS) {
6963
7041
  const setup = runSetupProvider(provider.id, resolvedCommand, wrapperPath);
@@ -6984,7 +7062,7 @@ function ensureOtelHooks(options) {
6984
7062
  function disableOtelHooksExport() {
6985
7063
  return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
6986
7064
  }
6987
- var import_child_process10, fs42, os14, path45, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS;
7065
+ var import_child_process10, fs42, os14, path45, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
6988
7066
  var init_otel_hooks = __esm({
6989
7067
  "src/core/otel-hooks.ts"() {
6990
7068
  "use strict";
@@ -7001,6 +7079,17 @@ var init_otel_hooks = __esm({
7001
7079
  { id: "codex", label: "codex" }
7002
7080
  ];
7003
7081
  OTEL_HOOKS_AGENTS = ["cursor", "claude", "codex"];
7082
+ LEGACY_CURSOR_ONLY_HOOK_EVENTS = [
7083
+ "afterAgentResponse",
7084
+ "afterAgentThought",
7085
+ "beforeShellExecution",
7086
+ "afterShellExecution",
7087
+ "beforeMCPExecution",
7088
+ "afterMCPExecution",
7089
+ "beforeReadFile",
7090
+ "subagentStart",
7091
+ "subagentStop"
7092
+ ];
7004
7093
  }
7005
7094
  });
7006
7095
 
@@ -37226,13 +37315,13 @@ function usage(yargs, shim3) {
37226
37315
  };
37227
37316
  self.stringifiedValues = function stringifiedValues(values, separator) {
37228
37317
  let string3 = "";
37229
- const sep6 = separator || ", ";
37318
+ const sep7 = separator || ", ";
37230
37319
  const array2 = [].concat(values);
37231
37320
  if (!values || !array2.length)
37232
37321
  return string3;
37233
37322
  array2.forEach((value) => {
37234
37323
  if (string3.length)
37235
- string3 += sep6;
37324
+ string3 += sep7;
37236
37325
  string3 += JSON.stringify(value);
37237
37326
  });
37238
37327
  return string3;
@@ -44248,6 +44337,7 @@ var HarnessVerificationResultSchema = external_exports.object({
44248
44337
  status: external_exports.enum(["pass", "fail"]),
44249
44338
  agent_id: external_exports.number().int().min(HAR_AGENT_SLOT_MIN),
44250
44339
  total_ms: external_exports.number().optional(),
44340
+ coverage: external_exports.number().min(0).max(100).optional(),
44251
44341
  stages: external_exports.array(HarnessVerificationStepSchema)
44252
44342
  });
44253
44343
  var HarnessStageRunStatusSchema = external_exports.enum([
@@ -44572,6 +44662,7 @@ var AgentSessionUsageSchema = external_exports.object({
44572
44662
  sessionKey: external_exports.string().min(1),
44573
44663
  agentId: external_exports.number().int().min(HAR_AGENT_SLOT_MIN),
44574
44664
  agentTool: AgentToolSchema,
44665
+ userEmail: external_exports.string().email().optional(),
44575
44666
  workDir: external_exports.string().optional(),
44576
44667
  branch: external_exports.string().optional(),
44577
44668
  suffix: external_exports.string().optional(),
@@ -67894,24 +67985,36 @@ function providerHint(agentTool) {
67894
67985
  if (agentTool === "codex") return "openai";
67895
67986
  return void 0;
67896
67987
  }
67988
+ function toGenaiPricesUsage(totals) {
67989
+ const rawInput = num(totals.tokensInput);
67990
+ const cacheRead = num(totals.tokensCacheRead);
67991
+ const cacheWrite = num(totals.tokensCacheCreation);
67992
+ const uncached = rawInput >= cacheRead ? rawInput - cacheRead : rawInput;
67993
+ const inclusiveInput = uncached + cacheRead + cacheWrite;
67994
+ return {
67995
+ input_tokens: inclusiveInput,
67996
+ output_tokens: num(totals.tokensOutput),
67997
+ cache_read_tokens: cacheRead,
67998
+ cache_write_tokens: cacheWrite
67999
+ };
68000
+ }
67897
68001
  function pricingModelCandidates(modelId) {
67898
68002
  const out = [modelId];
67899
68003
  if (modelId.startsWith("cursor-")) out.push(modelId.slice("cursor-".length));
67900
68004
  return [...new Set(out)];
67901
68005
  }
67902
68006
  function estimateModelCostUsd(modelId, totals, agentTool) {
67903
- const usage2 = {
67904
- input_tokens: num(totals.tokensInput),
67905
- output_tokens: num(totals.tokensOutput),
67906
- cache_read_tokens: num(totals.tokensCacheRead),
67907
- cache_write_tokens: num(totals.tokensCacheCreation)
67908
- };
67909
- const tokenSum = usage2.input_tokens + usage2.output_tokens + usage2.cache_read_tokens + usage2.cache_write_tokens;
68007
+ const usage2 = toGenaiPricesUsage(totals);
68008
+ const tokenSum = usage2.input_tokens + usage2.output_tokens;
67910
68009
  if (tokenSum <= 0) return null;
67911
68010
  const providerId = providerHint(agentTool);
67912
68011
  for (const candidate of pricingModelCandidates(modelId)) {
67913
- const result = ve(usage2, candidate, providerId ? { providerId } : void 0);
67914
- if (result) return result.total_price;
68012
+ try {
68013
+ const result = ve(usage2, candidate, providerId ? { providerId } : void 0);
68014
+ if (result) return result.total_price;
68015
+ } catch {
68016
+ continue;
68017
+ }
67915
68018
  }
67916
68019
  return null;
67917
68020
  }
@@ -76180,6 +76283,7 @@ async function syncRepoRunsAndSlots(apiUrl, repoId, repoPath, dryRun) {
76180
76283
  }
76181
76284
  if (isTelemetryEnabled() && process.env.NODE_ENV !== "test") {
76182
76285
  try {
76286
+ const userEmail = resolvePortalUserEmail();
76183
76287
  const usage2 = status.slots.flatMap(
76184
76288
  (slot) => harvestUsageForSlot({
76185
76289
  agentId: slot.agentId,
@@ -76198,7 +76302,8 @@ async function syncRepoRunsAndSlots(apiUrl, repoId, repoPath, dryRun) {
76198
76302
  agentId: slot.agentId,
76199
76303
  suffix: slot.suffix,
76200
76304
  createdAt: slot.sessionCreatedAt
76201
- })
76305
+ }),
76306
+ ...userEmail ? { userEmail } : {}
76202
76307
  }))
76203
76308
  );
76204
76309
  if (usage2.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "LLM-powered CLI for reproducible agent development environments",
5
5
  "keywords": [
6
6
  "har",