@osfactory/har 0.13.0 → 0.14.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 +225 -67
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23129,6 +23129,22 @@ var AgentSessionUsageSchema = external_exports.object({
23129
23129
  var SyncUsageInputSchema = external_exports.object({
23130
23130
  usage: external_exports.array(AgentSessionUsageSchema)
23131
23131
  });
23132
+ var AgentSessionEventSchema = external_exports.object({
23133
+ sessionKey: external_exports.string().min(1),
23134
+ agentId: external_exports.number().int().min(HAR_AGENT_SLOT_MIN),
23135
+ agentTool: AgentToolSchema,
23136
+ eventName: external_exports.string().min(1),
23137
+ sequence: external_exports.number().int().nonnegative().default(0),
23138
+ timestamp: external_exports.string(),
23139
+ attributes: external_exports.record(external_exports.unknown()).optional(),
23140
+ promptText: external_exports.string().nullable().optional(),
23141
+ responseText: external_exports.string().nullable().optional(),
23142
+ rawTruncated: external_exports.string().nullable().optional(),
23143
+ source: external_exports.enum(["otel", "harvest"]).default("otel")
23144
+ });
23145
+ var SyncSessionEventsInputSchema = external_exports.object({
23146
+ events: external_exports.array(AgentSessionEventSchema)
23147
+ });
23132
23148
 
23133
23149
  // src/harness/manifest.ts
23134
23150
  var GENERATOR_VERSION = "0.4.0";
@@ -23367,7 +23383,7 @@ async function handleAgentSkills(options) {
23367
23383
  const { repoPath, mode } = options;
23368
23384
  if (options.enabled === false) return false;
23369
23385
  let targets;
23370
- if (options.agents !== void 0) {
23386
+ if (typeof options.agents === "string") {
23371
23387
  targets = parseAgentTargets(options.agents);
23372
23388
  } else {
23373
23389
  targets = detectAgentTargets(repoPath);
@@ -29915,6 +29931,18 @@ function createRemoteExecutor(apiUrl, apiKey) {
29915
29931
  var fs33 = __toESM(require("fs"));
29916
29932
  var os9 = __toESM(require("os"));
29917
29933
  var path33 = __toESM(require("path"));
29934
+ var DEFAULT_SIGNALS_ON = {
29935
+ metrics: true,
29936
+ logs: true,
29937
+ prompts: false,
29938
+ traces: false
29939
+ };
29940
+ var DEFAULT_SIGNALS_OFF = {
29941
+ metrics: false,
29942
+ logs: false,
29943
+ prompts: false,
29944
+ traces: false
29945
+ };
29918
29946
  function getPreferencePath() {
29919
29947
  if (process.env.HAR_TELEMETRY_CONFIG_PATH) {
29920
29948
  return path33.resolve(process.env.HAR_TELEMETRY_CONFIG_PATH);
@@ -29928,24 +29956,41 @@ function parseEnvOverride(raw) {
29928
29956
  if (["1", "true", "on", "yes", "enabled"].includes(normalized)) return true;
29929
29957
  return void 0;
29930
29958
  }
29959
+ function normalizeSignals(enabled, raw) {
29960
+ if (!enabled) return { ...DEFAULT_SIGNALS_OFF };
29961
+ return {
29962
+ metrics: raw?.metrics !== false,
29963
+ logs: raw?.logs !== false,
29964
+ prompts: raw?.prompts === true,
29965
+ traces: raw?.traces === true
29966
+ };
29967
+ }
29931
29968
  function readTelemetryPreference() {
29932
29969
  const preferencePath = getPreferencePath();
29933
29970
  try {
29934
29971
  if (!fs33.existsSync(preferencePath)) {
29935
- return { enabled: true };
29972
+ return { enabled: true, signals: { ...DEFAULT_SIGNALS_ON } };
29936
29973
  }
29937
29974
  const parsed = JSON.parse(fs33.readFileSync(preferencePath, "utf8"));
29975
+ const enabled = parsed.enabled !== false;
29938
29976
  return {
29939
- enabled: parsed.enabled !== false,
29977
+ enabled,
29978
+ signals: normalizeSignals(enabled, parsed.signals),
29940
29979
  updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : void 0
29941
29980
  };
29942
29981
  } catch {
29943
- return { enabled: true };
29982
+ return { enabled: true, signals: { ...DEFAULT_SIGNALS_ON } };
29944
29983
  }
29945
29984
  }
29946
- function writeTelemetryPreference(enabled) {
29985
+ function writeTelemetryPreference(enabled, signals) {
29986
+ const current = readTelemetryPreference();
29987
+ const nextSignals = normalizeSignals(enabled, {
29988
+ ...current.signals,
29989
+ ...signals
29990
+ });
29947
29991
  const preference = {
29948
29992
  enabled,
29993
+ signals: enabled ? nextSignals : { ...DEFAULT_SIGNALS_OFF },
29949
29994
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
29950
29995
  };
29951
29996
  const preferencePath = getPreferencePath();
@@ -29958,12 +30003,18 @@ function isTelemetryEnabled() {
29958
30003
  if (envOverride !== void 0) return envOverride;
29959
30004
  return readTelemetryPreference().enabled;
29960
30005
  }
30006
+ function getTelemetrySignals() {
30007
+ if (!isTelemetryEnabled()) return { ...DEFAULT_SIGNALS_OFF };
30008
+ return readTelemetryPreference().signals;
30009
+ }
29961
30010
  function getTelemetryPreferencePath() {
29962
30011
  return getPreferencePath();
29963
30012
  }
29964
30013
  var TELEMETRY_SIGNALS = [
29965
- "Claude Code: tokens (input/output/cache) and estimated USD cost via OTEL metrics",
29966
- "Codex CLI: token usage via OTEL metrics (no native USD; harvest fills gaps)",
30014
+ "Metrics (default): tokens and estimated USD cost via OTEL metrics",
30015
+ "Logs/events (default): session events (tool calls, api_request) without prompt bodies",
30016
+ "Prompts (opt-in): user/assistant text via OTEL_LOG_USER_PROMPTS \u2014 har telemetry on --prompts",
30017
+ "Traces (opt-in): thin span ingest when CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1",
29967
30018
  "Fallback: har control sync harvests local Claude/Codex session files when OTEL is missing"
29968
30019
  ];
29969
30020
 
@@ -30006,13 +30057,31 @@ function buildTelemetryEnvBlock(attrs, options) {
30006
30057
  ];
30007
30058
  const injectOtel = isTelemetryEnabled() && options?.otelReady !== false;
30008
30059
  if (injectOtel) {
30060
+ const signals = getTelemetrySignals();
30009
30061
  lines.push(
30010
30062
  "# HAR telemetry \u2192 Mission Control OTLP (disable: har telemetry off)",
30011
30063
  "CLAUDE_CODE_ENABLE_TELEMETRY=1",
30012
- "OTEL_METRICS_EXPORTER=otlp",
30013
30064
  "OTEL_EXPORTER_OTLP_PROTOCOL=http/json",
30014
30065
  `OTEL_EXPORTER_OTLP_ENDPOINT=${apiUrl}/api/otel`
30015
30066
  );
30067
+ if (signals.metrics) {
30068
+ lines.push("OTEL_METRICS_EXPORTER=otlp");
30069
+ }
30070
+ if (signals.logs) {
30071
+ lines.push("OTEL_LOGS_EXPORTER=otlp");
30072
+ }
30073
+ if (signals.prompts) {
30074
+ lines.push(
30075
+ "OTEL_LOG_USER_PROMPTS=1",
30076
+ "OTEL_LOG_ASSISTANT_RESPONSES=1"
30077
+ );
30078
+ }
30079
+ if (signals.traces) {
30080
+ lines.push(
30081
+ "OTEL_TRACES_EXPORTER=otlp",
30082
+ "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1"
30083
+ );
30084
+ }
30016
30085
  }
30017
30086
  return lines.join("\n") + "\n";
30018
30087
  }
@@ -30111,19 +30180,12 @@ function extractClaudeUsageFromRecords(records) {
30111
30180
  }
30112
30181
  return { tokensInput, tokensOutput, tokensCacheRead, tokensCacheCreation, costUsd };
30113
30182
  }
30114
- function harvestClaudeUsage(slot) {
30183
+ function findMatchingClaudeTranscripts(slot) {
30115
30184
  const targets = [slot.workDir, slot.worktreePath].filter(Boolean);
30116
- if (targets.length === 0) return null;
30185
+ if (targets.length === 0) return [];
30117
30186
  const root = claudeProjectsRoot();
30118
- if (!fs35.existsSync(root)) return null;
30119
- const sessionKey = buildSessionKey({
30120
- branch: slot.branch,
30121
- agentId: slot.agentId,
30122
- suffix: slot.suffix,
30123
- createdAt: slot.sessionCreatedAt
30124
- });
30125
- let best = null;
30126
- let bestMtime = 0;
30187
+ if (!fs35.existsSync(root)) return [];
30188
+ const matches = [];
30127
30189
  for (const entry of fs35.readdirSync(root, { withFileTypes: true })) {
30128
30190
  if (!entry.isDirectory()) continue;
30129
30191
  const projectDir = path35.join(root, entry.name);
@@ -30143,16 +30205,70 @@ function harvestClaudeUsage(slot) {
30143
30205
  }
30144
30206
  }
30145
30207
  if (!cwdHit) continue;
30146
- const usage2 = extractClaudeUsageFromRecords(records);
30147
- if (usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead === 0 && (usage2.costUsd == null || usage2.costUsd === 0)) {
30148
- continue;
30149
- }
30150
- if (stat.mtimeMs >= bestMtime) {
30151
- bestMtime = stat.mtimeMs;
30152
- best = usage2;
30153
- }
30208
+ matches.push({ filePath, records, mtimeMs: stat.mtimeMs });
30154
30209
  }
30155
30210
  }
30211
+ return matches.sort((a2, b2) => b2.mtimeMs - a2.mtimeMs);
30212
+ }
30213
+ function extractPromptEvents(records, sessionKey, slot) {
30214
+ const events = [];
30215
+ let sequence = 0;
30216
+ for (const record2 of records) {
30217
+ if (!record2 || typeof record2 !== "object") continue;
30218
+ const payload = record2;
30219
+ const typ = String(payload.type ?? "");
30220
+ const message = payload.message;
30221
+ const role = String(message?.role ?? payload.role ?? "");
30222
+ let text = null;
30223
+ const content = message?.content ?? payload.content;
30224
+ if (typeof content === "string") text = content;
30225
+ else if (Array.isArray(content)) {
30226
+ text = content.map((part) => {
30227
+ if (typeof part === "string") return part;
30228
+ if (part && typeof part === "object" && typeof part.text === "string") {
30229
+ return part.text;
30230
+ }
30231
+ return "";
30232
+ }).filter(Boolean).join("\n");
30233
+ }
30234
+ if (!text || text.trim().length === 0) continue;
30235
+ const isUser = typ === "user" || role === "user" || typ === "human" || Boolean(payload.userType);
30236
+ const isAssistant = typ === "assistant" || role === "assistant";
30237
+ if (!isUser && !isAssistant) continue;
30238
+ sequence += 1;
30239
+ const timestamp = typeof payload.timestamp === "string" ? payload.timestamp : typeof payload.ts === "string" ? payload.ts : (/* @__PURE__ */ new Date()).toISOString();
30240
+ events.push({
30241
+ sessionKey,
30242
+ agentId: slot.agentId,
30243
+ agentTool: "claude_code",
30244
+ eventName: isUser ? "claude_code.user_prompt" : "claude_code.assistant_response",
30245
+ sequence,
30246
+ timestamp,
30247
+ promptText: isUser ? text.slice(0, 8e3) : null,
30248
+ responseText: isAssistant ? text.slice(0, 8e3) : null,
30249
+ rawTruncated: text.slice(0, 4e3),
30250
+ source: "harvest"
30251
+ });
30252
+ }
30253
+ return events;
30254
+ }
30255
+ function harvestClaudeUsage(slot) {
30256
+ const matches = findMatchingClaudeTranscripts(slot);
30257
+ const sessionKey = buildSessionKey({
30258
+ branch: slot.branch,
30259
+ agentId: slot.agentId,
30260
+ suffix: slot.suffix,
30261
+ createdAt: slot.sessionCreatedAt
30262
+ });
30263
+ let best = null;
30264
+ for (const match of matches) {
30265
+ const usage2 = extractClaudeUsageFromRecords(match.records);
30266
+ if (usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead === 0 && (usage2.costUsd == null || usage2.costUsd === 0)) {
30267
+ continue;
30268
+ }
30269
+ best = usage2;
30270
+ break;
30271
+ }
30156
30272
  if (!best) return null;
30157
30273
  const now = (/* @__PURE__ */ new Date()).toISOString();
30158
30274
  const tokensTotal = best.tokensInput + best.tokensOutput + best.tokensCacheRead + best.tokensCacheCreation;
@@ -30174,6 +30290,18 @@ function harvestClaudeUsage(slot) {
30174
30290
  lastSeenAt: now
30175
30291
  };
30176
30292
  }
30293
+ function harvestClaudeEvents(slot) {
30294
+ if (!getTelemetrySignals().prompts) return [];
30295
+ const matches = findMatchingClaudeTranscripts(slot);
30296
+ if (matches.length === 0) return [];
30297
+ const sessionKey = buildSessionKey({
30298
+ branch: slot.branch,
30299
+ agentId: slot.agentId,
30300
+ suffix: slot.suffix,
30301
+ createdAt: slot.sessionCreatedAt
30302
+ });
30303
+ return extractPromptEvents(matches[0].records, sessionKey, slot).slice(-40);
30304
+ }
30177
30305
 
30178
30306
  // src/core/usage-harvest/codex.ts
30179
30307
  var fs36 = __toESM(require("fs"));
@@ -30300,6 +30428,9 @@ function harvestUsageForSlot(slot) {
30300
30428
  if (codex) out.push(codex);
30301
30429
  return out;
30302
30430
  }
30431
+ function harvestEventsForSlot(slot) {
30432
+ return harvestClaudeEvents(slot);
30433
+ }
30303
30434
 
30304
30435
  // src/core/control-sync.ts
30305
30436
  async function postJson(url, body, dryRun) {
@@ -30454,6 +30585,21 @@ async function syncRepoRunsAndSlots(apiUrl, repoId, repoPath, dryRun) {
30454
30585
  const usageBody = SyncUsageInputSchema.parse({ usage: usage2 });
30455
30586
  await postJson(`${apiUrl}/api/repos/${repoId}/usage`, usageBody, dryRun);
30456
30587
  }
30588
+ const events = status.slots.flatMap(
30589
+ (slot) => harvestEventsForSlot({
30590
+ agentId: slot.agentId,
30591
+ workDir: slot.workDir,
30592
+ worktreePath: slot.worktreePath,
30593
+ branch: slot.branch,
30594
+ suffix: slot.suffix,
30595
+ sessionCreatedAt: slot.sessionCreatedAt,
30596
+ repoPath
30597
+ })
30598
+ );
30599
+ if (events.length > 0) {
30600
+ const eventsBody = SyncSessionEventsInputSchema.parse({ events });
30601
+ await postJson(`${apiUrl}/api/repos/${repoId}/events`, eventsBody, dryRun);
30602
+ }
30457
30603
  } catch (err) {
30458
30604
  const message = err instanceof Error ? err.message : String(err);
30459
30605
  process.stderr.write(`[har control] usage harvest skipped: ${message}
@@ -31109,19 +31255,14 @@ var envCommand = {
31109
31255
  describe: "Auto-apply AGENT.md proposal without prompting (--auto only)"
31110
31256
  }).option("cursor-rule", {
31111
31257
  type: "boolean",
31112
- default: false,
31113
- describe: "Create .cursor/rules/har-workflow.mdc without prompting"
31114
- }).option("no-cursor-rule", {
31115
- type: "boolean",
31116
- default: false,
31117
- describe: "Skip Cursor rule scaffolding"
31258
+ // No default: unset → prompt/auto-detect; --cursor-rule → true; --no-cursor-rule → false
31259
+ // (do not declare a separate --no-cursor-rule option — yargs negation owns that.)
31260
+ describe: "Create .cursor/rules/har-workflow.mdc without prompting (use --no-cursor-rule to skip)"
31118
31261
  }).option("agents", {
31119
31262
  type: "string",
31120
- describe: "Scaffold agent skills for these targets (comma-separated: claude,cursor,codex); auto-detected when omitted"
31121
- }).option("no-agents", {
31122
- type: "boolean",
31123
- default: false,
31124
- describe: "Skip agent skills scaffolding"
31263
+ // --no-agents is yargs negation of this string option (sets agents=false). Do not
31264
+ // declare a separate --no-agents boolean — it collides and crashes parseAgentTargets.
31265
+ describe: "Scaffold agent skills for these targets (comma-separated: claude,cursor,codex); auto-detected when omitted; --no-agents to skip"
31125
31266
  }),
31126
31267
  handleInit
31127
31268
  ).command(
@@ -31140,19 +31281,11 @@ var envCommand = {
31140
31281
  describe: "Adaptation summary to store in the manifest (--finalize only)"
31141
31282
  }).option("cursor-rule", {
31142
31283
  type: "boolean",
31143
- default: false,
31144
- describe: "Create .cursor/rules/har-workflow.mdc without prompting"
31145
- }).option("no-cursor-rule", {
31146
- type: "boolean",
31147
- default: false,
31148
- describe: "Skip Cursor rule scaffolding"
31284
+ // No default: unset → prompt/auto-detect; --cursor-rule → true; --no-cursor-rule → false
31285
+ describe: "Create .cursor/rules/har-workflow.mdc without prompting (use --no-cursor-rule to skip)"
31149
31286
  }).option("agents", {
31150
31287
  type: "string",
31151
- describe: "Scaffold agent skills for these targets (comma-separated: claude,cursor,codex); auto-detected when omitted"
31152
- }).option("no-agents", {
31153
- type: "boolean",
31154
- default: false,
31155
- describe: "Skip agent skills scaffolding"
31288
+ describe: "Scaffold agent skills for these targets (comma-separated: claude,cursor,codex); auto-detected when omitted; --no-agents to skip"
31156
31289
  }),
31157
31290
  handleMaintain
31158
31291
  ).command(
@@ -31328,14 +31461,13 @@ async function handleInit(argv) {
31328
31461
  recordRepoForControlSync(repoPath);
31329
31462
  await handleCursorRule({
31330
31463
  repoPath,
31331
- cursorRule: resolveCursorRuleFlag(argv.cursorRule, argv.noCursorRule),
31464
+ cursorRule: resolveCursorRuleFlag(argv.cursorRule),
31332
31465
  autoYes: argv.yes,
31333
31466
  mode: "init"
31334
31467
  });
31335
31468
  await handleAgentSkills({
31336
31469
  repoPath,
31337
- agents: argv.agents,
31338
- enabled: argv.noAgents ? false : void 0,
31470
+ ...resolveAgentsScaffoldOptions(argv.agents),
31339
31471
  autoYes: argv.yes,
31340
31472
  force: argv.force,
31341
31473
  mode: "init"
@@ -31401,14 +31533,13 @@ async function handleMaintain(argv) {
31401
31533
  }
31402
31534
  await handleCursorRule({
31403
31535
  repoPath,
31404
- cursorRule: resolveCursorRuleFlag(argv.cursorRule, argv.noCursorRule),
31536
+ cursorRule: resolveCursorRuleFlag(argv.cursorRule),
31405
31537
  autoYes: argv.yes,
31406
31538
  mode: "maintain"
31407
31539
  });
31408
31540
  await handleAgentSkills({
31409
31541
  repoPath,
31410
- agents: argv.agents,
31411
- enabled: argv.noAgents ? false : void 0,
31542
+ ...resolveAgentsScaffoldOptions(argv.agents),
31412
31543
  autoYes: argv.yes,
31413
31544
  mode: "maintain"
31414
31545
  });
@@ -31417,10 +31548,13 @@ async function handleMaintain(argv) {
31417
31548
  process.exit(1);
31418
31549
  }
31419
31550
  }
31420
- function resolveCursorRuleFlag(cursorRule, noCursorRule) {
31421
- if (noCursorRule) return false;
31422
- if (cursorRule) return true;
31423
- return void 0;
31551
+ function resolveCursorRuleFlag(cursorRule) {
31552
+ return cursorRule;
31553
+ }
31554
+ function resolveAgentsScaffoldOptions(agents) {
31555
+ if (agents === false) return { enabled: false };
31556
+ if (typeof agents === "string") return { agents };
31557
+ return {};
31424
31558
  }
31425
31559
  function emitManualAdaptationPrompt(repoPath, mode, profile = "default", bundleReport) {
31426
31560
  const prompt = mode === "init" ? buildInitAdaptationPrompt(repoPath, profile) : buildMaintainAdaptationPrompt(repoPath, bundleReport);
@@ -40163,18 +40297,20 @@ function printSignals() {
40163
40297
  async function handleStatus3(argv) {
40164
40298
  const preference = readTelemetryPreference();
40165
40299
  const enabled = isTelemetryEnabled();
40300
+ const signals = getTelemetrySignals();
40166
40301
  const apiUrl = getControlApiUrl();
40167
40302
  const reachable = enabled ? await isControlApiReachable(apiUrl) : false;
40168
40303
  const payload = {
40169
40304
  enabled,
40170
40305
  preferenceEnabled: preference.enabled,
40306
+ signals,
40171
40307
  preferencePath: getTelemetryPreferencePath(),
40172
40308
  updatedAt: preference.updatedAt ?? null,
40173
40309
  envOverride: process.env.HAR_TELEMETRY ?? null,
40174
40310
  controlApiUrl: apiUrl,
40175
40311
  controlReachable: reachable,
40176
40312
  otelEndpoint: `${apiUrl.replace(/\/$/, "")}/api/otel`,
40177
- signals: [...TELEMETRY_SIGNALS]
40313
+ signalDescriptions: [...TELEMETRY_SIGNALS]
40178
40314
  };
40179
40315
  if (argv.json) {
40180
40316
  process.stdout.write(`${JSON.stringify(payload, null, 2)}
@@ -40184,21 +40320,33 @@ async function handleStatus3(argv) {
40184
40320
  header("har telemetry status");
40185
40321
  info(`Enabled: ${enabled ? "yes" : "no"}${process.env.HAR_TELEMETRY ? " (HAR_TELEMETRY override)" : ""}`);
40186
40322
  info(`Preference: ${getTelemetryPreferencePath()}${preference.updatedAt ? ` (updated ${preference.updatedAt})` : " (default on)"}`);
40323
+ info(
40324
+ `Signals: metrics=${signals.metrics} logs=${signals.logs} prompts=${signals.prompts} traces=${signals.traces}`
40325
+ );
40187
40326
  info(`Mission Control: ${apiUrl} (${reachable ? "reachable" : "not reachable"})`);
40188
40327
  info(`OTLP endpoint: ${payload.otelEndpoint}`);
40189
40328
  printSignals();
40190
40329
  }
40191
- async function handleOn() {
40330
+ async function handleOn(argv) {
40192
40331
  header("har telemetry on");
40193
- writeTelemetryPreference(true);
40332
+ const preference = writeTelemetryPreference(true, {
40333
+ prompts: argv.prompts === true ? true : void 0,
40334
+ traces: argv.traces === true ? true : void 0
40335
+ });
40194
40336
  success("Telemetry enabled (opt-out). Agent usage will be stored in local Mission Control.");
40337
+ info(
40338
+ `Signals: metrics=${preference.signals.metrics} logs=${preference.signals.logs} prompts=${preference.signals.prompts} traces=${preference.signals.traces}`
40339
+ );
40340
+ if (preference.signals.prompts) {
40341
+ warn("Prompt/response text will leave the agent machine for local Mission Control storage.");
40342
+ }
40195
40343
  printSignals();
40196
40344
  const result = await ensureTelemetryInfrastructure({ startIfNeeded: true });
40197
40345
  if (result.message) success(result.message);
40198
40346
  if (result.warning) warn(result.warning);
40199
40347
  if (result.otelReady) {
40200
40348
  info(`OTLP ingest: ${result.apiUrl.replace(/\/$/, "")}/api/otel`);
40201
- info("Usage appears under Mission Control \u2192 Worktrees. Disable: har telemetry off");
40349
+ info("Usage appears under Mission Control \u2192 Worktrees / Usage. Disable: har telemetry off");
40202
40350
  }
40203
40351
  }
40204
40352
  async function handleOff() {
@@ -40308,10 +40456,20 @@ var telemetryCommand = {
40308
40456
  ).command(
40309
40457
  "on",
40310
40458
  "Enable telemetry (default) and ensure Mission Control is running",
40311
- () => {
40312
- },
40313
- () => {
40314
- void handleOn();
40459
+ (y2) => y2.option("prompts", {
40460
+ type: "boolean",
40461
+ default: false,
40462
+ describe: "Opt in to shipping user/assistant prompt text to Mission Control"
40463
+ }).option("traces", {
40464
+ type: "boolean",
40465
+ default: false,
40466
+ describe: "Opt in to thin OTEL traces ingest (Claude beta)"
40467
+ }),
40468
+ (argv) => {
40469
+ void handleOn({
40470
+ prompts: argv.prompts,
40471
+ traces: argv.traces
40472
+ });
40315
40473
  }
40316
40474
  ).command(
40317
40475
  "off",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "LLM-powered CLI for reproducible agent development environments",
5
5
  "keywords": [
6
6
  "har",