@osfactory/har 0.64.0 → 0.64.2

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 +704 -504
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -593,8 +593,8 @@ var init_parseUtil = __esm({
593
593
  init_errors();
594
594
  init_en();
595
595
  makeIssue = (params) => {
596
- const { data, path: path70, errorMaps, issueData } = params;
597
- const fullPath = [...path70, ...issueData.path || []];
596
+ const { data, path: path69, errorMaps, issueData } = params;
597
+ const fullPath = [...path69, ...issueData.path || []];
598
598
  const fullIssue = {
599
599
  ...issueData,
600
600
  path: fullPath
@@ -902,11 +902,11 @@ var init_types = __esm({
902
902
  init_parseUtil();
903
903
  init_util();
904
904
  ParseInputLazyPath = class {
905
- constructor(parent, value, path70, key) {
905
+ constructor(parent, value, path69, key) {
906
906
  this._cachedPath = [];
907
907
  this.parent = parent;
908
908
  this.data = value;
909
- this._path = path70;
909
+ this._path = path69;
910
910
  this._key = key;
911
911
  }
912
912
  get path() {
@@ -4288,7 +4288,7 @@ var init_zod = __esm({
4288
4288
  });
4289
4289
 
4290
4290
  // packages/schemas/src/schema.ts
4291
- var HAR_STAGE_KINDS, HAR_AGENT_SLOT_MIN, AgentSkillTargetSchema, ScaffoldedAgentFileSchema, HarnessManifestSchema, HarnessStageKindSchema, HarnessArtifactKindSchema, HarnessArtifactSchema, HarnessStageIdSchema, HarnessStageSchema, HarnessAgentSlotsSchema, CommitGateConfigSchema, OnboardingPreferencesSchema, HarnessStageRegistrySchema, HarnessVerificationStepSchema, ShellRunOutputSchema, HarnessVerificationResultSchema, HarnessStageRunStatusSchema, HarnessStageLogSchema, HarnessStageUrlSchema, HarnessStageRunResultSchema, StageKindSchema, VerificationResultSchema, StageResultSchema, RunRecordTriggerSchema, WorkUnitIdSchema, WorkAttemptIdSchema, WorkUnitRelatedLinkSchema, WorkUnitMetadataSchema, WorkUnitOutcomeSchema, WorkUnitRecordSchema, WorkAttemptRecordSchema, RunRecordSchema, SlotRegistryEntrySchema, AgentSlotHarnessUsageSchema, PreflightBlockerSchema, SlotReadinessSchema, AgentSlotStatusSchema, EnvironmentStatusSchema, RegisterRepoInputSchema, UnregisterRepoInputSchema, UnregisterWorktreeResultSchema, UnregisterRepoResultSchema, ResetMissionControlInputSchema, HarnessScrubResultSchema, ResetMissionControlResultSchema, DeleteWorktreesInputSchema, DeleteWorktreeResultSchema, DeleteWorktreesResultSchema, SyncRunsInputSchema, SyncSlotsInputSchema, SyncWorkUnitsInputSchema, ChangedFileStatusSchema, ChangedFileSchema, ValidationRecordSchema, SyncValidationsInputSchema, ValidationBindingRecordSchema, SyncValidationBindingsInputSchema, AgentToolSchema, UsageSourceSchema, AgentTrajectorySourceSchema, AgentTrajectoryContentDisclosureSchema, AgentTrajectoryRecordV1Schema, AgentTrajectoryRecordSchema, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
4291
+ var HAR_STAGE_KINDS, HAR_AGENT_SLOT_MIN, AgentSkillTargetSchema, ScaffoldedAgentFileSchema, HarnessManifestSchema, HarnessStageKindSchema, HarnessArtifactKindSchema, HarnessArtifactSchema, HarnessStageIdSchema, HarnessStageSchema, HarnessAgentSlotsSchema, CommitGateConfigSchema, OnboardingPreferencesSchema, HarnessStageRegistrySchema, HarnessVerificationStepSchema, ShellRunOutputSchema, HarnessVerificationResultSchema, HarnessStageRunStatusSchema, HarnessStageLogSchema, HarnessStageUrlSchema, HarnessStageRunResultSchema, StageKindSchema, VerificationResultSchema, StageResultSchema, RunRecordTriggerSchema, WorkUnitIdSchema, WorkAttemptIdSchema, WorkUnitRelatedLinkSchema, WorkUnitMetadataSchema, WorkUnitOutcomeSchema, WorkUnitRecordSchema, WorkAttemptRecordSchema, RunRecordSchema, SlotRegistryEntrySchema, AgentSlotHarnessUsageSchema, PreflightBlockerSchema, SlotReadinessSchema, AgentSlotStatusSchema, EnvironmentStatusSchema, RegisterRepoInputSchema, UnregisterRepoInputSchema, UnregisterWorktreeResultSchema, UnregisterRepoResultSchema, ResetMissionControlInputSchema, HarnessScrubResultSchema, ResetMissionControlResultSchema, DeleteWorktreesInputSchema, DeleteWorktreeResultSchema, DeleteWorktreesResultSchema, SyncRunsInputSchema, SyncSlotsInputSchema, SyncWorkUnitsInputSchema, ChangedFileStatusSchema, ChangedFileSchema, ValidationRecordSchema, SyncValidationsInputSchema, ValidationBindingRecordSchema, SyncValidationBindingsInputSchema, AgentToolSchema, UsageSourceSchema, AgentTrajectorySourceSchema, AgentTrajectoryContentDisclosureSchema, AgentTrajectoryRecordV1Schema, AgentTrajectoryRecordSchema, USAGE_HARVEST_VERSION, PRE_DEDUPE_HARVEST_VERSION, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
4292
4292
  var init_schema = __esm({
4293
4293
  "packages/schemas/src/schema.ts"() {
4294
4294
  "use strict";
@@ -4774,6 +4774,8 @@ var init_schema = __esm({
4774
4774
  attemptId: WorkAttemptIdSchema.optional()
4775
4775
  }).passthrough();
4776
4776
  AgentTrajectoryRecordSchema = AgentTrajectoryRecordV1Schema;
4777
+ USAGE_HARVEST_VERSION = 1;
4778
+ PRE_DEDUPE_HARVEST_VERSION = 0;
4777
4779
  AgentSessionUsageSchema = external_exports.object({
4778
4780
  sessionKey: external_exports.string().min(1),
4779
4781
  agentId: external_exports.number().int().min(HAR_AGENT_SLOT_MIN),
@@ -4792,6 +4794,7 @@ var init_schema = __esm({
4792
4794
  costUsd: external_exports.number().nonnegative().nullable().optional(),
4793
4795
  modelBreakdown: external_exports.record(external_exports.unknown()).optional(),
4794
4796
  sources: external_exports.array(UsageSourceSchema).default([]),
4797
+ harvestVersion: external_exports.number().int().nonnegative().default(PRE_DEDUPE_HARVEST_VERSION),
4795
4798
  firstSeenAt: external_exports.string(),
4796
4799
  lastSeenAt: external_exports.string()
4797
4800
  });
@@ -4819,6 +4822,31 @@ var init_schema = __esm({
4819
4822
  }
4820
4823
  });
4821
4824
 
4825
+ // packages/schemas/src/usage-authority.ts
4826
+ function usageHarvestVersion(row) {
4827
+ const version2 = Number(row?.harvestVersion ?? PRE_DEDUPE_HARVEST_VERSION);
4828
+ return Number.isFinite(version2) && version2 > 0 ? Math.floor(version2) : PRE_DEDUPE_HARVEST_VERSION;
4829
+ }
4830
+ function includesSource(row, source) {
4831
+ return (row?.sources ?? []).includes(source);
4832
+ }
4833
+ function harvestSupersedes(existing, incoming) {
4834
+ if (!existing || !incoming) return false;
4835
+ if (includesSource(existing, "otel") || includesSource(incoming, "otel")) return false;
4836
+ return usageHarvestVersion(incoming) > usageHarvestVersion(existing);
4837
+ }
4838
+ function mergedHarvestVersion(existing, incoming) {
4839
+ if (!includesSource(existing, "harvest")) return usageHarvestVersion(incoming);
4840
+ if (!includesSource(incoming, "harvest")) return usageHarvestVersion(existing);
4841
+ return Math.min(usageHarvestVersion(existing), usageHarvestVersion(incoming));
4842
+ }
4843
+ var init_usage_authority = __esm({
4844
+ "packages/schemas/src/usage-authority.ts"() {
4845
+ "use strict";
4846
+ init_schema();
4847
+ }
4848
+ });
4849
+
4822
4850
  // node_modules/@pydantic/genai-prices/dist/index.js
4823
4851
  function h() {
4824
4852
  return U;
@@ -28294,6 +28322,7 @@ var init_schema2 = __esm({
28294
28322
  "src/harness/schema.ts"() {
28295
28323
  "use strict";
28296
28324
  init_schema();
28325
+ init_usage_authority();
28297
28326
  init_usage_pricing();
28298
28327
  }
28299
28328
  });
@@ -28704,7 +28733,7 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
28704
28733
  const stream = options.stream ?? false;
28705
28734
  const echoStdout = stream && (options.streamStdout ?? true);
28706
28735
  const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
28707
- return new Promise((resolve53) => {
28736
+ return new Promise((resolve52) => {
28708
28737
  const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
28709
28738
  ...spawnOptions,
28710
28739
  stdio: ["inherit", "pipe", "pipe"]
@@ -28719,14 +28748,14 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
28719
28748
  stderr += d;
28720
28749
  if (stream) process.stderr.write(d);
28721
28750
  });
28722
- proc.on("close", (code) => resolve53({ stdout, stderr, code: code ?? 0 }));
28751
+ proc.on("close", (code) => resolve52({ stdout, stderr, code: code ?? 0 }));
28723
28752
  });
28724
28753
  }
28725
28754
  function runShellCommand(command2, options = {}) {
28726
28755
  const stream = options.stream ?? false;
28727
28756
  const echoStdout = stream && (options.streamStdout ?? true);
28728
28757
  const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
28729
- return new Promise((resolve53) => {
28758
+ return new Promise((resolve52) => {
28730
28759
  const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
28731
28760
  ...spawnOptions,
28732
28761
  stdio: ["inherit", "pipe", "pipe"]
@@ -28741,7 +28770,7 @@ function runShellCommand(command2, options = {}) {
28741
28770
  stderr += d;
28742
28771
  if (stream) process.stderr.write(d);
28743
28772
  });
28744
- proc.on("close", (code) => resolve53({ stdout, stderr, code: code ?? 0 }));
28773
+ proc.on("close", (code) => resolve52({ stdout, stderr, code: code ?? 0 }));
28745
28774
  });
28746
28775
  }
28747
28776
  var import_child_process;
@@ -31541,17 +31570,17 @@ function listWorkUnits(harnessRoot) {
31541
31570
  ).sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt));
31542
31571
  }
31543
31572
  function createWorkAttempt(harnessRoot, input) {
31544
- const attempt = WorkAttemptRecordSchema.parse({
31573
+ const attempt2 = WorkAttemptRecordSchema.parse({
31545
31574
  ...input,
31546
31575
  version: 1,
31547
31576
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
31548
31577
  });
31549
31578
  ensureWorkEvidenceIgnored(harnessRoot);
31550
31579
  writeRecord2(
31551
- hashedRecordPath(harnessRoot, WORK_ATTEMPTS_DIR, attempt.attemptId),
31552
- attempt
31580
+ hashedRecordPath(harnessRoot, WORK_ATTEMPTS_DIR, attempt2.attemptId),
31581
+ attempt2
31553
31582
  );
31554
- return attempt;
31583
+ return attempt2;
31555
31584
  }
31556
31585
  function listWorkAttempts(harnessRoot) {
31557
31586
  return listRecords(
@@ -32313,6 +32342,8 @@ function extractClaudeUsageFromRecords(records) {
32313
32342
  let tokensCacheCreation = 0;
32314
32343
  let costUsd = null;
32315
32344
  const modelBreakdown = {};
32345
+ const billed = /* @__PURE__ */ new Map();
32346
+ const unkeyed = [];
32316
32347
  for (const record2 of records) {
32317
32348
  if (!record2 || typeof record2 !== "object") continue;
32318
32349
  const payload = record2;
@@ -32327,29 +32358,34 @@ function extractClaudeUsageFromRecords(records) {
32327
32358
  const message = payload.message;
32328
32359
  const nestedUsage = payload.usage ?? message?.usage;
32329
32360
  if (nestedUsage && payload.type !== "result") {
32330
- const i = Number(nestedUsage.input_tokens ?? 0);
32331
- const o = Number(nestedUsage.output_tokens ?? 0);
32332
- const cr = Number(nestedUsage.cache_read_input_tokens ?? 0);
32333
- const cc = Number(nestedUsage.cache_creation_input_tokens ?? 0);
32334
- tokensInput += i;
32335
- tokensOutput += o;
32336
- tokensCacheRead += cr;
32337
- tokensCacheCreation += cc;
32338
32361
  const model = typeof message?.model === "string" ? message.model : void 0;
32339
- if (model && model !== "<synthetic>") {
32340
- const totals = modelBreakdown[model] ??= {
32341
- tokensInput: 0,
32342
- tokensOutput: 0,
32343
- tokensCacheRead: 0,
32344
- tokensCacheCreation: 0,
32345
- tokensTotal: 0
32346
- };
32347
- totals.tokensInput += i;
32348
- totals.tokensOutput += o;
32349
- totals.tokensCacheRead += cr;
32350
- totals.tokensCacheCreation += cc;
32351
- totals.tokensTotal += i + o + cr + cc;
32352
- }
32362
+ const entry = { usage: nestedUsage, model };
32363
+ if (typeof message?.id === "string" && message.id) billed.set(message.id, entry);
32364
+ else unkeyed.push(entry);
32365
+ }
32366
+ }
32367
+ for (const { usage: usage2, model } of [...billed.values(), ...unkeyed]) {
32368
+ const i = Number(usage2.input_tokens ?? 0);
32369
+ const o = Number(usage2.output_tokens ?? 0);
32370
+ const cr = Number(usage2.cache_read_input_tokens ?? 0);
32371
+ const cc = Number(usage2.cache_creation_input_tokens ?? 0);
32372
+ tokensInput += i;
32373
+ tokensOutput += o;
32374
+ tokensCacheRead += cr;
32375
+ tokensCacheCreation += cc;
32376
+ if (model && model !== "<synthetic>") {
32377
+ const totals = modelBreakdown[model] ??= {
32378
+ tokensInput: 0,
32379
+ tokensOutput: 0,
32380
+ tokensCacheRead: 0,
32381
+ tokensCacheCreation: 0,
32382
+ tokensTotal: 0
32383
+ };
32384
+ totals.tokensInput += i;
32385
+ totals.tokensOutput += o;
32386
+ totals.tokensCacheRead += cr;
32387
+ totals.tokensCacheCreation += cc;
32388
+ totals.tokensTotal += i + o + cr + cc;
32353
32389
  }
32354
32390
  }
32355
32391
  return { tokensInput, tokensOutput, tokensCacheRead, tokensCacheCreation, costUsd, modelBreakdown };
@@ -32388,8 +32424,9 @@ function findMatchingClaudeTranscripts(slot) {
32388
32424
  }
32389
32425
  }
32390
32426
  }
32391
- if (primaryHit) primary.push({ filePath, records, mtimeMs: stat.mtimeMs });
32392
- else if (fallbackHit) fallback.push({ filePath, records, mtimeMs: stat.mtimeMs });
32427
+ if (primaryHit) primary.push({ filePath, records, mtimeMs: stat.mtimeMs, primary: true });
32428
+ else if (fallbackHit)
32429
+ fallback.push({ filePath, records, mtimeMs: stat.mtimeMs, primary: false });
32393
32430
  }
32394
32431
  }
32395
32432
  primary.sort((a, b2) => b2.mtimeMs - a.mtimeMs);
@@ -32446,18 +32483,14 @@ function harvestClaudeUsage(slot) {
32446
32483
  suffix: slot.suffix,
32447
32484
  createdAt: slot.sessionCreatedAt
32448
32485
  });
32449
- let best = null;
32450
- for (const match of matches) {
32451
- const usage2 = extractClaudeUsageFromRecords(match.records);
32452
- if (usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead === 0 && (usage2.costUsd == null || usage2.costUsd === 0)) {
32453
- continue;
32454
- }
32455
- best = usage2;
32456
- break;
32486
+ const own = matches.filter((match) => match.primary);
32487
+ const usable = own.length > 0 ? own : matches;
32488
+ const usage2 = extractClaudeUsageFromRecords(usable.flatMap((match) => match.records));
32489
+ if (usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead === 0 && (usage2.costUsd == null || usage2.costUsd === 0)) {
32490
+ return null;
32457
32491
  }
32458
- if (!best) return null;
32459
32492
  const now = (/* @__PURE__ */ new Date()).toISOString();
32460
- const tokensTotal = best.tokensInput + best.tokensOutput + best.tokensCacheRead + best.tokensCacheCreation;
32493
+ const tokensTotal = usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead + usage2.tokensCacheCreation;
32461
32494
  return {
32462
32495
  sessionKey,
32463
32496
  agentId: slot.agentId,
@@ -32465,14 +32498,15 @@ function harvestClaudeUsage(slot) {
32465
32498
  workDir: slot.workDir,
32466
32499
  branch: slot.branch,
32467
32500
  suffix: slot.suffix,
32468
- tokensInput: best.tokensInput,
32469
- tokensOutput: best.tokensOutput,
32470
- tokensCacheRead: best.tokensCacheRead,
32471
- tokensCacheCreation: best.tokensCacheCreation,
32501
+ tokensInput: usage2.tokensInput,
32502
+ tokensOutput: usage2.tokensOutput,
32503
+ tokensCacheRead: usage2.tokensCacheRead,
32504
+ tokensCacheCreation: usage2.tokensCacheCreation,
32472
32505
  tokensTotal,
32473
- costUsd: best.costUsd,
32474
- ...Object.keys(best.modelBreakdown).length > 0 ? { modelBreakdown: best.modelBreakdown } : {},
32506
+ costUsd: usage2.costUsd,
32507
+ ...Object.keys(usage2.modelBreakdown).length > 0 ? { modelBreakdown: usage2.modelBreakdown } : {},
32475
32508
  sources: ["harvest"],
32509
+ harvestVersion: USAGE_HARVEST_VERSION,
32476
32510
  firstSeenAt: slot.sessionCreatedAt ?? now,
32477
32511
  lastSeenAt: now
32478
32512
  };
@@ -32496,6 +32530,7 @@ var init_claude = __esm({
32496
32530
  fs23 = __toESM(require("fs"));
32497
32531
  os11 = __toESM(require("os"));
32498
32532
  path25 = __toESM(require("path"));
32533
+ init_schema2();
32499
32534
  init_telemetry_config();
32500
32535
  init_telemetry_env();
32501
32536
  init_workspace_path_match();
@@ -32614,6 +32649,7 @@ function harvestCodexUsage(slot) {
32614
32649
  tokensTotal,
32615
32650
  costUsd: null,
32616
32651
  sources: ["harvest"],
32652
+ harvestVersion: USAGE_HARVEST_VERSION,
32617
32653
  firstSeenAt: slot.sessionCreatedAt ?? now,
32618
32654
  lastSeenAt: now
32619
32655
  };
@@ -32625,6 +32661,7 @@ var init_codex = __esm({
32625
32661
  fs24 = __toESM(require("fs"));
32626
32662
  os12 = __toESM(require("os"));
32627
32663
  path26 = __toESM(require("path"));
32664
+ init_schema2();
32628
32665
  init_telemetry_env();
32629
32666
  init_workspace_path_match();
32630
32667
  }
@@ -32754,25 +32791,85 @@ var init_portal_watermark = __esm({
32754
32791
  }
32755
32792
  });
32756
32793
 
32757
- // src/core/control-persisted-usage.ts
32758
- async function getJson(url) {
32794
+ // src/core/control-api-read.ts
32795
+ function numberFromEnv(name, fallback) {
32796
+ const raw = Number(process.env[name]);
32797
+ return Number.isFinite(raw) && raw > 0 ? raw : fallback;
32798
+ }
32799
+ async function attempt(url) {
32759
32800
  try {
32760
32801
  const response = await fetch(url, {
32761
32802
  method: "GET",
32762
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
32803
+ signal: AbortSignal.timeout(numberFromEnv("HAR_CONTROL_READ_TIMEOUT_MS", DEFAULT_TIMEOUT_MS))
32763
32804
  });
32764
- if (!response.ok) return null;
32765
- return await response.json();
32766
- } catch {
32767
- return null;
32768
- }
32805
+ if (!response.ok) {
32806
+ return {
32807
+ read: { ok: false, error: `HTTP ${response.status}` },
32808
+ retryable: response.status >= 500
32809
+ };
32810
+ }
32811
+ return { read: { ok: true, data: await response.json() }, retryable: false };
32812
+ } catch (err) {
32813
+ return {
32814
+ read: { ok: false, error: err instanceof Error ? err.message : String(err) },
32815
+ retryable: true
32816
+ };
32817
+ }
32818
+ }
32819
+ async function readControlJson(url) {
32820
+ const first = await attempt(url);
32821
+ if (first.read.ok || !first.retryable) return first.read;
32822
+ await new Promise((resolve52) => setTimeout(resolve52, RETRY_DELAY_MS));
32823
+ return (await attempt(url)).read;
32824
+ }
32825
+ async function readControlPages(options) {
32826
+ const limit = numberFromEnv("HAR_CONTROL_READ_PAGE_SIZE", DEFAULT_PAGE_SIZE);
32827
+ const collected = [];
32828
+ let since = options.since;
32829
+ let sinceId = null;
32830
+ for (let page = 0; page < MAX_PAGES; page++) {
32831
+ const query = new URLSearchParams({ limit: String(limit) });
32832
+ if (since) query.set("since", since);
32833
+ if (sinceId) query.set("sinceId", sinceId);
32834
+ const read = await readControlJson(`${options.url}?${query.toString()}`);
32835
+ if (!read.ok) return { ok: false, error: read.error };
32836
+ const rows = options.rows(read.data);
32837
+ collected.push(...rows);
32838
+ if (rows.length < limit) return { ok: true, rows: collected, truncated: false };
32839
+ const last = options.cursor(rows[rows.length - 1]);
32840
+ const nextSince = last.createdAt ?? null;
32841
+ const nextSinceId = last.id ?? null;
32842
+ if (!nextSince || nextSince === since && nextSinceId === sinceId) {
32843
+ return { ok: true, rows: collected, truncated: false };
32844
+ }
32845
+ since = nextSince;
32846
+ sinceId = nextSinceId;
32847
+ }
32848
+ return { ok: true, rows: collected, truncated: true };
32769
32849
  }
32770
32850
  async function resolveControlRepoId(apiUrl, repoPath) {
32771
- const repos = await getJson(`${apiUrl}/api/repos`);
32772
- if (!Array.isArray(repos)) return null;
32851
+ const repos = await readControlJson(`${apiUrl}/api/repos`);
32852
+ if (!repos.ok) return repos;
32853
+ if (!Array.isArray(repos.data)) return { ok: false, error: "unexpected /api/repos payload" };
32773
32854
  const target = path28.resolve(repoPath);
32774
- return repos.find((repo) => path28.resolve(repo.path) === target)?.id ?? null;
32855
+ return {
32856
+ ok: true,
32857
+ data: repos.data.find((repo) => path28.resolve(repo.path) === target)?.id ?? null
32858
+ };
32775
32859
  }
32860
+ var path28, DEFAULT_TIMEOUT_MS, RETRY_DELAY_MS, DEFAULT_PAGE_SIZE, MAX_PAGES;
32861
+ var init_control_api_read = __esm({
32862
+ "src/core/control-api-read.ts"() {
32863
+ "use strict";
32864
+ path28 = __toESM(require("path"));
32865
+ DEFAULT_TIMEOUT_MS = 1e4;
32866
+ RETRY_DELAY_MS = 250;
32867
+ DEFAULT_PAGE_SIZE = 1e3;
32868
+ MAX_PAGES = 20;
32869
+ }
32870
+ });
32871
+
32872
+ // src/core/control-persisted-usage.ts
32776
32873
  function optionalString(value) {
32777
32874
  return value == null ? void 0 : value;
32778
32875
  }
@@ -32798,6 +32895,7 @@ function normalizeUsage(row) {
32798
32895
  costUsd: row.costUsd == null ? null : Number(row.costUsd),
32799
32896
  ...row.modelBreakdown ? { modelBreakdown: row.modelBreakdown } : {},
32800
32897
  sources: toSources(row.sources),
32898
+ harvestVersion: Number(row.harvestVersion ?? 0),
32801
32899
  firstSeenAt: row.firstSeenAt,
32802
32900
  lastSeenAt: row.lastSeenAt
32803
32901
  };
@@ -32825,50 +32923,54 @@ function maxTimestamp(a, b2) {
32825
32923
  return a > b2 ? a : b2;
32826
32924
  }
32827
32925
  async function fetchPersistedPortalTelemetry(repoPath, apiUrl, options) {
32828
- const repoId = await resolveControlRepoId(apiUrl, repoPath);
32829
- if (!repoId) return { usage: [], events: [], maxSyncedAt: null };
32926
+ const empty = { usage: [], events: [], maxSyncedAt: null, failures: [], truncated: [] };
32927
+ const repo = await resolveControlRepoId(apiUrl, repoPath);
32928
+ if (!repo.ok) {
32929
+ return { ...empty, failures: [{ channel: "repos", reason: repo.error }] };
32930
+ }
32931
+ if (!repo.data) return empty;
32830
32932
  const since = options?.since ?? null;
32831
- const [usageResponse, eventsResponse] = await Promise.all([
32832
- getJson(`${apiUrl}/api/repos/${repoId}/usage`),
32833
- getJson(`${apiUrl}/api/repos/${repoId}/events`)
32933
+ const [usageRead, eventsRead] = await Promise.all([
32934
+ readControlJson(`${apiUrl}/api/repos/${repo.data}/usage`),
32935
+ readControlPages({
32936
+ url: `${apiUrl}/api/repos/${repo.data}/events`,
32937
+ since,
32938
+ rows: (data) => data?.events ?? [],
32939
+ cursor: (row) => ({ createdAt: row.createdAt, id: row.id })
32940
+ })
32834
32941
  ]);
32835
- const usage2 = selectSince(usageResponse?.usage ?? [], since, (row) => row.updatedAt ?? row.lastSeenAt);
32836
- const events = selectSince(eventsResponse?.events ?? [], since, (row) => row.createdAt ?? row.timestamp);
32942
+ const failures = [];
32943
+ const truncated = [];
32944
+ if (!usageRead.ok) failures.push({ channel: "usage", reason: usageRead.error });
32945
+ if (!eventsRead.ok) failures.push({ channel: "events", reason: eventsRead.error });
32946
+ else if (eventsRead.truncated) truncated.push("events");
32947
+ const usage2 = selectSince(
32948
+ usageRead.ok ? usageRead.data?.usage ?? [] : [],
32949
+ since,
32950
+ (row) => row.updatedAt ?? row.lastSeenAt
32951
+ );
32952
+ const events = selectSince(
32953
+ eventsRead.ok ? eventsRead.rows : [],
32954
+ since,
32955
+ (row) => row.createdAt ?? row.timestamp
32956
+ );
32837
32957
  return {
32838
32958
  usage: usage2.selected.map(normalizeUsage),
32839
32959
  events: events.selected.map(normalizeEvent),
32840
- maxSyncedAt: maxTimestamp(usage2.maxSyncedAt, events.maxSyncedAt)
32960
+ maxSyncedAt: maxTimestamp(usage2.maxSyncedAt, events.maxSyncedAt),
32961
+ failures,
32962
+ truncated
32841
32963
  };
32842
32964
  }
32843
- var path28, FETCH_TIMEOUT_MS;
32844
32965
  var init_control_persisted_usage = __esm({
32845
32966
  "src/core/control-persisted-usage.ts"() {
32846
32967
  "use strict";
32847
- path28 = __toESM(require("path"));
32848
32968
  init_portal_watermark();
32849
- FETCH_TIMEOUT_MS = 3e3;
32969
+ init_control_api_read();
32850
32970
  }
32851
32971
  });
32852
32972
 
32853
32973
  // src/core/control-persisted-trajectory.ts
32854
- async function getJson2(url) {
32855
- try {
32856
- const response = await fetch(url, {
32857
- method: "GET",
32858
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
32859
- });
32860
- if (!response.ok) return null;
32861
- return await response.json();
32862
- } catch {
32863
- return null;
32864
- }
32865
- }
32866
- async function resolveControlRepoId2(apiUrl, repoPath) {
32867
- const repos = await getJson2(`${apiUrl}/api/repos`);
32868
- if (!Array.isArray(repos)) return null;
32869
- const target = path29.resolve(repoPath);
32870
- return repos.find((repo) => path29.resolve(repo.path) === target)?.id ?? null;
32871
- }
32872
32974
  function optional(value) {
32873
32975
  return value == null ? void 0 : value;
32874
32976
  }
@@ -32924,24 +33026,44 @@ async function fetchPersistedTrajectory(repoPath, apiUrl, request) {
32924
33026
  records: [],
32925
33027
  spans: [],
32926
33028
  recordsMaxSyncedAt: null,
32927
- spansMaxSyncedAt: null
33029
+ spansMaxSyncedAt: null,
33030
+ failures: [],
33031
+ truncated: []
32928
33032
  };
32929
33033
  if (!request.records && !request.spans) return empty;
32930
- const repoId = await resolveControlRepoId2(apiUrl, repoPath);
32931
- if (!repoId) return empty;
32932
- const [trajectoryResponse, spansResponse] = await Promise.all([
32933
- request.records ? getJson2(
32934
- `${apiUrl}/api/repos/${repoId}/trajectory`
32935
- ) : null,
32936
- request.spans ? getJson2(`${apiUrl}/api/repos/${repoId}/spans`) : null
33034
+ const repo = await resolveControlRepoId(apiUrl, repoPath);
33035
+ if (!repo.ok) return { ...empty, failures: [{ channel: "repos", reason: repo.error }] };
33036
+ if (!repo.data) return empty;
33037
+ const [trajectoryRead, spansRead] = await Promise.all([
33038
+ request.records ? readControlPages({
33039
+ url: `${apiUrl}/api/repos/${repo.data}/trajectory`,
33040
+ since: request.records.since,
33041
+ rows: (data) => data?.records ?? [],
33042
+ cursor: (row) => ({ createdAt: row.createdAt, id: row.id })
33043
+ }) : null,
33044
+ request.spans ? readControlPages({
33045
+ url: `${apiUrl}/api/repos/${repo.data}/spans`,
33046
+ since: request.spans.since,
33047
+ rows: (data) => data?.spans ?? [],
33048
+ cursor: (row) => ({ createdAt: row.createdAt, id: row.id })
33049
+ }) : null
32937
33050
  ]);
33051
+ const failures = [];
33052
+ const truncated = [];
33053
+ if (trajectoryRead && !trajectoryRead.ok) {
33054
+ failures.push({ channel: "trajectory", reason: trajectoryRead.error });
33055
+ } else if (trajectoryRead?.ok && trajectoryRead.truncated) {
33056
+ truncated.push("trajectory");
33057
+ }
33058
+ if (spansRead && !spansRead.ok) failures.push({ channel: "spans", reason: spansRead.error });
33059
+ else if (spansRead?.ok && spansRead.truncated) truncated.push("spans");
32938
33060
  const trajectory = selectSince(
32939
- trajectoryResponse?.records ?? [],
33061
+ trajectoryRead?.ok ? trajectoryRead.rows : [],
32940
33062
  request.records ? request.records.since : null,
32941
33063
  (row) => row.createdAt ?? null
32942
33064
  );
32943
33065
  const spans = selectSince(
32944
- spansResponse?.spans ?? [],
33066
+ spansRead?.ok ? spansRead.rows : [],
32945
33067
  request.spans ? request.spans.since : null,
32946
33068
  (row) => row.createdAt ?? null
32947
33069
  );
@@ -32952,17 +33074,17 @@ async function fetchPersistedTrajectory(repoPath, apiUrl, request) {
32952
33074
  }),
32953
33075
  spans: spans.selected.map(toPortalSpan),
32954
33076
  recordsMaxSyncedAt: trajectory.maxSyncedAt,
32955
- spansMaxSyncedAt: spans.maxSyncedAt
33077
+ spansMaxSyncedAt: spans.maxSyncedAt,
33078
+ failures,
33079
+ truncated
32956
33080
  };
32957
33081
  }
32958
- var path29, FETCH_TIMEOUT_MS2;
32959
33082
  var init_control_persisted_trajectory = __esm({
32960
33083
  "src/core/control-persisted-trajectory.ts"() {
32961
33084
  "use strict";
32962
- path29 = __toESM(require("path"));
32963
33085
  init_schema2();
32964
33086
  init_portal_watermark();
32965
- FETCH_TIMEOUT_MS2 = 5e3;
33087
+ init_control_api_read();
32966
33088
  }
32967
33089
  });
32968
33090
 
@@ -33003,10 +33125,34 @@ function mergeModelBreakdown(a, b2) {
33003
33125
  }
33004
33126
  return out;
33005
33127
  }
33006
- function mergeUsageRow(a, b2) {
33128
+ function replaceCounters(row) {
33129
+ return {
33130
+ tokensInput: num2(row.tokensInput),
33131
+ tokensOutput: num2(row.tokensOutput),
33132
+ tokensCacheRead: num2(row.tokensCacheRead),
33133
+ tokensCacheCreation: num2(row.tokensCacheCreation),
33134
+ tokensTotal: num2(row.tokensTotal),
33135
+ costUsd: row.costUsd ?? null,
33136
+ modelBreakdown: row.modelBreakdown,
33137
+ harvestVersion: usageHarvestVersion(row)
33138
+ };
33139
+ }
33140
+ function maxCounters(a, b2) {
33007
33141
  const costA = a.costUsd ?? null;
33008
33142
  const costB = b2.costUsd ?? null;
33009
- const costUsd = costA != null || costB != null ? Math.max(num2(costA), num2(costB)) : a.costUsd ?? b2.costUsd;
33143
+ return {
33144
+ tokensInput: Math.max(num2(a.tokensInput), num2(b2.tokensInput)),
33145
+ tokensOutput: Math.max(num2(a.tokensOutput), num2(b2.tokensOutput)),
33146
+ tokensCacheRead: Math.max(num2(a.tokensCacheRead), num2(b2.tokensCacheRead)),
33147
+ tokensCacheCreation: Math.max(num2(a.tokensCacheCreation), num2(b2.tokensCacheCreation)),
33148
+ tokensTotal: Math.max(num2(a.tokensTotal), num2(b2.tokensTotal)),
33149
+ costUsd: costA != null || costB != null ? Math.max(num2(costA), num2(costB)) : a.costUsd ?? b2.costUsd,
33150
+ modelBreakdown: mergeModelBreakdown(a.modelBreakdown, b2.modelBreakdown),
33151
+ harvestVersion: mergedHarvestVersion(a, b2)
33152
+ };
33153
+ }
33154
+ function mergeUsageRow(a, b2) {
33155
+ const counters = harvestSupersedes(a, b2) ? replaceCounters(b2) : harvestSupersedes(b2, a) ? replaceCounters(a) : maxCounters(a, b2);
33010
33156
  return {
33011
33157
  ...a,
33012
33158
  ...b2,
@@ -33015,13 +33161,7 @@ function mergeUsageRow(a, b2) {
33015
33161
  suffix: b2.suffix ?? a.suffix,
33016
33162
  workUnitId: b2.workUnitId ?? a.workUnitId,
33017
33163
  attemptId: b2.attemptId ?? a.attemptId,
33018
- tokensInput: Math.max(num2(a.tokensInput), num2(b2.tokensInput)),
33019
- tokensOutput: Math.max(num2(a.tokensOutput), num2(b2.tokensOutput)),
33020
- tokensCacheRead: Math.max(num2(a.tokensCacheRead), num2(b2.tokensCacheRead)),
33021
- tokensCacheCreation: Math.max(num2(a.tokensCacheCreation), num2(b2.tokensCacheCreation)),
33022
- tokensTotal: Math.max(num2(a.tokensTotal), num2(b2.tokensTotal)),
33023
- costUsd,
33024
- modelBreakdown: mergeModelBreakdown(a.modelBreakdown, b2.modelBreakdown),
33164
+ ...counters,
33025
33165
  sources: [.../* @__PURE__ */ new Set([...a.sources ?? [], ...b2.sources ?? []])],
33026
33166
  firstSeenAt: earlier(a.firstSeenAt, b2.firstSeenAt),
33027
33167
  lastSeenAt: later(a.lastSeenAt, b2.lastSeenAt)
@@ -33048,6 +33188,7 @@ var KEY_SEP;
33048
33188
  var init_portal_usage_merge = __esm({
33049
33189
  "src/core/portal-usage-merge.ts"() {
33050
33190
  "use strict";
33191
+ init_schema2();
33051
33192
  KEY_SEP = "\0";
33052
33193
  }
33053
33194
  });
@@ -33157,13 +33298,13 @@ function describeFetchFailure(url, bodyBytes, err) {
33157
33298
  }
33158
33299
  async function postForResponse(url, headers, payload) {
33159
33300
  let lastErr;
33160
- for (let attempt = 1; attempt <= MAX_FETCH_ATTEMPTS; attempt++) {
33301
+ for (let attempt2 = 1; attempt2 <= MAX_FETCH_ATTEMPTS; attempt2++) {
33161
33302
  try {
33162
33303
  return await fetch(url, { method: "POST", headers, body: payload });
33163
33304
  } catch (err) {
33164
33305
  lastErr = err;
33165
- if (attempt < MAX_FETCH_ATTEMPTS) {
33166
- await new Promise((resolve53) => setTimeout(resolve53, attempt * 100));
33306
+ if (attempt2 < MAX_FETCH_ATTEMPTS) {
33307
+ await new Promise((resolve52) => setTimeout(resolve52, attempt2 * 100));
33167
33308
  }
33168
33309
  }
33169
33310
  }
@@ -33258,8 +33399,17 @@ function modelsFromBreakdown(breakdown) {
33258
33399
  ...totals && typeof totals === "object" ? totals : {}
33259
33400
  }));
33260
33401
  }
33402
+ function describeReadFailures(repoPath, failures) {
33403
+ const detail = failures.map((f) => `${f.channel} (${f.reason})`).join(", ");
33404
+ return `${path29.basename(repoPath)}: could not read ${detail} from Mission Control \u2014 that telemetry is missing from this sync and its watermark is held, so the next sync retries it.`;
33405
+ }
33406
+ function describeTruncatedReads(repoPath, channels) {
33407
+ return `${path29.basename(repoPath)}: ${channels.join(", ")} hit the read page cap \u2014 the remainder syncs on the next run.`;
33408
+ }
33261
33409
  async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, portal) {
33262
- if (!isTelemetryEnabled()) return { usage: [], events: [], maxSyncedAt: null };
33410
+ if (!isTelemetryEnabled()) {
33411
+ return { usage: [], events: [], maxSyncedAt: null, failures: [], truncated: [] };
33412
+ }
33263
33413
  try {
33264
33414
  const userEmail = resolvePortalUserEmail(portal);
33265
33415
  const fallbackAgentId = slots.length > 0 ? Math.min(...slots.map((slot) => slot.agentId)) : null;
@@ -33318,9 +33468,23 @@ async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, por
33318
33468
  const events = dedupePortalEvents(harvestedEvents, persisted.events).map(
33319
33469
  (event) => dropNullFields({ ...event })
33320
33470
  );
33321
- return { usage: usage2, events, maxSyncedAt: persisted.maxSyncedAt };
33322
- } catch {
33323
- return { usage: [], events: [], maxSyncedAt: null };
33471
+ return {
33472
+ usage: usage2,
33473
+ events,
33474
+ maxSyncedAt: persisted.maxSyncedAt,
33475
+ failures: persisted.failures,
33476
+ truncated: persisted.truncated
33477
+ };
33478
+ } catch (err) {
33479
+ return {
33480
+ usage: [],
33481
+ events: [],
33482
+ maxSyncedAt: null,
33483
+ failures: [
33484
+ { channel: "telemetry", reason: err instanceof Error ? err.message : String(err) }
33485
+ ],
33486
+ truncated: []
33487
+ };
33324
33488
  }
33325
33489
  }
33326
33490
  async function buildPortalPayload(repoPath, controlApiUrl, since, full = false, portal) {
@@ -33334,16 +33498,16 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false,
33334
33498
  const attempts = listWorkAttempts(harnessRoot);
33335
33499
  const validationBindings = listValidationBindings(harnessRoot);
33336
33500
  const userEmail = resolvePortalUserEmail(portal);
33337
- const { usage: usage2, events, maxSyncedAt } = await collectPortalTelemetry(
33501
+ const { usage: usage2, events, maxSyncedAt, failures, truncated } = await collectPortalTelemetry(
33338
33502
  repoPath,
33339
33503
  status.slots,
33340
33504
  controlApiUrl,
33341
33505
  since,
33342
33506
  portal
33343
33507
  );
33344
- if (full && isTelemetryEnabled() && usage2.length === 0 && runs.some((r) => r.agentId != null)) {
33508
+ if (full && isTelemetryEnabled() && failures.length === 0 && usage2.length === 0 && runs.some((r) => r.agentId != null)) {
33345
33509
  warn(
33346
- `${path30.basename(repoPath)}: agent runs found but no usage harvested \u2014 attribution will be missing. This happens when agent sessions ran outside the har worktree slot (e.g. in the main checkout). Run agents inside \`har env launch\`.`
33510
+ `${path29.basename(repoPath)}: agent runs found but no usage harvested \u2014 attribution will be missing. This happens when agent sessions ran outside the har worktree slot (e.g. in the main checkout). Run agents inside \`har env launch\`.`
33347
33511
  );
33348
33512
  }
33349
33513
  const syncBody = {
@@ -33363,7 +33527,7 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false,
33363
33527
  ...usage2.length > 0 ? { usage: usage2 } : {}
33364
33528
  };
33365
33529
  const runsPayload = userEmail ? runs.map((run2) => ({ ...run2, userEmail })) : runs;
33366
- return { syncBody, runs: runsPayload, events, maxSyncedAt };
33530
+ return { syncBody, runs: runsPayload, events, maxSyncedAt, failures, truncated };
33367
33531
  }
33368
33532
  async function isControlApiReachable(apiUrl = getControlApiUrl()) {
33369
33533
  try {
@@ -33380,7 +33544,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
33380
33544
  const deadline = Date.now() + timeoutMs;
33381
33545
  while (Date.now() < deadline) {
33382
33546
  if (await isControlApiReachable(apiUrl)) return true;
33383
- await new Promise((resolve53) => setTimeout(resolve53, intervalMs));
33547
+ await new Promise((resolve52) => setTimeout(resolve52, intervalMs));
33384
33548
  }
33385
33549
  return false;
33386
33550
  }
@@ -33397,13 +33561,14 @@ async function syncReposWithControl(options) {
33397
33561
  const results = [];
33398
33562
  let synced = 0;
33399
33563
  let failed = 0;
33564
+ let incomplete = 0;
33400
33565
  for (const repoPath of options.repoPaths) {
33401
33566
  const destinationAliases = destinationAliasesForSync(repoPath, options.portalTargets);
33402
33567
  if (destinationAliases.length > 1) {
33403
33568
  const targetResults = [];
33404
33569
  for (const alias of destinationAliases) {
33405
33570
  try {
33406
- await withTimeout(
33571
+ const outcome = await withTimeout(
33407
33572
  syncRepoWithControl({
33408
33573
  repoPath,
33409
33574
  apiUrl,
@@ -33415,7 +33580,11 @@ async function syncReposWithControl(options) {
33415
33580
  EXPLICIT_SYNC_TIMEOUT_MS,
33416
33581
  "control sync"
33417
33582
  );
33418
- targetResults.push({ alias, ok: true });
33583
+ targetResults.push({
33584
+ alias,
33585
+ ok: true,
33586
+ ...outcome.warnings.length > 0 ? { warnings: outcome.warnings } : {}
33587
+ });
33419
33588
  } catch (err) {
33420
33589
  targetResults.push({
33421
33590
  alias,
@@ -33427,11 +33596,12 @@ async function syncReposWithControl(options) {
33427
33596
  const ok = targetResults.every((entry) => entry.ok);
33428
33597
  if (ok) synced++;
33429
33598
  else failed++;
33599
+ if (ok && targetResults.some((entry) => entry.warnings)) incomplete++;
33430
33600
  results.push({ repoPath, ok, targets: targetResults, error: ok ? void 0 : "one or more targets failed" });
33431
33601
  continue;
33432
33602
  }
33433
33603
  try {
33434
- await withTimeout(
33604
+ const outcome = await withTimeout(
33435
33605
  syncRepoWithControl({
33436
33606
  repoPath,
33437
33607
  apiUrl,
@@ -33444,13 +33614,18 @@ async function syncReposWithControl(options) {
33444
33614
  "control sync"
33445
33615
  );
33446
33616
  synced++;
33447
- results.push({ repoPath, ok: true });
33617
+ if (outcome.warnings.length > 0) incomplete++;
33618
+ results.push({
33619
+ repoPath,
33620
+ ok: true,
33621
+ ...outcome.warnings.length > 0 ? { warnings: outcome.warnings } : {}
33622
+ });
33448
33623
  } catch (err) {
33449
33624
  failed++;
33450
33625
  results.push({ repoPath, ok: false, error: err instanceof Error ? err.message : String(err) });
33451
33626
  }
33452
33627
  }
33453
- return { synced, failed, results };
33628
+ return { synced, failed, incomplete, results };
33454
33629
  }
33455
33630
  function destinationAliasesForSync(repoPath, explicit) {
33456
33631
  if (explicit && explicit.length > 0) return explicit;
@@ -33515,7 +33690,7 @@ async function syncRepoWithLocalControl(options) {
33515
33690
  const listResponse = await fetch(`${apiUrl}/api/repos`);
33516
33691
  if (!listResponse.ok) throw new Error("Failed to list repos from Control API");
33517
33692
  const repos = await listResponse.json();
33518
- const existing = repos.find((r) => path30.resolve(r.path) === repoPath);
33693
+ const existing = repos.find((r) => path29.resolve(r.path) === repoPath);
33519
33694
  if (!existing) {
33520
33695
  return;
33521
33696
  }
@@ -33527,7 +33702,7 @@ async function syncRepoWithLocalControl(options) {
33527
33702
  }
33528
33703
  }
33529
33704
  async function syncRepoWithPortal(options, controlApiUrl, portal) {
33530
- if (!isRepoPortalSyncEnabled(options.repoPath)) return;
33705
+ if (!isRepoPortalSyncEnabled(options.repoPath)) return [];
33531
33706
  const { repoPath, dryRun, full } = options;
33532
33707
  const watermarkKey = watermarkKeyForTarget(portal);
33533
33708
  const since = full ? null : readPortalWatermarkForTarget(repoPath, portal);
@@ -33540,7 +33715,7 @@ async function syncRepoWithPortal(options, controlApiUrl, portal) {
33540
33715
  }
33541
33716
  }
33542
33717
  const runsSince = rewindSince(stored?.lastSyncedAt ?? null);
33543
- const { syncBody, runs, events, maxSyncedAt } = await buildPortalPayload(
33718
+ const { syncBody, runs, events, maxSyncedAt, failures, truncated } = await buildPortalPayload(
33544
33719
  repoPath,
33545
33720
  controlApiUrl,
33546
33721
  since,
@@ -33563,18 +33738,25 @@ async function syncRepoWithPortal(options, controlApiUrl, portal) {
33563
33738
  for (const batch of chunkBySerializedSize(events, maxSyncBatchBytes())) {
33564
33739
  await postPortal(portal, "/api/otel", { path: repoPath, events: batch }, dryRun);
33565
33740
  }
33566
- if (!dryRun && maxSyncedAt) {
33741
+ if (!dryRun && maxSyncedAt && failures.length === 0) {
33567
33742
  writePortalWatermark(repoPath, watermarkKey, maxSyncedAt);
33568
33743
  }
33569
- await syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun, full);
33744
+ const warnings = [];
33745
+ if (failures.length > 0) warnings.push(describeReadFailures(repoPath, failures));
33746
+ if (truncated.length > 0) warnings.push(describeTruncatedReads(repoPath, truncated));
33747
+ warnings.push(
33748
+ ...await syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun, full)
33749
+ );
33750
+ for (const message of warnings) warn(message);
33751
+ return warnings;
33570
33752
  }
33571
33753
  async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun, full) {
33572
33754
  const wantRecords = isPortalTrajectoryEnabledForTarget(portal);
33573
33755
  const wantSpans = isTelemetryEnabled();
33574
- if (!wantRecords && !wantSpans) return;
33756
+ if (!wantRecords && !wantSpans) return [];
33575
33757
  const recordsTarget = trajectoryWatermarkTarget(portal);
33576
33758
  const spansTarget = spansWatermarkTarget(portal);
33577
- const { records, spans, recordsMaxSyncedAt, spansMaxSyncedAt } = await fetchPersistedTrajectory(repoPath, controlApiUrl, {
33759
+ const { records, spans, recordsMaxSyncedAt, spansMaxSyncedAt, failures, truncated } = await fetchPersistedTrajectory(repoPath, controlApiUrl, {
33578
33760
  records: wantRecords ? {
33579
33761
  since: full ? null : readScopedPortalWatermark(
33580
33762
  repoPath,
@@ -33590,10 +33772,11 @@ async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun,
33590
33772
  )
33591
33773
  } : false
33592
33774
  });
33775
+ const failedChannel = (channel) => failures.some((failure) => failure.channel === channel || failure.channel === "repos");
33593
33776
  for (const batch of chunkBySerializedSize(spans, maxSyncBatchBytes())) {
33594
33777
  await postPortal(portal, "/api/otel", { path: repoPath, spans: batch }, dryRun);
33595
33778
  }
33596
- if (!dryRun && spansMaxSyncedAt) {
33779
+ if (!dryRun && spansMaxSyncedAt && !failedChannel("spans")) {
33597
33780
  writePortalWatermark(repoPath, spansTarget, spansMaxSyncedAt);
33598
33781
  }
33599
33782
  let recordsLanded = true;
@@ -33607,14 +33790,18 @@ async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun,
33607
33790
  if (!supported) {
33608
33791
  recordsLanded = false;
33609
33792
  warn(
33610
- `${path30.basename(repoPath)}: this har-portal has no /api/trajectory endpoint \u2014 trajectory forwarding skipped (upgrade the portal; records are kept for the next sync).`
33793
+ `${path29.basename(repoPath)}: this har-portal has no /api/trajectory endpoint \u2014 trajectory forwarding skipped (upgrade the portal; records are kept for the next sync).`
33611
33794
  );
33612
33795
  break;
33613
33796
  }
33614
33797
  }
33615
- if (!dryRun && recordsLanded && recordsMaxSyncedAt) {
33798
+ if (!dryRun && recordsLanded && recordsMaxSyncedAt && !failedChannel("trajectory")) {
33616
33799
  writePortalWatermark(repoPath, recordsTarget, recordsMaxSyncedAt);
33617
33800
  }
33801
+ return [
33802
+ ...failures.length > 0 ? [describeReadFailures(repoPath, failures)] : [],
33803
+ ...truncated.length > 0 ? [describeTruncatedReads(repoPath, truncated)] : []
33804
+ ];
33618
33805
  }
33619
33806
  async function syncRepoWithControl(options) {
33620
33807
  const repoPath = canonicalizeControlRepoPath(options.repoPath);
@@ -33646,19 +33833,20 @@ async function syncRepoWithControl(options) {
33646
33833
  if (!response.ok) {
33647
33834
  throw new Error(`Cloud sync failed: ${response.status}`);
33648
33835
  }
33649
- return;
33836
+ return { warnings: [] };
33650
33837
  }
33651
33838
  await syncRepoWithLocalControl({ ...options, repoPath, apiUrl });
33652
- if (!isRepoPortalSyncEnabled(repoPath)) return;
33839
+ if (!isRepoPortalSyncEnabled(repoPath)) return { warnings: [] };
33653
33840
  const resolved = resolvePortalTargetsForRepo({
33654
33841
  repoPath,
33655
33842
  explicitTargets: options.portalTargets
33656
33843
  });
33657
- if (!resolved) return;
33844
+ if (!resolved) return { warnings: [] };
33845
+ const warnings = [];
33658
33846
  const failures = [];
33659
33847
  for (const portal of resolved.targets) {
33660
33848
  try {
33661
- await syncRepoWithPortal({ ...options, repoPath }, apiUrl, portal);
33849
+ warnings.push(...await syncRepoWithPortal({ ...options, repoPath }, apiUrl, portal));
33662
33850
  } catch (err) {
33663
33851
  failures.push({
33664
33852
  alias: portal.alias ?? portal.identityKey,
@@ -33666,7 +33854,7 @@ async function syncRepoWithControl(options) {
33666
33854
  });
33667
33855
  }
33668
33856
  }
33669
- if (failures.length === 0) return;
33857
+ if (failures.length === 0) return { warnings };
33670
33858
  if (failures.length === resolved.targets.length && failures.length === 1) {
33671
33859
  throw new Error(failures[0].error);
33672
33860
  }
@@ -33806,7 +33994,7 @@ async function syncRunWithLocalControl(repoPath, run2, apiUrl) {
33806
33994
  const listResponse = await fetch(`${apiUrl}/api/repos`);
33807
33995
  if (!listResponse.ok) return;
33808
33996
  const repos = await listResponse.json();
33809
- repoId = repos.find((r) => path30.resolve(r.path) === repoPath)?.id;
33997
+ repoId = repos.find((r) => path29.resolve(r.path) === repoPath)?.id;
33810
33998
  }
33811
33999
  if (!repoId) return;
33812
34000
  const runsBody = SyncRunsInputSchema.parse({ runs: [run2] });
@@ -33839,11 +34027,11 @@ async function syncRunWithControlAsync(repoPath, run2) {
33839
34027
  }
33840
34028
  }
33841
34029
  }
33842
- var path30, DEFAULT_MAX_BATCH_BYTES, DEFAULT_SYNC_OVERLAP_MS, MAX_FETCH_ATTEMPTS, SYNC_TIMEOUT_MS, EXPLICIT_SYNC_TIMEOUT_MS;
34030
+ var path29, DEFAULT_MAX_BATCH_BYTES, DEFAULT_SYNC_OVERLAP_MS, MAX_FETCH_ATTEMPTS, SYNC_TIMEOUT_MS, EXPLICIT_SYNC_TIMEOUT_MS;
33843
34031
  var init_control_sync = __esm({
33844
34032
  "src/core/control-sync.ts"() {
33845
34033
  "use strict";
33846
- path30 = __toESM(require("path"));
34034
+ path29 = __toESM(require("path"));
33847
34035
  init_manifest();
33848
34036
  init_stages();
33849
34037
  init_schema2();
@@ -33878,7 +34066,7 @@ var init_control_sync = __esm({
33878
34066
  // src/core/sync-context.ts
33879
34067
  function markDirty(repoPath) {
33880
34068
  if (!repoPath) return;
33881
- dirtyRepos.add(path31.resolve(repoPath));
34069
+ dirtyRepos.add(path30.resolve(repoPath));
33882
34070
  }
33883
34071
  function markAllRegisteredDirty() {
33884
34072
  syncAllRegistered = true;
@@ -33903,11 +34091,11 @@ async function syncDirtyRepos() {
33903
34091
  } catch {
33904
34092
  }
33905
34093
  }
33906
- var path31, dirtyRepos, syncAllRegistered;
34094
+ var path30, dirtyRepos, syncAllRegistered;
33907
34095
  var init_sync_context = __esm({
33908
34096
  "src/core/sync-context.ts"() {
33909
34097
  "use strict";
33910
- path31 = __toESM(require("path"));
34098
+ path30 = __toESM(require("path"));
33911
34099
  dirtyRepos = /* @__PURE__ */ new Set();
33912
34100
  syncAllRegistered = false;
33913
34101
  }
@@ -35005,15 +35193,15 @@ var require_route = __commonJS({
35005
35193
  };
35006
35194
  }
35007
35195
  function wrapConversion(toModel, graph) {
35008
- const path70 = [graph[toModel].parent, toModel];
35196
+ const path69 = [graph[toModel].parent, toModel];
35009
35197
  let fn = conversions[graph[toModel].parent][toModel];
35010
35198
  let cur = graph[toModel].parent;
35011
35199
  while (graph[cur].parent) {
35012
- path70.unshift(graph[cur].parent);
35200
+ path69.unshift(graph[cur].parent);
35013
35201
  fn = link(conversions[graph[cur].parent][cur], fn);
35014
35202
  cur = graph[cur].parent;
35015
35203
  }
35016
- fn.conversion = path70;
35204
+ fn.conversion = path69;
35017
35205
  return fn;
35018
35206
  }
35019
35207
  module2.exports = function(fromModel) {
@@ -41507,7 +41695,7 @@ var require_lib2 = __commonJS({
41507
41695
  return matches;
41508
41696
  };
41509
41697
  exports2.analyse = analyse;
41510
- var detectFile = (filepath, opts = {}) => new Promise((resolve53, reject) => {
41698
+ var detectFile = (filepath, opts = {}) => new Promise((resolve52, reject) => {
41511
41699
  let fd;
41512
41700
  const fs54 = (0, node_1.default)();
41513
41701
  const handler = (err, buffer) => {
@@ -41517,7 +41705,7 @@ var require_lib2 = __commonJS({
41517
41705
  if (err) {
41518
41706
  reject(err);
41519
41707
  } else if (buffer) {
41520
- resolve53((0, exports2.detect)(buffer));
41708
+ resolve52((0, exports2.detect)(buffer));
41521
41709
  } else {
41522
41710
  reject(new Error("No error and no buffer received"));
41523
41711
  }
@@ -46066,7 +46254,7 @@ var require_Observable = __commonJS({
46066
46254
  Observable2.prototype.forEach = function(next, promiseCtor) {
46067
46255
  var _this = this;
46068
46256
  promiseCtor = getPromiseCtor(promiseCtor);
46069
- return new promiseCtor(function(resolve53, reject) {
46257
+ return new promiseCtor(function(resolve52, reject) {
46070
46258
  var subscriber = new Subscriber_1.SafeSubscriber({
46071
46259
  next: function(value) {
46072
46260
  try {
@@ -46077,7 +46265,7 @@ var require_Observable = __commonJS({
46077
46265
  }
46078
46266
  },
46079
46267
  error: reject,
46080
- complete: resolve53
46268
+ complete: resolve52
46081
46269
  });
46082
46270
  _this.subscribe(subscriber);
46083
46271
  });
@@ -46099,14 +46287,14 @@ var require_Observable = __commonJS({
46099
46287
  Observable2.prototype.toPromise = function(promiseCtor) {
46100
46288
  var _this = this;
46101
46289
  promiseCtor = getPromiseCtor(promiseCtor);
46102
- return new promiseCtor(function(resolve53, reject) {
46290
+ return new promiseCtor(function(resolve52, reject) {
46103
46291
  var value;
46104
46292
  _this.subscribe(function(x) {
46105
46293
  return value = x;
46106
46294
  }, function(err) {
46107
46295
  return reject(err);
46108
46296
  }, function() {
46109
- return resolve53(value);
46297
+ return resolve52(value);
46110
46298
  });
46111
46299
  });
46112
46300
  };
@@ -48202,11 +48390,11 @@ var require_innerFrom = __commonJS({
48202
48390
  "use strict";
48203
48391
  var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
48204
48392
  function adopt(value) {
48205
- return value instanceof P2 ? value : new P2(function(resolve53) {
48206
- resolve53(value);
48393
+ return value instanceof P2 ? value : new P2(function(resolve52) {
48394
+ resolve52(value);
48207
48395
  });
48208
48396
  }
48209
- return new (P2 || (P2 = Promise))(function(resolve53, reject) {
48397
+ return new (P2 || (P2 = Promise))(function(resolve52, reject) {
48210
48398
  function fulfilled(value) {
48211
48399
  try {
48212
48400
  step(generator.next(value));
@@ -48222,7 +48410,7 @@ var require_innerFrom = __commonJS({
48222
48410
  }
48223
48411
  }
48224
48412
  function step(result) {
48225
- result.done ? resolve53(result.value) : adopt(result.value).then(fulfilled, rejected);
48413
+ result.done ? resolve52(result.value) : adopt(result.value).then(fulfilled, rejected);
48226
48414
  }
48227
48415
  step((generator = generator.apply(thisArg, _arguments || [])).next());
48228
48416
  });
@@ -48304,14 +48492,14 @@ var require_innerFrom = __commonJS({
48304
48492
  }, i);
48305
48493
  function verb(n) {
48306
48494
  i[n] = o[n] && function(v2) {
48307
- return new Promise(function(resolve53, reject) {
48308
- v2 = o[n](v2), settle(resolve53, reject, v2.done, v2.value);
48495
+ return new Promise(function(resolve52, reject) {
48496
+ v2 = o[n](v2), settle(resolve52, reject, v2.done, v2.value);
48309
48497
  });
48310
48498
  };
48311
48499
  }
48312
- function settle(resolve53, reject, d, v2) {
48500
+ function settle(resolve52, reject, d, v2) {
48313
48501
  Promise.resolve(v2).then(function(v3) {
48314
- resolve53({ value: v3, done: d });
48502
+ resolve52({ value: v3, done: d });
48315
48503
  }, reject);
48316
48504
  }
48317
48505
  };
@@ -48930,7 +49118,7 @@ var require_lastValueFrom = __commonJS({
48930
49118
  var EmptyError_1 = require_EmptyError();
48931
49119
  function lastValueFrom2(source, config2) {
48932
49120
  var hasConfig = typeof config2 === "object";
48933
- return new Promise(function(resolve53, reject) {
49121
+ return new Promise(function(resolve52, reject) {
48934
49122
  var _hasValue = false;
48935
49123
  var _value;
48936
49124
  source.subscribe({
@@ -48941,9 +49129,9 @@ var require_lastValueFrom = __commonJS({
48941
49129
  error: reject,
48942
49130
  complete: function() {
48943
49131
  if (_hasValue) {
48944
- resolve53(_value);
49132
+ resolve52(_value);
48945
49133
  } else if (hasConfig) {
48946
- resolve53(config2.defaultValue);
49134
+ resolve52(config2.defaultValue);
48947
49135
  } else {
48948
49136
  reject(new EmptyError_1.EmptyError());
48949
49137
  }
@@ -48965,16 +49153,16 @@ var require_firstValueFrom = __commonJS({
48965
49153
  var Subscriber_1 = require_Subscriber();
48966
49154
  function firstValueFrom(source, config2) {
48967
49155
  var hasConfig = typeof config2 === "object";
48968
- return new Promise(function(resolve53, reject) {
49156
+ return new Promise(function(resolve52, reject) {
48969
49157
  var subscriber = new Subscriber_1.SafeSubscriber({
48970
49158
  next: function(value) {
48971
- resolve53(value);
49159
+ resolve52(value);
48972
49160
  subscriber.unsubscribe();
48973
49161
  },
48974
49162
  error: reject,
48975
49163
  complete: function() {
48976
49164
  if (hasConfig) {
48977
- resolve53(config2.defaultValue);
49165
+ resolve52(config2.defaultValue);
48978
49166
  } else {
48979
49167
  reject(new EmptyError_1.EmptyError());
48980
49168
  }
@@ -54766,14 +54954,14 @@ var require_run_async = __commonJS({
54766
54954
  return function() {
54767
54955
  var args = arguments;
54768
54956
  var originalThis = this;
54769
- var promise = new Promise(function(resolve53, reject) {
54957
+ var promise = new Promise(function(resolve52, reject) {
54770
54958
  var resolved = false;
54771
54959
  const wrappedResolve = function(value) {
54772
54960
  if (resolved) {
54773
54961
  console.warn("Run-async promise already resolved.");
54774
54962
  }
54775
54963
  resolved = true;
54776
- resolve53(value);
54964
+ resolve52(value);
54777
54965
  };
54778
54966
  var rejected = false;
54779
54967
  const wrappedReject = function(value) {
@@ -54881,25 +55069,25 @@ __export(otel_hooks_exports, {
54881
55069
  });
54882
55070
  function getOtelHooksHome() {
54883
55071
  if (process.env.HAR_OTEL_HOOKS_HOME) {
54884
- return path54.resolve(process.env.HAR_OTEL_HOOKS_HOME);
55072
+ return path53.resolve(process.env.HAR_OTEL_HOOKS_HOME);
54885
55073
  }
54886
- return path54.join(os19.homedir(), ".har", "otel-hooks");
55074
+ return path53.join(os19.homedir(), ".har", "otel-hooks");
54887
55075
  }
54888
55076
  function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
54889
- return path54.join(hooksHome, "otel_config.json");
55077
+ return path53.join(hooksHome, "otel_config.json");
54890
55078
  }
54891
55079
  function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
54892
- return path54.join(hooksHome, "run-otel-hook.sh");
55080
+ return path53.join(hooksHome, "run-otel-hook.sh");
54893
55081
  }
54894
55082
  function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
54895
- return path54.join(hooksHome, "state");
55083
+ return path53.join(hooksHome, "state");
54896
55084
  }
54897
55085
  function localOtelHookBin(hooksHome) {
54898
- return path54.join(hooksHome, "node_modules", ".bin", "otel-hook");
55086
+ return path53.join(hooksHome, "node_modules", ".bin", "otel-hook");
54899
55087
  }
54900
55088
  function installedPackageVersion(hooksHome) {
54901
55089
  try {
54902
- const pkgPath = path54.join(
55090
+ const pkgPath = path53.join(
54903
55091
  hooksHome,
54904
55092
  "node_modules",
54905
55093
  "@osfactory",
@@ -55046,9 +55234,9 @@ function uninstallLegacyPythonHooks(hooksHome) {
55046
55234
  }
55047
55235
  function removeLegacyPythonArtifacts(hooksHome) {
55048
55236
  const legacyPaths = [
55049
- path54.join(hooksHome, ".venv"),
55050
- path54.join(hooksHome, "otel_config.yaml"),
55051
- path54.join(hooksHome, "venv")
55237
+ path53.join(hooksHome, ".venv"),
55238
+ path53.join(hooksHome, "otel_config.yaml"),
55239
+ path53.join(hooksHome, "venv")
55052
55240
  ];
55053
55241
  for (const target of legacyPaths) {
55054
55242
  try {
@@ -55194,14 +55382,14 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
55194
55382
  function rewriteKnownHookRegistrations(wrapperPath) {
55195
55383
  const home = os19.homedir();
55196
55384
  const candidates = [
55197
- path54.join(home, ".cursor", "hooks.json"),
55198
- path54.join(home, ".claude", "settings.json"),
55199
- path54.join(home, ".codex", "hooks.json")
55385
+ path53.join(home, ".cursor", "hooks.json"),
55386
+ path53.join(home, ".claude", "settings.json"),
55387
+ path53.join(home, ".codex", "hooks.json")
55200
55388
  ];
55201
55389
  for (const filePath of candidates) {
55202
55390
  try {
55203
55391
  rewriteHookCommandsToWrapper(filePath, wrapperPath);
55204
- if (filePath.endsWith(`${path54.sep}.cursor${path54.sep}hooks.json`)) {
55392
+ if (filePath.endsWith(`${path53.sep}.cursor${path53.sep}hooks.json`)) {
55205
55393
  pruneLegacyCursorHookEvents(filePath, wrapperPath);
55206
55394
  }
55207
55395
  } catch {
@@ -55311,14 +55499,14 @@ function ensureOtelHooks(options) {
55311
55499
  function disableOtelHooksExport() {
55312
55500
  return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
55313
55501
  }
55314
- var import_child_process14, fs46, os19, path54, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
55502
+ var import_child_process14, fs46, os19, path53, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
55315
55503
  var init_otel_hooks = __esm({
55316
55504
  "src/core/otel-hooks.ts"() {
55317
55505
  "use strict";
55318
55506
  import_child_process14 = require("child_process");
55319
55507
  fs46 = __toESM(require("fs"));
55320
55508
  os19 = __toESM(require("os"));
55321
- path54 = __toESM(require("path"));
55509
+ path53 = __toESM(require("path"));
55322
55510
  init_control_config();
55323
55511
  init_telemetry_config();
55324
55512
  OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.2.0";
@@ -58293,7 +58481,7 @@ var require_compile = __commonJS({
58293
58481
  const schOrFunc = root.refs[ref];
58294
58482
  if (schOrFunc)
58295
58483
  return schOrFunc;
58296
- let _sch = resolve53.call(this, root, ref);
58484
+ let _sch = resolve52.call(this, root, ref);
58297
58485
  if (_sch === void 0) {
58298
58486
  const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
58299
58487
  const { schemaId } = this.opts;
@@ -58320,7 +58508,7 @@ var require_compile = __commonJS({
58320
58508
  function sameSchemaEnv(s1, s2) {
58321
58509
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
58322
58510
  }
58323
- function resolve53(root, ref) {
58511
+ function resolve52(root, ref) {
58324
58512
  let sch;
58325
58513
  while (typeof (sch = this.refs[ref]) == "string")
58326
58514
  ref = sch;
@@ -58538,8 +58726,8 @@ var require_utils2 = __commonJS({
58538
58726
  }
58539
58727
  return ind;
58540
58728
  }
58541
- function removeDotSegments(path70) {
58542
- let input = path70;
58729
+ function removeDotSegments(path69) {
58730
+ let input = path69;
58543
58731
  const output = [];
58544
58732
  let nextSlash = -1;
58545
58733
  let len = 0;
@@ -58791,8 +58979,8 @@ var require_schemes = __commonJS({
58791
58979
  wsComponent.secure = void 0;
58792
58980
  }
58793
58981
  if (wsComponent.resourceName) {
58794
- const [path70, query] = wsComponent.resourceName.split("?");
58795
- wsComponent.path = path70 && path70 !== "/" ? path70 : void 0;
58982
+ const [path69, query] = wsComponent.resourceName.split("?");
58983
+ wsComponent.path = path69 && path69 !== "/" ? path69 : void 0;
58796
58984
  wsComponent.query = query;
58797
58985
  wsComponent.resourceName = void 0;
58798
58986
  }
@@ -58951,7 +59139,7 @@ var require_fast_uri = __commonJS({
58951
59139
  }
58952
59140
  return uri;
58953
59141
  }
58954
- function resolve53(baseURI, relativeURI, options) {
59142
+ function resolve52(baseURI, relativeURI, options) {
58955
59143
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
58956
59144
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
58957
59145
  schemelessOptions.skipEscape = true;
@@ -59209,7 +59397,7 @@ var require_fast_uri = __commonJS({
59209
59397
  var fastUri = {
59210
59398
  SCHEMES,
59211
59399
  normalize: normalize3,
59212
- resolve: resolve53,
59400
+ resolve: resolve52,
59213
59401
  resolveComponent,
59214
59402
  equal,
59215
59403
  serialize,
@@ -63474,11 +63662,11 @@ var parser = new YargsParser({
63474
63662
  resolve: import_path2.resolve,
63475
63663
  // TODO: figure out a way to combine ESM and CJS coverage, such that
63476
63664
  // we can exercise all the lines below:
63477
- require: (path70) => {
63665
+ require: (path69) => {
63478
63666
  if (typeof require !== "undefined") {
63479
- return require(path70);
63480
- } else if (path70.match(/\.json$/)) {
63481
- return JSON.parse((0, import_fs2.readFileSync)(path70, "utf8"));
63667
+ return require(path69);
63668
+ } else if (path69.match(/\.json$/)) {
63669
+ return JSON.parse((0, import_fs2.readFileSync)(path69, "utf8"));
63482
63670
  } else {
63483
63671
  throw Error("only .json config files are supported in ESM");
63484
63672
  }
@@ -66004,12 +66192,12 @@ var YargsInstance = class {
66004
66192
  async getCompletion(args, done) {
66005
66193
  argsert("<array> [function]", [args, done], arguments.length);
66006
66194
  if (!done) {
66007
- return new Promise((resolve53, reject) => {
66195
+ return new Promise((resolve52, reject) => {
66008
66196
  __classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
66009
66197
  if (err)
66010
66198
  reject(err);
66011
66199
  else
66012
- resolve53(completions);
66200
+ resolve52(completions);
66013
66201
  });
66014
66202
  });
66015
66203
  } else {
@@ -67054,33 +67242,33 @@ init_telemetry_config();
67054
67242
  init_sync_context();
67055
67243
 
67056
67244
  // src/cli/commands/agents.ts
67057
- var path34 = __toESM(require("path"));
67245
+ var path33 = __toESM(require("path"));
67058
67246
 
67059
67247
  // src/harness/agent-skills.ts
67060
67248
  var fs27 = __toESM(require("fs"));
67061
67249
  var os14 = __toESM(require("os"));
67062
- var path33 = __toESM(require("path"));
67250
+ var path32 = __toESM(require("path"));
67063
67251
  var readline = __toESM(require("readline"));
67064
67252
  init_file_ops();
67065
67253
  init_logging();
67066
67254
 
67067
67255
  // src/utils/paths.ts
67068
67256
  var fs26 = __toESM(require("fs"));
67069
- var path32 = __toESM(require("path"));
67257
+ var path31 = __toESM(require("path"));
67070
67258
  function resolveTemplatesDir() {
67071
67259
  const candidates = [
67072
- path32.join(__dirname, "templates"),
67073
- path32.join(__dirname, "..", "templates"),
67074
- path32.join(__dirname, "..", "harness", "templates")
67260
+ path31.join(__dirname, "templates"),
67261
+ path31.join(__dirname, "..", "templates"),
67262
+ path31.join(__dirname, "..", "harness", "templates")
67075
67263
  ];
67076
67264
  for (const dir of candidates) {
67077
- if (fs26.existsSync(path32.join(dir, "har-boilerplate"))) return dir;
67265
+ if (fs26.existsSync(path31.join(dir, "har-boilerplate"))) return dir;
67078
67266
  }
67079
67267
  throw new Error("Templates directory not found. Run npm run build.");
67080
67268
  }
67081
67269
  function resolveTemplateFile(name) {
67082
67270
  const dir = resolveTemplatesDir();
67083
- const filePath = path32.join(dir, name);
67271
+ const filePath = path31.join(dir, name);
67084
67272
  return fs26.existsSync(filePath) ? filePath : null;
67085
67273
  }
67086
67274
 
@@ -67089,18 +67277,18 @@ init_manifest();
67089
67277
  var AGENT_SKILL_TARGETS = ["claude", "cursor", "codex"];
67090
67278
  var MANAGED_HEADER = "<!-- managed by har \u2014 regenerated by `har agents install` / `har env maintain`; edit at your own risk -->";
67091
67279
  function agentSkillsTemplateDir() {
67092
- const dir = path33.join(resolveTemplatesDir(), "agent-skills");
67280
+ const dir = path32.join(resolveTemplatesDir(), "agent-skills");
67093
67281
  if (!fs27.existsSync(dir)) {
67094
67282
  throw new Error("Agent skills templates not found (templates/agent-skills). Run npm run build.");
67095
67283
  }
67096
67284
  return dir;
67097
67285
  }
67098
67286
  function readSkillsManifest() {
67099
- const manifestPath = path33.join(agentSkillsTemplateDir(), "skills.manifest.json");
67287
+ const manifestPath = path32.join(agentSkillsTemplateDir(), "skills.manifest.json");
67100
67288
  return JSON.parse(fs27.readFileSync(manifestPath, "utf8"));
67101
67289
  }
67102
67290
  function readSkillBody(entry) {
67103
- return fs27.readFileSync(path33.join(agentSkillsTemplateDir(), entry.body), "utf8");
67291
+ return fs27.readFileSync(path32.join(agentSkillsTemplateDir(), entry.body), "utf8");
67104
67292
  }
67105
67293
  function renderYamlValue(value) {
67106
67294
  if (typeof value === "string") return JSON.stringify(value);
@@ -67132,7 +67320,7 @@ function renderSkillFiles(agents) {
67132
67320
  agent: "claude",
67133
67321
  skill: entry.id,
67134
67322
  scope: "repo",
67135
- relPath: path33.join(".claude", "skills", entry.id, "SKILL.md"),
67323
+ relPath: path32.join(".claude", "skills", entry.id, "SKILL.md"),
67136
67324
  content: renderClaudeSkill(entry, body)
67137
67325
  });
67138
67326
  }
@@ -67141,7 +67329,7 @@ function renderSkillFiles(agents) {
67141
67329
  agent: "cursor",
67142
67330
  skill: entry.id,
67143
67331
  scope: "repo",
67144
- relPath: path33.join(".cursor", "commands", `${entry.id}.md`),
67332
+ relPath: path32.join(".cursor", "commands", `${entry.id}.md`),
67145
67333
  content: renderPlainSkill(body)
67146
67334
  });
67147
67335
  }
@@ -67150,7 +67338,7 @@ function renderSkillFiles(agents) {
67150
67338
  agent: "codex",
67151
67339
  skill: entry.id,
67152
67340
  scope: "global",
67153
- relPath: path33.posix.join("~", ".codex", "prompts", `${entry.codex.promptName}.md`),
67341
+ relPath: path32.posix.join("~", ".codex", "prompts", `${entry.codex.promptName}.md`),
67154
67342
  content: renderPlainSkill(body)
67155
67343
  });
67156
67344
  }
@@ -67159,9 +67347,9 @@ function renderSkillFiles(agents) {
67159
67347
  }
67160
67348
  function resolveScaffoldPath(repoPath, file) {
67161
67349
  if (file.scope === "global") {
67162
- return path33.join(os14.homedir(), file.relPath.replace(/^~\//, ""));
67350
+ return path32.join(os14.homedir(), file.relPath.replace(/^~\//, ""));
67163
67351
  }
67164
- return path33.join(repoPath, file.relPath);
67352
+ return path32.join(repoPath, file.relPath);
67165
67353
  }
67166
67354
  function isHarManaged(filePath) {
67167
67355
  return fs27.readFileSync(filePath, "utf8").includes(MANAGED_HEADER);
@@ -67213,7 +67401,7 @@ function removeAgentSkills(repoPath, agents) {
67213
67401
  }
67214
67402
  fs27.rmSync(destPath);
67215
67403
  removed.push(file.relPath);
67216
- const parent = path33.dirname(destPath);
67404
+ const parent = path32.dirname(destPath);
67217
67405
  if (fs27.existsSync(parent) && fs27.readdirSync(parent).length === 0) {
67218
67406
  fs27.rmdirSync(parent);
67219
67407
  }
@@ -67234,9 +67422,9 @@ function detectAgentTargets(repoPath) {
67234
67422
  const manifest = readManifest(repoPath);
67235
67423
  const scaffolded = new Set((manifest?.scaffoldedAgentFiles ?? []).map((entry) => entry.agent));
67236
67424
  const detected = new Set(scaffolded);
67237
- if (fs27.existsSync(path33.join(repoPath, ".claude"))) detected.add("claude");
67238
- if (fs27.existsSync(path33.join(repoPath, ".cursor"))) detected.add("cursor");
67239
- if (fs27.existsSync(path33.join(os14.homedir(), ".codex"))) detected.add("codex");
67425
+ if (fs27.existsSync(path32.join(repoPath, ".claude"))) detected.add("claude");
67426
+ if (fs27.existsSync(path32.join(repoPath, ".cursor"))) detected.add("cursor");
67427
+ if (fs27.existsSync(path32.join(os14.homedir(), ".codex"))) detected.add("codex");
67240
67428
  return AGENT_SKILL_TARGETS.filter((agent) => detected.has(agent));
67241
67429
  }
67242
67430
  function parseAgentTargets(raw) {
@@ -67280,16 +67468,16 @@ async function handleAgentSkills(options) {
67280
67468
  }
67281
67469
  async function askYesNo(question) {
67282
67470
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
67283
- return new Promise((resolve53) => {
67471
+ return new Promise((resolve52) => {
67284
67472
  process.stderr.write(`${question} `);
67285
67473
  rl.once("line", (answer) => {
67286
67474
  rl.close();
67287
67475
  const trimmed = answer.trim();
67288
67476
  if (trimmed === "") {
67289
- resolve53(true);
67477
+ resolve52(true);
67290
67478
  return;
67291
67479
  }
67292
- resolve53(/^y(es)?$/i.test(trimmed));
67480
+ resolve52(/^y(es)?$/i.test(trimmed));
67293
67481
  });
67294
67482
  });
67295
67483
  }
@@ -67323,7 +67511,7 @@ var agentsCommand = {
67323
67511
  }
67324
67512
  };
67325
67513
  function handleInstall(argv) {
67326
- const repoPath = path34.resolve(argv.repo);
67514
+ const repoPath = path33.resolve(argv.repo);
67327
67515
  header("har agents install");
67328
67516
  try {
67329
67517
  const targets = resolveTargets(argv, repoPath);
@@ -67349,7 +67537,7 @@ function handleInstall(argv) {
67349
67537
  }
67350
67538
  }
67351
67539
  function handleRemove(argv) {
67352
- const repoPath = path34.resolve(argv.repo);
67540
+ const repoPath = path33.resolve(argv.repo);
67353
67541
  header("har agents remove");
67354
67542
  try {
67355
67543
  const targets = resolveTargets(argv, repoPath);
@@ -67369,7 +67557,7 @@ function handleRemove(argv) {
67369
67557
  }
67370
67558
 
67371
67559
  // src/cli/commands/env.ts
67372
- var path58 = __toESM(require("path"));
67560
+ var path57 = __toESM(require("path"));
67373
67561
 
67374
67562
  // src/cli/finish-command.ts
67375
67563
  init_sync_context();
@@ -67380,23 +67568,23 @@ async function finishCommand(code) {
67380
67568
 
67381
67569
  // src/core/harness.ts
67382
67570
  var fs42 = __toESM(require("fs"));
67383
- var path49 = __toESM(require("path"));
67571
+ var path48 = __toESM(require("path"));
67384
67572
 
67385
67573
  // src/harness/generator.ts
67386
67574
  var fs32 = __toESM(require("fs"));
67387
- var path39 = __toESM(require("path"));
67575
+ var path38 = __toESM(require("path"));
67388
67576
  init_file_ops();
67389
67577
  init_logging();
67390
67578
 
67391
67579
  // src/core/gitignore.ts
67392
67580
  var fs28 = __toESM(require("fs"));
67393
- var path35 = __toESM(require("path"));
67581
+ var path34 = __toESM(require("path"));
67394
67582
  var HARNESS_ROOT_GITIGNORE_PATTERNS = [
67395
67583
  ".env.agent.*",
67396
67584
  "ecosystem.agent.*.config.cjs"
67397
67585
  ];
67398
67586
  function ensureRootGitignorePatterns(checkoutDir) {
67399
- const gitignorePath = path35.join(checkoutDir, ".gitignore");
67587
+ const gitignorePath = path34.join(checkoutDir, ".gitignore");
67400
67588
  const content = fs28.existsSync(gitignorePath) ? fs28.readFileSync(gitignorePath, "utf8") : "";
67401
67589
  const lines = content.split("\n").map((line) => line.trim());
67402
67590
  const missing = HARNESS_ROOT_GITIGNORE_PATTERNS.filter((pattern) => !lines.includes(pattern));
@@ -67411,7 +67599,7 @@ function ensureRootGitignorePatterns(checkoutDir) {
67411
67599
 
67412
67600
  // src/harness/gitignore-template.ts
67413
67601
  var fs29 = __toESM(require("fs"));
67414
- var path36 = __toESM(require("path"));
67602
+ var path35 = __toESM(require("path"));
67415
67603
  var HARNESS_GITIGNORE_TEMPLATE = "gitignore.template";
67416
67604
  var HARNESS_GITIGNORE_FILE = ".gitignore";
67417
67605
  function harnessFileForTemplate(templateFile) {
@@ -67421,16 +67609,16 @@ function templateFileForHarness(harnessFile) {
67421
67609
  return harnessFile === HARNESS_GITIGNORE_FILE ? HARNESS_GITIGNORE_TEMPLATE : harnessFile;
67422
67610
  }
67423
67611
  function resolveGitignoreTemplateSource(boilerplateDir) {
67424
- const primary = path36.join(boilerplateDir, HARNESS_GITIGNORE_TEMPLATE);
67612
+ const primary = path35.join(boilerplateDir, HARNESS_GITIGNORE_TEMPLATE);
67425
67613
  if (fs29.existsSync(primary)) return primary;
67426
- const legacy = path36.join(boilerplateDir, HARNESS_GITIGNORE_FILE);
67614
+ const legacy = path35.join(boilerplateDir, HARNESS_GITIGNORE_FILE);
67427
67615
  if (fs29.existsSync(legacy)) return legacy;
67428
67616
  return null;
67429
67617
  }
67430
67618
  function writeHarnessGitignore(harnessDir, boilerplateDir) {
67431
67619
  const src = resolveGitignoreTemplateSource(boilerplateDir);
67432
67620
  if (!src) return;
67433
- fs29.writeFileSync(path36.join(harnessDir, HARNESS_GITIGNORE_FILE), fs29.readFileSync(src, "utf8"));
67621
+ fs29.writeFileSync(path35.join(harnessDir, HARNESS_GITIGNORE_FILE), fs29.readFileSync(src, "utf8"));
67434
67622
  }
67435
67623
  function isExpectedHarnessOnlyFile(harnessFile, templateFiles) {
67436
67624
  return harnessFile === HARNESS_GITIGNORE_FILE && templateFiles.includes(HARNESS_GITIGNORE_TEMPLATE);
@@ -67441,7 +67629,7 @@ init_manifest();
67441
67629
 
67442
67630
  // src/harness/plugin-ledger.ts
67443
67631
  var fs30 = __toESM(require("fs"));
67444
- var path37 = __toESM(require("path"));
67632
+ var path36 = __toESM(require("path"));
67445
67633
  init_zod();
67446
67634
  init_file_ops();
67447
67635
  init_manifest();
@@ -67464,7 +67652,7 @@ var PluginLedgerSchema = external_exports.object({
67464
67652
  plugins: external_exports.array(PluginLedgerEntrySchema).default([])
67465
67653
  });
67466
67654
  function getPluginLedgerPath(repoPath) {
67467
- return path37.join(path37.resolve(repoPath), DEFAULT_HAR_DIR, "plugins.json");
67655
+ return path36.join(path36.resolve(repoPath), DEFAULT_HAR_DIR, "plugins.json");
67468
67656
  }
67469
67657
  function readPluginLedger(repoPath) {
67470
67658
  const ledgerPath = getPluginLedgerPath(repoPath);
@@ -67479,7 +67667,7 @@ function readPluginLedger(repoPath) {
67479
67667
  }
67480
67668
  function writePluginLedger(repoPath, ledger) {
67481
67669
  const ledgerPath = getPluginLedgerPath(repoPath);
67482
- const harnessDir = path37.dirname(ledgerPath);
67670
+ const harnessDir = path36.dirname(ledgerPath);
67483
67671
  if (!fs30.existsSync(harnessDir)) {
67484
67672
  fs30.mkdirSync(harnessDir, { recursive: true });
67485
67673
  }
@@ -67517,7 +67705,7 @@ function ensurePluginLedgerScaffold(repoPath, options) {
67517
67705
 
67518
67706
  // src/harness/profiles.ts
67519
67707
  var fs31 = __toESM(require("fs"));
67520
- var path38 = __toESM(require("path"));
67708
+ var path37 = __toESM(require("path"));
67521
67709
  init_zod();
67522
67710
  var HARNESS_PROFILES = ["default", "cli", "ios"];
67523
67711
  var ProfileBundleRefSchema = external_exports.object({
@@ -67570,7 +67758,7 @@ var PROFILE_DIRS = {
67570
67758
  };
67571
67759
  function readProfileManifest(profile) {
67572
67760
  const templates = resolveTemplatesDir();
67573
- const manifestPath = path38.join(templates, "profiles", profile, "profile.manifest.json");
67761
+ const manifestPath = path37.join(templates, "profiles", profile, "profile.manifest.json");
67574
67762
  if (fs31.existsSync(manifestPath)) {
67575
67763
  const parsed = ProfileManifestSchema.safeParse(
67576
67764
  JSON.parse(fs31.readFileSync(manifestPath, "utf8"))
@@ -67586,7 +67774,7 @@ function readProfileManifest(profile) {
67586
67774
  return PROFILE_COMPOSITIONS[profile];
67587
67775
  }
67588
67776
  function resolveProfileBundleDir(bundle) {
67589
- const dir = path38.join(resolveTemplatesDir(), bundle.path);
67777
+ const dir = path37.join(resolveTemplatesDir(), bundle.path);
67590
67778
  if (!fs31.existsSync(dir)) {
67591
67779
  throw new Error(`Profile bundle not found: ${bundle.id} (${bundle.path}). Run npm run build.`);
67592
67780
  }
@@ -67602,20 +67790,20 @@ var CLI_PRUNE_FILES = [
67602
67790
  ];
67603
67791
  function pruneCliProfile(harnessDir) {
67604
67792
  for (const file of CLI_PRUNE_FILES) {
67605
- const filePath = path39.join(harnessDir, file);
67793
+ const filePath = path38.join(harnessDir, file);
67606
67794
  if (fs32.existsSync(filePath)) {
67607
67795
  fs32.unlinkSync(filePath);
67608
67796
  }
67609
67797
  }
67610
67798
  }
67611
67799
  function scaffoldHarnessBoilerplate(repoPath, options = {}) {
67612
- const harnessDir = path39.join(repoPath, DEFAULT_HAR_DIR);
67613
- const projectName = path39.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
67800
+ const harnessDir = path38.join(repoPath, DEFAULT_HAR_DIR);
67801
+ const projectName = path38.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
67614
67802
  const profile = options.profile ?? "default";
67615
67803
  const profileManifest = readProfileManifest(profile);
67616
67804
  const bundleIds = profileManifest.bundles.map((b2) => b2.id);
67617
67805
  const primaryOverlay = PROFILE_DIRS[profile];
67618
- const boilerplateDir = path39.join(resolveTemplatesDir(), primaryOverlay);
67806
+ const boilerplateDir = path38.join(resolveTemplatesDir(), primaryOverlay);
67619
67807
  if (fs32.existsSync(harnessDir) && !options.force) {
67620
67808
  throw new Error(
67621
67809
  '.har/ already exists. Use --force to overwrite or run "har env maintain" to update in place.'
@@ -67637,7 +67825,7 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
67637
67825
  pruneCliProfile(harnessDir);
67638
67826
  }
67639
67827
  syncAgentSlotsToHarnessEnv(repoPath);
67640
- const harnessEnvPath = path39.join(harnessDir, "harness.env");
67828
+ const harnessEnvPath = path38.join(harnessDir, "harness.env");
67641
67829
  if (fs32.existsSync(harnessEnvPath)) {
67642
67830
  let content = fs32.readFileSync(harnessEnvPath, "utf8");
67643
67831
  content = content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
@@ -67666,7 +67854,7 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
67666
67854
 
67667
67855
  // src/harness/agent-md.ts
67668
67856
  var fs34 = __toESM(require("fs"));
67669
- var path42 = __toESM(require("path"));
67857
+ var path41 = __toESM(require("path"));
67670
67858
  init_file_ops();
67671
67859
  init_logging();
67672
67860
  init_manifest();
@@ -67674,7 +67862,7 @@ init_manifest();
67674
67862
  // src/harness/instruction-files.ts
67675
67863
  var fs33 = __toESM(require("fs"));
67676
67864
  var os16 = __toESM(require("os"));
67677
- var path41 = __toESM(require("path"));
67865
+ var path40 = __toESM(require("path"));
67678
67866
 
67679
67867
  // node_modules/@inquirer/core/dist/esm/lib/key.js
67680
67868
  var isUpKey = (key, keybindings = []) => (
@@ -68708,13 +68896,13 @@ var PromisePolyfill = class extends Promise {
68708
68896
  // Available starting from Node 22
68709
68897
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
68710
68898
  static withResolver() {
68711
- let resolve53;
68899
+ let resolve52;
68712
68900
  let reject;
68713
68901
  const promise = new Promise((res, rej) => {
68714
- resolve53 = res;
68902
+ resolve52 = res;
68715
68903
  reject = rej;
68716
68904
  });
68717
- return { promise, resolve: resolve53, reject };
68905
+ return { promise, resolve: resolve52, reject };
68718
68906
  }
68719
68907
  };
68720
68908
 
@@ -68748,7 +68936,7 @@ function createPrompt(view) {
68748
68936
  output
68749
68937
  });
68750
68938
  const screen = new ScreenManager(rl);
68751
- const { promise, resolve: resolve53, reject } = PromisePolyfill.withResolver();
68939
+ const { promise, resolve: resolve52, reject } = PromisePolyfill.withResolver();
68752
68940
  const cancel = () => reject(new CancelPromptError());
68753
68941
  if (signal) {
68754
68942
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -68775,7 +68963,7 @@ function createPrompt(view) {
68775
68963
  cycle(() => {
68776
68964
  try {
68777
68965
  const nextView = view(config2, (value) => {
68778
- setImmediate(() => resolve53(value));
68966
+ setImmediate(() => resolve52(value));
68779
68967
  });
68780
68968
  if (nextView === void 0) {
68781
68969
  const callerFilename = callSites[1]?.getFileName();
@@ -70084,9 +70272,9 @@ var import_rxjs = __toESM(require_cjs(), 1);
70084
70272
  var import_run_async = __toESM(require_run_async(), 1);
70085
70273
  var import_mute_stream2 = __toESM(require_lib(), 1);
70086
70274
  var _ = {
70087
- set: (obj, path70 = "", value) => {
70275
+ set: (obj, path69 = "", value) => {
70088
70276
  let pointer = obj;
70089
- path70.split(".").forEach((key, index, arr) => {
70277
+ path69.split(".").forEach((key, index, arr) => {
70090
70278
  if (key === "__proto__" || key === "constructor")
70091
70279
  return;
70092
70280
  if (index === arr.length - 1) {
@@ -70097,8 +70285,8 @@ var _ = {
70097
70285
  pointer = pointer[key];
70098
70286
  });
70099
70287
  },
70100
- get: (obj, path70 = "", defaultValue) => {
70101
- const travel = (regexp) => String.prototype.split.call(path70, regexp).filter(Boolean).reduce(
70288
+ get: (obj, path69 = "", defaultValue) => {
70289
+ const travel = (regexp) => String.prototype.split.call(path69, regexp).filter(Boolean).reduce(
70102
70290
  // @ts-expect-error implicit any on res[key]
70103
70291
  (res, key) => res == null ? res : res[key],
70104
70292
  obj
@@ -70216,7 +70404,7 @@ var PromptsRunner = class {
70216
70404
  throw new Error(`Prompt for type ${question.type} not found`);
70217
70405
  }
70218
70406
  let cleanupSignal;
70219
- const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((resolve53, reject) => {
70407
+ const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((resolve52, reject) => {
70220
70408
  const { signal: signal2 } = opt;
70221
70409
  if (signal2.aborted) {
70222
70410
  reject(new AbortPromptError({ cause: signal2.reason }));
@@ -70253,7 +70441,7 @@ var PromptsRunner = class {
70253
70441
  signal2.removeEventListener("abort", abort);
70254
70442
  cleanupSignal = void 0;
70255
70443
  };
70256
- activePrompt.run().then(resolve53, reject).finally(cleanup);
70444
+ activePrompt.run().then(resolve52, reject).finally(cleanup);
70257
70445
  }) : prompt2;
70258
70446
  let cleanupModuleSignal;
70259
70447
  const { signal: moduleSignal } = this.opt;
@@ -70423,12 +70611,12 @@ function outsideContentShrinkMessage(beforeLines, afterLines) {
70423
70611
  }
70424
70612
  function detectInstructionFiles(repoPath) {
70425
70613
  return {
70426
- agentsMd: fs33.existsSync(path41.join(repoPath, AGENTS_MD)),
70427
- agentMd: fs33.existsSync(path41.join(repoPath, LEGACY_AGENT_MD)),
70428
- claudeMd: fs33.existsSync(path41.join(repoPath, CLAUDE_MD)),
70429
- cursorDir: fs33.existsSync(path41.join(repoPath, ".cursor")),
70430
- claudeDir: fs33.existsSync(path41.join(repoPath, ".claude")),
70431
- codexHome: fs33.existsSync(path41.join(os16.homedir(), ".codex"))
70614
+ agentsMd: fs33.existsSync(path40.join(repoPath, AGENTS_MD)),
70615
+ agentMd: fs33.existsSync(path40.join(repoPath, LEGACY_AGENT_MD)),
70616
+ claudeMd: fs33.existsSync(path40.join(repoPath, CLAUDE_MD)),
70617
+ cursorDir: fs33.existsSync(path40.join(repoPath, ".cursor")),
70618
+ claudeDir: fs33.existsSync(path40.join(repoPath, ".claude")),
70619
+ codexHome: fs33.existsSync(path40.join(os16.homedir(), ".codex"))
70432
70620
  };
70433
70621
  }
70434
70622
  function formatDetectionReport(detection) {
@@ -70529,7 +70717,7 @@ function mergeAgentsMdContent(existing, incoming) {
70529
70717
  return content;
70530
70718
  }
70531
70719
  function upsertAgentsMdHarSection(repoPath, options = {}) {
70532
- const dest = path41.join(repoPath, AGENTS_MD);
70720
+ const dest = path40.join(repoPath, AGENTS_MD);
70533
70721
  const section = loadHarAgentsSectionFromTemplate();
70534
70722
  if (!fs33.existsSync(dest)) {
70535
70723
  writeFileSafe(dest, loadAgentsMdTemplate());
@@ -70560,8 +70748,8 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
70560
70748
  return action;
70561
70749
  }
70562
70750
  function migrateLegacyAgentMd(repoPath) {
70563
- const legacyPath = path41.join(repoPath, LEGACY_AGENT_MD);
70564
- const agentsPath = path41.join(repoPath, AGENTS_MD);
70751
+ const legacyPath = path40.join(repoPath, LEGACY_AGENT_MD);
70752
+ const agentsPath = path40.join(repoPath, AGENTS_MD);
70565
70753
  if (!fs33.existsSync(legacyPath)) return false;
70566
70754
  const legacy = fs33.readFileSync(legacyPath, "utf8");
70567
70755
  if (!fs33.existsSync(agentsPath)) {
@@ -70602,8 +70790,8 @@ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
70602
70790
  [\`.har/README.md\`](./.har/README.md) before making changes.
70603
70791
  ${CLAUDE_HAR_SECTION_END}`;
70604
70792
  function ensureClaudeMdPointer(repoPath, options = {}) {
70605
- const dest = path41.join(repoPath, CLAUDE_MD);
70606
- const projectName = path41.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
70793
+ const dest = path40.join(repoPath, CLAUDE_MD);
70794
+ const projectName = path40.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
70607
70795
  const thin = loadClaudeMdTemplate(projectName);
70608
70796
  if (!fs33.existsSync(dest)) {
70609
70797
  writeFileSafe(dest, thin);
@@ -70758,10 +70946,10 @@ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
70758
70946
  var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
70759
70947
  function readAgentMdProposal(repoPath) {
70760
70948
  const harnessDir = getHarnessDir(repoPath);
70761
- const proposalPath = path42.join(harnessDir, AGENTS_MD_PROPOSAL);
70762
- const metaPath = path42.join(harnessDir, AGENTS_MD_PROPOSAL_META);
70763
- const legacyProposalPath = path42.join(harnessDir, AGENT_MD_PROPOSAL);
70764
- const legacyMetaPath = path42.join(harnessDir, AGENT_MD_PROPOSAL_META);
70949
+ const proposalPath = path41.join(harnessDir, AGENTS_MD_PROPOSAL);
70950
+ const metaPath = path41.join(harnessDir, AGENTS_MD_PROPOSAL_META);
70951
+ const legacyProposalPath = path41.join(harnessDir, AGENT_MD_PROPOSAL);
70952
+ const legacyMetaPath = path41.join(harnessDir, AGENT_MD_PROPOSAL_META);
70765
70953
  const resolvedProposal = fs34.existsSync(proposalPath) ? proposalPath : fs34.existsSync(legacyProposalPath) ? legacyProposalPath : null;
70766
70954
  if (!resolvedProposal) return null;
70767
70955
  const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
@@ -70787,7 +70975,7 @@ function clearAgentMdProposal(repoPath) {
70787
70975
  AGENT_MD_PROPOSAL,
70788
70976
  AGENT_MD_PROPOSAL_META
70789
70977
  ]) {
70790
- const p = path42.join(harnessDir, file);
70978
+ const p = path41.join(harnessDir, file);
70791
70979
  if (fs34.existsSync(p)) fs34.unlinkSync(p);
70792
70980
  }
70793
70981
  }
@@ -70801,7 +70989,7 @@ function wouldProposalShrinkExisting(existing, proposal) {
70801
70989
  function applyAgentMdProposalMerge(repoPath, options = {}) {
70802
70990
  const proposal = readAgentMdProposal(repoPath);
70803
70991
  if (!proposal) return false;
70804
- const agentsMdPath = path42.join(repoPath, AGENTS_MD);
70992
+ const agentsMdPath = path41.join(repoPath, AGENTS_MD);
70805
70993
  if (fs34.existsSync(agentsMdPath)) {
70806
70994
  const existing = fs34.readFileSync(agentsMdPath, "utf8");
70807
70995
  if (wouldProposalShrinkExisting(existing, proposal.content)) {
@@ -70827,7 +71015,7 @@ function finalizeAgentsMdInstructionFiles(repoPath) {
70827
71015
 
70828
71016
  // src/harness/validator.ts
70829
71017
  var fs35 = __toESM(require("fs"));
70830
- var path43 = __toESM(require("path"));
71018
+ var path42 = __toESM(require("path"));
70831
71019
  init_shell();
70832
71020
  init_manifest();
70833
71021
  init_stages();
@@ -70889,13 +71077,13 @@ function validateHarness(repoPath) {
70889
71077
  };
70890
71078
  }
70891
71079
  for (const file of getRequiredFiles(repoPath)) {
70892
- const filePath = path43.join(harnessDir, file);
71080
+ const filePath = path42.join(harnessDir, file);
70893
71081
  if (!fs35.existsSync(filePath)) {
70894
71082
  issues.push({ file, message: "Required file missing", severity: "error" });
70895
71083
  }
70896
71084
  }
70897
71085
  for (const script of SHELL_SCRIPTS) {
70898
- const scriptPath = path43.join(harnessDir, script);
71086
+ const scriptPath = path42.join(harnessDir, script);
70899
71087
  if (!fs35.existsSync(scriptPath)) continue;
70900
71088
  const stat = fs35.statSync(scriptPath);
70901
71089
  if (!(stat.mode & 73)) {
@@ -70912,7 +71100,7 @@ function validateHarness(repoPath) {
70912
71100
  }
70913
71101
  const manifest = readManifest(repoPath);
70914
71102
  const profile = manifest?.profile ?? "default";
70915
- const ecosystemPath = path43.join(harnessDir, "ecosystem.agent.template.cjs");
71103
+ const ecosystemPath = path42.join(harnessDir, "ecosystem.agent.template.cjs");
70916
71104
  if (profile !== "cli" && fs35.existsSync(ecosystemPath)) {
70917
71105
  const content = fs35.readFileSync(ecosystemPath, "utf8");
70918
71106
  if (!content.includes("module.exports")) {
@@ -70923,7 +71111,7 @@ function validateHarness(repoPath) {
70923
71111
  });
70924
71112
  }
70925
71113
  }
70926
- const harnessEnvPath = path43.join(harnessDir, "harness.env");
71114
+ const harnessEnvPath = path42.join(harnessDir, "harness.env");
70927
71115
  if (fs35.existsSync(harnessEnvPath)) {
70928
71116
  const content = fs35.readFileSync(harnessEnvPath, "utf8");
70929
71117
  if (content.includes("TODO: set migrate command")) {
@@ -70933,14 +71121,14 @@ function validateHarness(repoPath) {
70933
71121
  issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
70934
71122
  }
70935
71123
  }
70936
- const verifyPath = path43.join(harnessDir, "verify.sh");
71124
+ const verifyPath = path42.join(harnessDir, "verify.sh");
70937
71125
  if (fs35.existsSync(verifyPath)) {
70938
71126
  const content = fs35.readFileSync(verifyPath, "utf8");
70939
71127
  if (content.includes("echo 'TODO:")) {
70940
71128
  issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
70941
71129
  }
70942
71130
  }
70943
- const stagesPath = path43.join(harnessDir, "stages.json");
71131
+ const stagesPath = path42.join(harnessDir, "stages.json");
70944
71132
  if (fs35.existsSync(stagesPath)) {
70945
71133
  try {
70946
71134
  JSON.parse(fs35.readFileSync(stagesPath, "utf8"));
@@ -70958,7 +71146,7 @@ function validateHarness(repoPath) {
70958
71146
  } else {
70959
71147
  issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
70960
71148
  }
70961
- const readmePath = path43.join(harnessDir, "README.md");
71149
+ const readmePath = path42.join(harnessDir, "README.md");
70962
71150
  if (fs35.existsSync(readmePath)) {
70963
71151
  const content = fs35.readFileSync(readmePath, "utf8");
70964
71152
  if (!content.includes(".har")) {
@@ -70974,7 +71162,7 @@ function validateHarness(repoPath) {
70974
71162
  async function smokeTestHarness(repoPath) {
70975
71163
  const harnessDir = getHarnessDir(repoPath);
70976
71164
  const issues = [];
70977
- const setupScript = path43.join(harnessDir, "setup-infra.sh");
71165
+ const setupScript = path42.join(harnessDir, "setup-infra.sh");
70978
71166
  if (fs35.existsSync(setupScript)) {
70979
71167
  const result = run(`bash "${setupScript}"`, { cwd: repoPath });
70980
71168
  if (result.code !== 0) {
@@ -70991,7 +71179,7 @@ async function smokeTestHarness(repoPath) {
70991
71179
 
70992
71180
  // src/harness/drift.ts
70993
71181
  var fs36 = __toESM(require("fs"));
70994
- var path44 = __toESM(require("path"));
71182
+ var path43 = __toESM(require("path"));
70995
71183
  init_env();
70996
71184
  init_manifest();
70997
71185
  init_stages();
@@ -71061,12 +71249,12 @@ function listBoilerplateFiles(boilerplateDir) {
71061
71249
  return fs36.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
71062
71250
  }
71063
71251
  function compareHarnessToTemplate(repoPath) {
71064
- const resolved = path44.resolve(repoPath);
71252
+ const resolved = path43.resolve(repoPath);
71065
71253
  const manifest = readManifest(resolved);
71066
71254
  const profile = manifest?.profile ?? "default";
71067
71255
  const harnessDir = getHarnessDir(resolved);
71068
- const projectName = path44.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
71069
- const boilerplateDir = path44.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
71256
+ const projectName = path43.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
71257
+ const boilerplateDir = path43.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
71070
71258
  const templateFiles = listBoilerplateFiles(boilerplateDir);
71071
71259
  const missing = [];
71072
71260
  const checksumMismatch = [];
@@ -71074,8 +71262,8 @@ function compareHarnessToTemplate(repoPath) {
71074
71262
  const unchanged = [];
71075
71263
  for (const file of templateFiles) {
71076
71264
  const harnessFile = harnessFileForTemplate(file);
71077
- const templatePath = path44.join(boilerplateDir, file);
71078
- const harnessPath = path44.join(harnessDir, harnessFile);
71265
+ const templatePath = path43.join(boilerplateDir, file);
71266
+ const harnessPath = path43.join(harnessDir, harnessFile);
71079
71267
  let templateContent = fs36.readFileSync(templatePath, "utf8");
71080
71268
  if (file === "harness.env") {
71081
71269
  templateContent = substituteProjectName(templateContent, projectName);
@@ -71094,7 +71282,7 @@ function compareHarnessToTemplate(repoPath) {
71094
71282
  }
71095
71283
  if (fs36.existsSync(harnessDir)) {
71096
71284
  for (const file of fs36.readdirSync(harnessDir)) {
71097
- const full = path44.join(harnessDir, file);
71285
+ const full = path43.join(harnessDir, file);
71098
71286
  if (!fs36.statSync(full).isFile()) continue;
71099
71287
  if (file === "manifest.json" || file === "plugins.json" || file.startsWith("ADAPT-PROMPT")) {
71100
71288
  continue;
@@ -71124,19 +71312,19 @@ function compareHarnessToTemplate(repoPath) {
71124
71312
  // src/harness/maintain-bundle.ts
71125
71313
  var fs41 = __toESM(require("fs"));
71126
71314
  var os18 = __toESM(require("os"));
71127
- var path48 = __toESM(require("path"));
71315
+ var path47 = __toESM(require("path"));
71128
71316
  init_file_ops();
71129
71317
  init_shell();
71130
71318
  init_manifest();
71131
71319
 
71132
71320
  // src/harness/plugin-drift.ts
71133
71321
  var fs40 = __toESM(require("fs"));
71134
- var path47 = __toESM(require("path"));
71322
+ var path46 = __toESM(require("path"));
71135
71323
  init_manifest();
71136
71324
 
71137
71325
  // src/harness/plugins.ts
71138
71326
  var fs39 = __toESM(require("fs"));
71139
- var path46 = __toESM(require("path"));
71327
+ var path45 = __toESM(require("path"));
71140
71328
  init_zod();
71141
71329
  init_logging();
71142
71330
 
@@ -71151,12 +71339,12 @@ function harnessExists(repoPath) {
71151
71339
  var import_child_process11 = require("child_process");
71152
71340
  var fs38 = __toESM(require("fs"));
71153
71341
  var os17 = __toESM(require("os"));
71154
- var path45 = __toESM(require("path"));
71342
+ var path44 = __toESM(require("path"));
71155
71343
  function hasManifest(dir) {
71156
- return fs38.existsSync(path45.join(dir, "template.manifest.json"));
71344
+ return fs38.existsSync(path44.join(dir, "template.manifest.json"));
71157
71345
  }
71158
71346
  function readPackageVersion(dir) {
71159
- const pkgPath = path45.join(dir, "package.json");
71347
+ const pkgPath = path44.join(dir, "package.json");
71160
71348
  if (!fs38.existsSync(pkgPath)) return void 0;
71161
71349
  try {
71162
71350
  const pkg = JSON.parse(fs38.readFileSync(pkgPath, "utf8"));
@@ -71166,7 +71354,7 @@ function readPackageVersion(dir) {
71166
71354
  }
71167
71355
  }
71168
71356
  function readManifestId(dir) {
71169
- const manifestPath = path45.join(dir, "template.manifest.json");
71357
+ const manifestPath = path44.join(dir, "template.manifest.json");
71170
71358
  if (!fs38.existsSync(manifestPath)) return void 0;
71171
71359
  try {
71172
71360
  const raw = JSON.parse(fs38.readFileSync(manifestPath, "utf8"));
@@ -71187,24 +71375,24 @@ function looksLikeNpm(spec) {
71187
71375
  return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@.+)?$/i.test(spec);
71188
71376
  }
71189
71377
  function resolveBundledDir(pluginId) {
71190
- const dir = path45.join(resolveTemplatesDir(), "plugins", pluginId);
71378
+ const dir = path44.join(resolveTemplatesDir(), "plugins", pluginId);
71191
71379
  return hasManifest(dir) ? dir : null;
71192
71380
  }
71193
71381
  function expandHome(p) {
71194
- if (p.startsWith("~/")) return path45.join(os17.homedir(), p.slice(2));
71382
+ if (p.startsWith("~/")) return path44.join(os17.homedir(), p.slice(2));
71195
71383
  if (p === "~") return os17.homedir();
71196
71384
  return p;
71197
71385
  }
71198
71386
  function resolvePathSpec(spec) {
71199
71387
  const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
71200
- const dir = path45.resolve(expandHome(raw));
71388
+ const dir = path44.resolve(expandHome(raw));
71201
71389
  if (!fs38.existsSync(dir) || !fs38.statSync(dir).isDirectory()) {
71202
71390
  throw new Error(`Plugin path not found: ${spec}`);
71203
71391
  }
71204
71392
  if (!hasManifest(dir)) {
71205
71393
  throw new Error(`No template.manifest.json in ${dir}`);
71206
71394
  }
71207
- const id = readManifestId(dir) ?? path45.basename(dir);
71395
+ const id = readManifestId(dir) ?? path44.basename(dir);
71208
71396
  return {
71209
71397
  id,
71210
71398
  kind: "path",
@@ -71215,7 +71403,7 @@ function resolvePathSpec(spec) {
71215
71403
  };
71216
71404
  }
71217
71405
  function makeTempDir(prefix) {
71218
- return fs38.mkdtempSync(path45.join(os17.tmpdir(), prefix));
71406
+ return fs38.mkdtempSync(path44.join(os17.tmpdir(), prefix));
71219
71407
  }
71220
71408
  function resolveNpmSpec(spec) {
71221
71409
  const tmp = makeTempDir("har-plugin-npm-");
@@ -71230,16 +71418,16 @@ function resolveNpmSpec(spec) {
71230
71418
  if (tarballs.length === 0) {
71231
71419
  throw new Error(`npm pack produced no tarball for ${spec}`);
71232
71420
  }
71233
- const extractDir = path45.join(tmp, "extract");
71421
+ const extractDir = path44.join(tmp, "extract");
71234
71422
  fs38.mkdirSync(extractDir);
71235
- (0, import_child_process11.execFileSync)("tar", ["-xzf", path45.join(tmp, tarballs[0]), "-C", extractDir], {
71423
+ (0, import_child_process11.execFileSync)("tar", ["-xzf", path44.join(tmp, tarballs[0]), "-C", extractDir], {
71236
71424
  encoding: "utf8",
71237
71425
  stdio: ["ignore", "pipe", "pipe"]
71238
71426
  });
71239
- const packageDir = path45.join(extractDir, "package");
71427
+ const packageDir = path44.join(extractDir, "package");
71240
71428
  let dir = packageDir;
71241
71429
  if (!hasManifest(dir)) {
71242
- const nested = fs38.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path45.join(extractDir, e.name)).find((d) => hasManifest(d));
71430
+ const nested = fs38.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path44.join(extractDir, e.name)).find((d) => hasManifest(d));
71243
71431
  if (!nested) {
71244
71432
  throw new Error(
71245
71433
  `npm package ${spec} has no template.manifest.json (not a HAR plugin bundle)`
@@ -71267,7 +71455,7 @@ function resolveNpmSpec(spec) {
71267
71455
  function resolveGitSpec(spec) {
71268
71456
  const tmp = makeTempDir("har-plugin-git-");
71269
71457
  const cleanupDirs = [tmp];
71270
- const cloneDir = path45.join(tmp, "repo");
71458
+ const cloneDir = path44.join(tmp, "repo");
71271
71459
  try {
71272
71460
  let url = spec;
71273
71461
  if (spec.startsWith("github:")) {
@@ -71286,16 +71474,16 @@ function resolveGitSpec(spec) {
71286
71474
  });
71287
71475
  let dir = cloneDir;
71288
71476
  if (!hasManifest(dir)) {
71289
- const pluginsRoot = path45.join(cloneDir, "plugins");
71477
+ const pluginsRoot = path44.join(cloneDir, "plugins");
71290
71478
  if (fs38.existsSync(pluginsRoot)) {
71291
- const child = fs38.readdirSync(pluginsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path45.join(pluginsRoot, e.name)).find((d) => hasManifest(d));
71479
+ const child = fs38.readdirSync(pluginsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path44.join(pluginsRoot, e.name)).find((d) => hasManifest(d));
71292
71480
  if (child) dir = child;
71293
71481
  }
71294
71482
  }
71295
71483
  if (!hasManifest(dir)) {
71296
71484
  throw new Error(`Git repo ${spec} has no template.manifest.json (not a HAR plugin bundle)`);
71297
71485
  }
71298
- const id = readManifestId(dir) ?? path45.basename(url.replace(/\.git$/, ""));
71486
+ const id = readManifestId(dir) ?? path44.basename(url.replace(/\.git$/, ""));
71299
71487
  return {
71300
71488
  id,
71301
71489
  kind: "git",
@@ -71354,9 +71542,9 @@ function resolvePluginSource(spec) {
71354
71542
  );
71355
71543
  }
71356
71544
  function listBundledPluginIds() {
71357
- const root = path45.join(resolveTemplatesDir(), "plugins");
71545
+ const root = path44.join(resolveTemplatesDir(), "plugins");
71358
71546
  if (!fs38.existsSync(root)) return [];
71359
- return fs38.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path45.join(root, name))).sort();
71547
+ return fs38.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path44.join(root, name))).sort();
71360
71548
  }
71361
71549
  function cleanupResolvedPlugin(source) {
71362
71550
  for (const dir of source.cleanupDirs) {
@@ -71412,14 +71600,14 @@ function primaryStageId(manifest) {
71412
71600
  return manifest.stageId ?? stages[0].id;
71413
71601
  }
71414
71602
  function resolveBundledPluginDir(pluginId) {
71415
- const dir = path46.join(resolveTemplatesDir(), "plugins", pluginId);
71603
+ const dir = path45.join(resolveTemplatesDir(), "plugins", pluginId);
71416
71604
  if (!fs39.existsSync(dir)) {
71417
71605
  throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
71418
71606
  }
71419
71607
  return dir;
71420
71608
  }
71421
71609
  function readPluginManifestFromDir(pluginDir, expectedId) {
71422
- const manifestPath = path46.join(pluginDir, "template.manifest.json");
71610
+ const manifestPath = path45.join(pluginDir, "template.manifest.json");
71423
71611
  if (!fs39.existsSync(manifestPath)) {
71424
71612
  throw new Error(`No template.manifest.json in ${pluginDir}`);
71425
71613
  }
@@ -71438,14 +71626,14 @@ function readPluginManifest(pluginId) {
71438
71626
  return readPluginManifestFromDir(resolveBundledPluginDir(pluginId), pluginId);
71439
71627
  }
71440
71628
  function ensureParentDir(filePath) {
71441
- const parent = path46.dirname(filePath);
71629
+ const parent = path45.dirname(filePath);
71442
71630
  if (!fs39.existsSync(parent)) {
71443
71631
  fs39.mkdirSync(parent, { recursive: true });
71444
71632
  }
71445
71633
  }
71446
71634
  function copyPluginFile(pluginDir, file, repoPath, force) {
71447
- const srcPath = path46.join(pluginDir, file.src);
71448
- const destPath = path46.join(repoPath, file.dest);
71635
+ const srcPath = path45.join(pluginDir, file.src);
71636
+ const destPath = path45.join(repoPath, file.dest);
71449
71637
  if (!fs39.existsSync(srcPath)) {
71450
71638
  throw new Error(`Plugin file missing: ${file.src}`);
71451
71639
  }
@@ -71462,11 +71650,11 @@ function copyPluginFile(pluginDir, file, repoPath, force) {
71462
71650
  return { written: true, path: file.dest };
71463
71651
  }
71464
71652
  function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
71465
- const packagePath = path46.join(repoPath, "package.json");
71653
+ const packagePath = path45.join(repoPath, "package.json");
71466
71654
  if (!fs39.existsSync(packagePath)) {
71467
71655
  throw new Error("No package.json in repo root. Add one before applying this plugin.");
71468
71656
  }
71469
- const fragmentPath = path46.join(pluginDir, fragmentRelPath);
71657
+ const fragmentPath = path45.join(pluginDir, fragmentRelPath);
71470
71658
  if (!fs39.existsSync(fragmentPath)) {
71471
71659
  throw new Error(`Package fragment missing: ${fragmentRelPath}`);
71472
71660
  }
@@ -71528,7 +71716,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
71528
71716
  if (force) return;
71529
71717
  const registry2 = readStageRegistry(repoPath);
71530
71718
  for (const stageId of stageIds) {
71531
- const scriptPath = path46.join(repoPath, ".har", "stages", `${stageId}.sh`);
71719
+ const scriptPath = path45.join(repoPath, ".har", "stages", `${stageId}.sh`);
71532
71720
  if (fs39.existsSync(scriptPath)) {
71533
71721
  throw new Error(
71534
71722
  `Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
@@ -71542,7 +71730,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
71542
71730
  }
71543
71731
  }
71544
71732
  function applyPluginFromDir(repoPath, pluginDir, options, meta) {
71545
- const resolved = path46.resolve(repoPath);
71733
+ const resolved = path45.resolve(repoPath);
71546
71734
  const force = options.force ?? false;
71547
71735
  const warnings = [];
71548
71736
  const filesWritten = [];
@@ -71562,7 +71750,7 @@ function applyPluginFromDir(repoPath, pluginDir, options, meta) {
71562
71750
  if (file.skipFlag === "skipCi" && options.skipCi) {
71563
71751
  continue;
71564
71752
  }
71565
- if (fs39.existsSync(path46.join(resolved, file.dest)) && !force) {
71753
+ if (fs39.existsSync(path45.join(resolved, file.dest)) && !force) {
71566
71754
  warnings.push(`Skipped optional file (exists): ${file.dest}`);
71567
71755
  continue;
71568
71756
  }
@@ -71628,12 +71816,12 @@ function listPluginIds() {
71628
71816
  init_stages();
71629
71817
  var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
71630
71818
  function detectInstalledPlugins(repoPath) {
71631
- const resolved = path47.resolve(repoPath);
71819
+ const resolved = path46.resolve(repoPath);
71632
71820
  const ledger = readPluginLedger(resolved);
71633
71821
  if (ledger && ledger.plugins.length > 0) {
71634
71822
  return ledger.plugins.map((p) => p.id).sort();
71635
71823
  }
71636
- const registryPath = path47.join(resolved, ".har", "stages.json");
71824
+ const registryPath = path46.join(resolved, ".har", "stages.json");
71637
71825
  if (!fs40.existsSync(registryPath)) return [];
71638
71826
  const registry2 = readStageRegistry(resolved);
71639
71827
  const stageIds = new Set(registry2.stages.map((stage) => stage.id));
@@ -71651,7 +71839,7 @@ function detectInstalledPlugins(repoPath) {
71651
71839
  return installed.sort();
71652
71840
  }
71653
71841
  function pluginTemplatePath(pluginId, srcRel) {
71654
- return path47.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
71842
+ return path46.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
71655
71843
  }
71656
71844
  function resolvePluginTemplateDir(repoPath, pluginId) {
71657
71845
  const ledger = readPluginLedger(repoPath);
@@ -71663,8 +71851,8 @@ function resolvePluginTemplateDir(repoPath, pluginId) {
71663
71851
  } catch {
71664
71852
  }
71665
71853
  }
71666
- const bundled = path47.join(resolveTemplatesDir(), "plugins", pluginId);
71667
- if (fs40.existsSync(path47.join(bundled, "template.manifest.json"))) {
71854
+ const bundled = path46.join(resolveTemplatesDir(), "plugins", pluginId);
71855
+ if (fs40.existsSync(path46.join(bundled, "template.manifest.json"))) {
71668
71856
  return bundled;
71669
71857
  }
71670
71858
  return null;
@@ -71678,7 +71866,7 @@ function listPluginDestPaths(pluginId, repoPath) {
71678
71866
  const paths = manifest.files.map((file) => file.dest);
71679
71867
  if (manifest.optionalFiles) {
71680
71868
  for (const file of manifest.optionalFiles) {
71681
- if (fs40.existsSync(path47.join(repoPath, file.dest))) {
71869
+ if (fs40.existsSync(path46.join(repoPath, file.dest))) {
71682
71870
  paths.push(file.dest);
71683
71871
  }
71684
71872
  }
@@ -71737,7 +71925,7 @@ function readTemplatePluginFile(pluginId, dest) {
71737
71925
  return null;
71738
71926
  }
71739
71927
  function readInstalledPluginFile(repoPath, pluginId, dest) {
71740
- const installedPath = path47.join(path47.resolve(repoPath), dest);
71928
+ const installedPath = path46.join(path46.resolve(repoPath), dest);
71741
71929
  if (!fs40.existsSync(installedPath)) return null;
71742
71930
  const content = fs40.readFileSync(installedPath, "utf8");
71743
71931
  const manifest = readPluginManifest(pluginId);
@@ -71758,7 +71946,7 @@ function pluginActionHint(pluginId, dest, kind) {
71758
71946
  }
71759
71947
  function comparePluginToTemplate(repoPath, pluginId) {
71760
71948
  const manifest = readPluginManifest(pluginId);
71761
- const resolved = path47.resolve(repoPath);
71949
+ const resolved = path46.resolve(repoPath);
71762
71950
  const destPaths = listPluginDestPaths(pluginId, resolved);
71763
71951
  const missing = [];
71764
71952
  const checksumMismatch = [];
@@ -71773,7 +71961,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
71773
71961
  }
71774
71962
  if (dest === "package.json") {
71775
71963
  const fragmentRel = manifest.merge?.[dest];
71776
- const installedPath = path47.join(resolved, dest);
71964
+ const installedPath = path46.join(resolved, dest);
71777
71965
  const installedRaw = fs40.readFileSync(installedPath, "utf8");
71778
71966
  if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
71779
71967
  unchanged.push(dest);
@@ -71800,7 +71988,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
71800
71988
  }
71801
71989
  function compareInstalledPluginsToTemplate(repoPath) {
71802
71990
  return detectInstalledPlugins(repoPath).filter((pluginId) => {
71803
- const bundled = path47.join(resolveTemplatesDir(), "plugins", pluginId, "template.manifest.json");
71991
+ const bundled = path46.join(resolveTemplatesDir(), "plugins", pluginId, "template.manifest.json");
71804
71992
  return fs40.existsSync(bundled);
71805
71993
  }).map((pluginId) => comparePluginToTemplate(repoPath, pluginId));
71806
71994
  }
@@ -71839,13 +72027,13 @@ function substituteProjectName2(content, projectName) {
71839
72027
  return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
71840
72028
  }
71841
72029
  function projectNameFromRepo(repoPath) {
71842
- return path48.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
72030
+ return path47.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
71843
72031
  }
71844
72032
  function boilerplateDirForProfile(profile) {
71845
- return path48.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
72033
+ return path47.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
71846
72034
  }
71847
72035
  function readBundledTemplateContent(repoPath, profile, file) {
71848
- const templatePath = path48.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
72036
+ const templatePath = path47.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
71849
72037
  let content = fs41.readFileSync(templatePath, "utf8");
71850
72038
  if (file === "harness.env") {
71851
72039
  content = substituteProjectName2(content, projectNameFromRepo(repoPath));
@@ -71877,10 +72065,10 @@ function actionHint(file, kind) {
71877
72065
  return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
71878
72066
  }
71879
72067
  function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
71880
- const tmpDir = fs41.mkdtempSync(path48.join(os18.tmpdir(), "har-maintain-diff-"));
72068
+ const tmpDir = fs41.mkdtempSync(path47.join(os18.tmpdir(), "har-maintain-diff-"));
71881
72069
  try {
71882
- const installedPath = path48.join(tmpDir, "installed");
71883
- const templatePath = path48.join(tmpDir, "template");
72070
+ const installedPath = path47.join(tmpDir, "installed");
72071
+ const templatePath = path47.join(tmpDir, "template");
71884
72072
  fs41.writeFileSync(installedPath, installedContent);
71885
72073
  fs41.writeFileSync(templatePath, templateContent);
71886
72074
  const result = run(`diff -u "${installedPath}" "${templatePath}"`);
@@ -71906,7 +72094,7 @@ function buildActions(repoPath, profile, drift) {
71906
72094
  });
71907
72095
  }
71908
72096
  for (const file of drift.checksumMismatch) {
71909
- const installedPath = path48.join(harnessDir, file);
72097
+ const installedPath = path47.join(harnessDir, file);
71910
72098
  const installedRel = `maintain/installed/${file}`;
71911
72099
  const templateRel = `maintain/templates/${file}`;
71912
72100
  const diffRel = `maintain/diffs/${file}.diff`;
@@ -72066,16 +72254,16 @@ function buildReadme(report) {
72066
72254
  }
72067
72255
  function writeBundleArtifacts(repoPath, profile, drift, report) {
72068
72256
  const harnessDir = getHarnessDir(repoPath);
72069
- const bundleDir = path48.join(harnessDir, MAINTAIN_DIR);
72257
+ const bundleDir = path47.join(harnessDir, MAINTAIN_DIR);
72070
72258
  if (fs41.existsSync(bundleDir)) {
72071
72259
  fs41.rmSync(bundleDir, { recursive: true, force: true });
72072
72260
  }
72073
72261
  const dirs = [
72074
72262
  bundleDir,
72075
- path48.join(bundleDir, "templates"),
72076
- path48.join(bundleDir, "installed"),
72077
- path48.join(bundleDir, "diffs"),
72078
- path48.join(bundleDir, "stale")
72263
+ path47.join(bundleDir, "templates"),
72264
+ path47.join(bundleDir, "installed"),
72265
+ path47.join(bundleDir, "diffs"),
72266
+ path47.join(bundleDir, "stale")
72079
72267
  ];
72080
72268
  for (const dir of dirs) {
72081
72269
  fs41.mkdirSync(dir, { recursive: true });
@@ -72083,11 +72271,11 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
72083
72271
  const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
72084
72272
  for (const file of affectedFiles) {
72085
72273
  const templateContent = readBundledTemplateContent(repoPath, profile, file);
72086
- writeFileSafe(path48.join(bundleDir, "templates", file), templateContent);
72087
- const harnessPath = path48.join(harnessDir, file);
72274
+ writeFileSafe(path47.join(bundleDir, "templates", file), templateContent);
72275
+ const harnessPath = path47.join(harnessDir, file);
72088
72276
  if (fs41.existsSync(harnessPath)) {
72089
72277
  const installedContent = fs41.readFileSync(harnessPath, "utf8");
72090
- writeFileSafe(path48.join(bundleDir, "installed", file), installedContent);
72278
+ writeFileSafe(path47.join(bundleDir, "installed", file), installedContent);
72091
72279
  const diff = createUnifiedDiff(
72092
72280
  installedContent,
72093
72281
  templateContent,
@@ -72095,14 +72283,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
72095
72283
  `templates/${file}`
72096
72284
  );
72097
72285
  if (diff) {
72098
- writeFileSafe(path48.join(bundleDir, "diffs", `${file}.diff`), diff);
72286
+ writeFileSafe(path47.join(bundleDir, "diffs", `${file}.diff`), diff);
72099
72287
  }
72100
72288
  }
72101
72289
  }
72102
- writeFileSafe(path48.join(bundleDir, "README.md"), buildReadme(report));
72103
- writeFileSafe(path48.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
72290
+ writeFileSafe(path47.join(bundleDir, "README.md"), buildReadme(report));
72291
+ writeFileSafe(path47.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
72104
72292
  writeFileSafe(
72105
- path48.join(bundleDir, "validation.json"),
72293
+ path47.join(bundleDir, "validation.json"),
72106
72294
  JSON.stringify(report.validation, null, 2) + "\n"
72107
72295
  );
72108
72296
  if (report.stale.length > 0) {
@@ -72114,12 +72302,12 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
72114
72302
  ...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
72115
72303
  ""
72116
72304
  ];
72117
- writeFileSafe(path48.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
72305
+ writeFileSafe(path47.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
72118
72306
  }
72119
72307
  return bundleDir;
72120
72308
  }
72121
72309
  function ensureParentDir2(filePath) {
72122
- const parent = path48.dirname(filePath);
72310
+ const parent = path47.dirname(filePath);
72123
72311
  if (!fs41.existsSync(parent)) {
72124
72312
  fs41.mkdirSync(parent, { recursive: true });
72125
72313
  }
@@ -72127,21 +72315,21 @@ function ensureParentDir2(filePath) {
72127
72315
  function writePluginBundleArtifacts(repoPath, bundleDir, report) {
72128
72316
  if (report.pluginActions.length === 0) return;
72129
72317
  for (const action of report.pluginActions) {
72130
- const pluginRoot = path48.join(bundleDir, "plugins", action.pluginId);
72131
- const templatesDir = path48.join(pluginRoot, "templates");
72132
- const installedDir = path48.join(pluginRoot, "installed");
72133
- const diffsDir = path48.join(pluginRoot, "diffs");
72318
+ const pluginRoot = path47.join(bundleDir, "plugins", action.pluginId);
72319
+ const templatesDir = path47.join(pluginRoot, "templates");
72320
+ const installedDir = path47.join(pluginRoot, "installed");
72321
+ const diffsDir = path47.join(pluginRoot, "diffs");
72134
72322
  for (const dir of [templatesDir, installedDir, diffsDir]) {
72135
72323
  fs41.mkdirSync(dir, { recursive: true });
72136
72324
  }
72137
72325
  const templateContent = readTemplatePluginFile(action.pluginId, action.file);
72138
72326
  if (templateContent === null) continue;
72139
- const templatePath = path48.join(templatesDir, action.file);
72327
+ const templatePath = path47.join(templatesDir, action.file);
72140
72328
  ensureParentDir2(templatePath);
72141
72329
  writeFileSafe(templatePath, templateContent);
72142
72330
  const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
72143
72331
  if (installedContent !== null) {
72144
- const installedPath = path48.join(installedDir, action.file);
72332
+ const installedPath = path47.join(installedDir, action.file);
72145
72333
  ensureParentDir2(installedPath);
72146
72334
  writeFileSafe(installedPath, installedContent);
72147
72335
  const diff = createUnifiedDiff(
@@ -72151,7 +72339,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
72151
72339
  `templates/${action.file}`
72152
72340
  );
72153
72341
  if (diff) {
72154
- const diffPath = path48.join(diffsDir, `${action.file}.diff`);
72342
+ const diffPath = path47.join(diffsDir, `${action.file}.diff`);
72155
72343
  ensureParentDir2(diffPath);
72156
72344
  writeFileSafe(diffPath, diff);
72157
72345
  }
@@ -72186,7 +72374,7 @@ function buildMaintainBundle(repoPath, validation2, drift) {
72186
72374
  return { bundleDir, report };
72187
72375
  }
72188
72376
  function removeMaintainBundle(repoPath) {
72189
- const bundleDir = path48.join(getHarnessDir(repoPath), MAINTAIN_DIR);
72377
+ const bundleDir = path47.join(getHarnessDir(repoPath), MAINTAIN_DIR);
72190
72378
  if (fs41.existsSync(bundleDir)) {
72191
72379
  fs41.rmSync(bundleDir, { recursive: true, force: true });
72192
72380
  }
@@ -72281,7 +72469,7 @@ function listHarnessScripts(repoPath) {
72281
72469
  return fs42.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
72282
72470
  }
72283
72471
  function describeProject(repoPath) {
72284
- const resolved = path49.resolve(repoPath);
72472
+ const resolved = path48.resolve(repoPath);
72285
72473
  const manifest = readManifest(resolved);
72286
72474
  const present = harnessExists(resolved);
72287
72475
  return {
@@ -72301,7 +72489,7 @@ function describeProject(repoPath) {
72301
72489
  };
72302
72490
  }
72303
72491
  async function initHarness(options) {
72304
- const repoPath = path49.resolve(options.repoPath);
72492
+ const repoPath = path48.resolve(options.repoPath);
72305
72493
  if (!fs42.existsSync(repoPath)) {
72306
72494
  throw new Error(`Path not found: ${repoPath}`);
72307
72495
  }
@@ -72322,7 +72510,7 @@ async function initHarness(options) {
72322
72510
  };
72323
72511
  }
72324
72512
  async function maintainHarness(options) {
72325
- const repoPath = path49.resolve(options.repoPath);
72513
+ const repoPath = path48.resolve(options.repoPath);
72326
72514
  const harnessDir = getHarnessDir(repoPath);
72327
72515
  if (!fs42.existsSync(harnessDir)) {
72328
72516
  throw new Error('No .har/ found. Run "har env init" first.');
@@ -72360,12 +72548,12 @@ function addPlugin(repoPath, pluginId, options = {}) {
72360
72548
 
72361
72549
  // src/harness/custom-stage.ts
72362
72550
  var fs43 = __toESM(require("fs"));
72363
- var path50 = __toESM(require("path"));
72551
+ var path49 = __toESM(require("path"));
72364
72552
  init_schema2();
72365
72553
  init_stages();
72366
72554
  var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
72367
72555
  function addCustomStage(repoPath, options) {
72368
- const resolved = path50.resolve(repoPath);
72556
+ const resolved = path49.resolve(repoPath);
72369
72557
  if (!harnessExists(resolved)) {
72370
72558
  throw new Error('No .har/ harness found. Run "har env init" first.');
72371
72559
  }
@@ -72402,18 +72590,18 @@ function addCustomStage(repoPath, options) {
72402
72590
  if (options.command) {
72403
72591
  stage.command = options.command;
72404
72592
  } else {
72405
- const scriptRel = path50.join("stages", `${id}.sh`);
72406
- const scriptAbs = path50.join(resolved, ".har", scriptRel);
72593
+ const scriptRel = path49.join("stages", `${id}.sh`);
72594
+ const scriptAbs = path49.join(resolved, ".har", scriptRel);
72407
72595
  if (fs43.existsSync(scriptAbs) && !options.force) {
72408
72596
  throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
72409
72597
  }
72410
- const skeletonPath = path50.join(
72598
+ const skeletonPath = path49.join(
72411
72599
  resolveTemplatesDir(),
72412
72600
  "plugins",
72413
72601
  "custom-stage-skeleton.sh"
72414
72602
  );
72415
72603
  const skeleton = fs43.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
72416
- fs43.mkdirSync(path50.dirname(scriptAbs), { recursive: true });
72604
+ fs43.mkdirSync(path49.dirname(scriptAbs), { recursive: true });
72417
72605
  fs43.writeFileSync(scriptAbs, skeleton);
72418
72606
  fs43.chmodSync(scriptAbs, 493);
72419
72607
  filesWritten.push(`.har/${scriptRel}`);
@@ -72464,7 +72652,7 @@ function addCustomStage(repoPath, options) {
72464
72652
 
72465
72653
  // src/harness/adaptation-prompt.ts
72466
72654
  var fs44 = __toESM(require("fs"));
72467
- var path51 = __toESM(require("path"));
72655
+ var path50 = __toESM(require("path"));
72468
72656
  var readline5 = __toESM(require("readline"));
72469
72657
 
72470
72658
  // src/utils/clipboard.ts
@@ -72576,7 +72764,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
72576
72764
  }
72577
72765
  function writeAdaptationPrompt(repoPath, content) {
72578
72766
  const harnessDir = getHarnessDir(repoPath);
72579
- const filePath = path51.join(harnessDir, ADAPTATION_PROMPT_FILE);
72767
+ const filePath = path50.join(harnessDir, ADAPTATION_PROMPT_FILE);
72580
72768
  writeFileSafe(filePath, content);
72581
72769
  return filePath;
72582
72770
  }
@@ -72595,12 +72783,12 @@ function printAdaptationPrompt(content) {
72595
72783
  }
72596
72784
  function askYesNo2(question) {
72597
72785
  const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
72598
- return new Promise((resolve53) => {
72786
+ return new Promise((resolve52) => {
72599
72787
  process.stderr.write(`${question} `);
72600
72788
  rl.once("line", (answer) => {
72601
72789
  rl.close();
72602
72790
  const trimmed = answer.trim();
72603
- resolve53(trimmed === "" || /^y(es)?$/i.test(trimmed));
72791
+ resolve52(trimmed === "" || /^y(es)?$/i.test(trimmed));
72604
72792
  });
72605
72793
  });
72606
72794
  }
@@ -72632,16 +72820,16 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
72632
72820
 
72633
72821
  // src/harness/cursor-rule.ts
72634
72822
  var fs45 = __toESM(require("fs"));
72635
- var path52 = __toESM(require("path"));
72823
+ var path51 = __toESM(require("path"));
72636
72824
  var readline6 = __toESM(require("readline"));
72637
72825
  init_file_ops();
72638
72826
  init_logging();
72639
72827
  var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
72640
72828
  function getCursorRulePath(repoPath) {
72641
- return path52.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
72829
+ return path51.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
72642
72830
  }
72643
72831
  function isCursorWorkspace(repoPath) {
72644
- return fs45.existsSync(path52.join(repoPath, ".cursor"));
72832
+ return fs45.existsSync(path51.join(repoPath, ".cursor"));
72645
72833
  }
72646
72834
  function cursorRuleExists(repoPath) {
72647
72835
  return fs45.existsSync(getCursorRulePath(repoPath));
@@ -72689,16 +72877,16 @@ async function promptScaffoldCursorRule(exists) {
72689
72877
  }
72690
72878
  async function askYesNo3(question) {
72691
72879
  const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
72692
- return new Promise((resolve53) => {
72880
+ return new Promise((resolve52) => {
72693
72881
  process.stderr.write(`${question} `);
72694
72882
  rl.once("line", (answer) => {
72695
72883
  rl.close();
72696
72884
  const trimmed = answer.trim();
72697
72885
  if (trimmed === "") {
72698
- resolve53(true);
72886
+ resolve52(true);
72699
72887
  return;
72700
72888
  }
72701
- resolve53(/^y(es)?$/i.test(trimmed));
72889
+ resolve52(/^y(es)?$/i.test(trimmed));
72702
72890
  });
72703
72891
  });
72704
72892
  }
@@ -72741,7 +72929,7 @@ init_control_config();
72741
72929
 
72742
72930
  // src/core/control-lifecycle.ts
72743
72931
  var import_child_process13 = require("child_process");
72744
- var path53 = __toESM(require("path"));
72932
+ var path52 = __toESM(require("path"));
72745
72933
 
72746
72934
  // src/core/control-image.ts
72747
72935
  init_package_version();
@@ -72768,10 +72956,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
72768
72956
  var CONTROL_CONTAINER_PORT = 3847;
72769
72957
  var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
72770
72958
  function resolveControlDir() {
72771
- return path53.resolve(__dirname, "..", "control");
72959
+ return path52.resolve(__dirname, "..", "control");
72772
72960
  }
72773
72961
  function resolveControlBuildContext() {
72774
- return path53.resolve(resolveControlDir(), "..");
72962
+ return path52.resolve(resolveControlDir(), "..");
72775
72963
  }
72776
72964
  function buildDockerRunArgs(options) {
72777
72965
  const name = options.containerName ?? CONTROL_CONTAINER_NAME;
@@ -72827,7 +73015,7 @@ async function startMissionControl(options) {
72827
73015
  "-t",
72828
73016
  imageRef,
72829
73017
  "-f",
72830
- path53.join(resolveControlDir(), "Dockerfile"),
73018
+ path52.join(resolveControlDir(), "Dockerfile"),
72831
73019
  resolveControlBuildContext()
72832
73020
  ]);
72833
73021
  if (buildCode !== 0) {
@@ -72974,7 +73162,7 @@ async function ensureTelemetryInfrastructure(options) {
72974
73162
  // src/core/run-service.ts
72975
73163
  init_telemetry_config();
72976
73164
  init_telemetry_env();
72977
- var path55 = __toESM(require("path"));
73165
+ var path54 = __toESM(require("path"));
72978
73166
  init_local_executor();
72979
73167
  function extractShellOutput(result) {
72980
73168
  const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
@@ -73180,12 +73368,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
73180
73368
  suffix: session.suffix,
73181
73369
  createdAt: session.createdAt
73182
73370
  });
73183
- const envFile = path55.join(session.workDir, `.env.agent.${options.agentId}`);
73371
+ const envFile = path54.join(session.workDir, `.env.agent.${options.agentId}`);
73184
73372
  try {
73185
73373
  appendTelemetryEnvToFile(envFile, {
73186
73374
  sessionKey,
73187
73375
  agentId: options.agentId,
73188
- repoPath: path55.resolve(options.repoPath),
73376
+ repoPath: path54.resolve(options.repoPath),
73189
73377
  workDir: session.workDir,
73190
73378
  branch: session.branch,
73191
73379
  suffix: session.suffix,
@@ -73424,7 +73612,7 @@ init_slot_status();
73424
73612
  // src/core/cleanup-service.ts
73425
73613
  var fs47 = __toESM(require("fs"));
73426
73614
  var os20 = __toESM(require("os"));
73427
- var path56 = __toESM(require("path"));
73615
+ var path55 = __toESM(require("path"));
73428
73616
  var import_child_process15 = require("child_process");
73429
73617
  init_control_sync();
73430
73618
  init_control_repo_path();
@@ -73433,9 +73621,9 @@ init_manifest();
73433
73621
  var DEFAULT_STALE_DAYS = 7;
73434
73622
  function getWorktreesRoot() {
73435
73623
  if (process.env.HAR_WORKTREES_ROOT) {
73436
- return path56.resolve(process.env.HAR_WORKTREES_ROOT);
73624
+ return path55.resolve(process.env.HAR_WORKTREES_ROOT);
73437
73625
  }
73438
- return path56.join(process.env.HOME || os20.homedir(), "worktrees");
73626
+ return path55.join(process.env.HOME || os20.homedir(), "worktrees");
73439
73627
  }
73440
73628
  function runGit3(cwd, args) {
73441
73629
  try {
@@ -73449,7 +73637,7 @@ function runGit3(cwd, args) {
73449
73637
  }
73450
73638
  }
73451
73639
  function basenameRepo(repoPath) {
73452
- return path56.basename(canonicalizeControlRepoPath(repoPath));
73640
+ return path55.basename(canonicalizeControlRepoPath(repoPath));
73453
73641
  }
73454
73642
  function ageDaysFrom(iso) {
73455
73643
  if (!iso) return void 0;
@@ -73461,12 +73649,12 @@ function matchesKeep(candidate, keep) {
73461
73649
  if (!keep?.length) return false;
73462
73650
  for (const pin of keep) {
73463
73651
  if (pin.worktreePath && candidate.worktreePath) {
73464
- if (path56.resolve(pin.worktreePath) === path56.resolve(candidate.worktreePath)) return true;
73652
+ if (path55.resolve(pin.worktreePath) === path55.resolve(candidate.worktreePath)) return true;
73465
73653
  }
73466
73654
  if (pin.repoPath && pin.agentId !== void 0 && candidate.agentId !== void 0) {
73467
73655
  const repo = canonicalizeControlRepoPath(pin.repoPath);
73468
- const candidateRepo = path56.resolve(candidate.repoPath);
73469
- if ((repo === candidateRepo || path56.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
73656
+ const candidateRepo = path55.resolve(candidate.repoPath);
73657
+ if ((repo === candidateRepo || path55.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
73470
73658
  return true;
73471
73659
  }
73472
73660
  }
@@ -73524,7 +73712,7 @@ function resolveRepoForWorktree(worktreePath) {
73524
73712
  if (!fs47.existsSync(worktreePath)) return void 0;
73525
73713
  const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
73526
73714
  if (!commonDir) return void 0;
73527
- const gitRoot = path56.resolve(worktreePath, commonDir, "..");
73715
+ const gitRoot = path55.resolve(worktreePath, commonDir, "..");
73528
73716
  if (!readManifest(gitRoot)) return void 0;
73529
73717
  return canonicalizeControlRepoPath(gitRoot);
73530
73718
  }
@@ -73534,7 +73722,7 @@ function discoverOrphanWorktrees(knownPaths) {
73534
73722
  const orphans = [];
73535
73723
  for (const entry of fs47.readdirSync(worktreesRoot, { withFileTypes: true })) {
73536
73724
  if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
73537
- const worktreePath = path56.resolve(path56.join(worktreesRoot, entry.name));
73725
+ const worktreePath = path55.resolve(path55.join(worktreesRoot, entry.name));
73538
73726
  if (knownPaths.has(worktreePath)) continue;
73539
73727
  const repoPath = resolveRepoForWorktree(worktreePath) ?? worktreesRoot;
73540
73728
  const porcelain = runGit3(worktreePath, "status --porcelain");
@@ -73565,8 +73753,8 @@ async function discoverCleanupCandidates(options = {}) {
73565
73753
  const status = collectEnvironmentStatus(harnessRoot);
73566
73754
  const projectName = basenameRepo(harnessRoot);
73567
73755
  for (const slot of status.slots) {
73568
- if (slot.worktreePath) knownWorktreePaths.add(path56.resolve(slot.worktreePath));
73569
- if (slot.workDir) knownWorktreePaths.add(path56.resolve(slot.workDir));
73756
+ if (slot.worktreePath) knownWorktreePaths.add(path55.resolve(slot.worktreePath));
73757
+ if (slot.workDir) knownWorktreePaths.add(path55.resolve(slot.workDir));
73570
73758
  const candidate = classifySlotCandidate(canonicalRepo, projectName, slot, {
73571
73759
  staleDays: options.staleDays,
73572
73760
  keep: options.keep
@@ -73626,8 +73814,8 @@ async function askYesNo4(question) {
73626
73814
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
73627
73815
  const readline8 = await import("readline");
73628
73816
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
73629
- const answer = await new Promise((resolve53) => {
73630
- rl.question(question, resolve53);
73817
+ const answer = await new Promise((resolve52) => {
73818
+ rl.question(question, resolve52);
73631
73819
  });
73632
73820
  rl.close();
73633
73821
  return /^[Yy]$/.test(answer.trim());
@@ -73710,7 +73898,7 @@ function parseCleanupKeepPins(values) {
73710
73898
  }
73711
73899
  if (raw.startsWith("/") || raw.startsWith("~")) {
73712
73900
  return {
73713
- worktreePath: raw.startsWith("~") ? path56.join(process.env.HOME || os20.homedir(), raw.slice(2)) : path56.resolve(raw)
73901
+ worktreePath: raw.startsWith("~") ? path55.join(process.env.HOME || os20.homedir(), raw.slice(2)) : path55.resolve(raw)
73714
73902
  };
73715
73903
  }
73716
73904
  return { repoPath: raw };
@@ -73724,12 +73912,12 @@ init_stages();
73724
73912
  init_logging();
73725
73913
  function askYesNo5(question) {
73726
73914
  const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
73727
- return new Promise((resolve53) => {
73915
+ return new Promise((resolve52) => {
73728
73916
  process.stderr.write(`${question} `);
73729
73917
  rl.once("line", (answer) => {
73730
73918
  rl.close();
73731
73919
  const trimmed = answer.trim();
73732
- resolve53(trimmed === "" || /^y(es)?$/i.test(trimmed));
73920
+ resolve52(trimmed === "" || /^y(es)?$/i.test(trimmed));
73733
73921
  });
73734
73922
  });
73735
73923
  }
@@ -73832,13 +74020,13 @@ function warnIfDockerUnavailable(status = detectDockerStatus()) {
73832
74020
  // src/core/onboarding-preferences.ts
73833
74021
  var fs48 = __toESM(require("fs"));
73834
74022
  var os21 = __toESM(require("os"));
73835
- var path57 = __toESM(require("path"));
74023
+ var path56 = __toESM(require("path"));
73836
74024
  init_schema2();
73837
74025
  function getOnboardingPreferencesPath() {
73838
74026
  if (process.env.HAR_PREFERENCES_PATH) {
73839
- return path57.resolve(process.env.HAR_PREFERENCES_PATH);
74027
+ return path56.resolve(process.env.HAR_PREFERENCES_PATH);
73840
74028
  }
73841
- return path57.join(os21.homedir(), ".har", "preferences.json");
74029
+ return path56.join(os21.homedir(), ".har", "preferences.json");
73842
74030
  }
73843
74031
  function readOnboardingPreferences() {
73844
74032
  const preferencePath = getOnboardingPreferencesPath();
@@ -73869,7 +74057,7 @@ function writeOnboardingPreferences(overrides) {
73869
74057
  };
73870
74058
  const parsed = OnboardingPreferencesSchema.parse(preference);
73871
74059
  const preferencePath = getOnboardingPreferencesPath();
73872
- fs48.mkdirSync(path57.dirname(preferencePath), { recursive: true });
74060
+ fs48.mkdirSync(path56.dirname(preferencePath), { recursive: true });
73873
74061
  fs48.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
73874
74062
  `);
73875
74063
  return parsed;
@@ -74215,7 +74403,7 @@ var envCommand = {
74215
74403
  }
74216
74404
  };
74217
74405
  async function handleInit(argv) {
74218
- const repoPath = path58.resolve(argv.repo);
74406
+ const repoPath = path57.resolve(argv.repo);
74219
74407
  const onboarding = resolveOnboardingOptions(argv);
74220
74408
  header("har env init");
74221
74409
  info(`Repository: ${repoPath}`);
@@ -74262,7 +74450,7 @@ async function handleInit(argv) {
74262
74450
  }
74263
74451
  }
74264
74452
  async function handleMaintain(argv) {
74265
- const repoPath = path58.resolve(argv.repo);
74453
+ const repoPath = path57.resolve(argv.repo);
74266
74454
  const onboarding = resolveOnboardingOptions(argv);
74267
74455
  header("har env maintain");
74268
74456
  info(`Repository: ${repoPath}`);
@@ -74393,7 +74581,7 @@ async function applyAgentIntegrations(options) {
74393
74581
  }
74394
74582
  }
74395
74583
  async function handleAddPlugin(argv) {
74396
- const repoPath = path58.resolve(argv.repo);
74584
+ const repoPath = path57.resolve(argv.repo);
74397
74585
  const available = listPluginIds();
74398
74586
  if (argv.list) {
74399
74587
  for (const id of available) {
@@ -74433,7 +74621,7 @@ async function handleAddPlugin(argv) {
74433
74621
  }
74434
74622
  }
74435
74623
  async function handleAddStage(argv) {
74436
- const repoPath = path58.resolve(argv.repo);
74624
+ const repoPath = path57.resolve(argv.repo);
74437
74625
  const available = listPluginIds();
74438
74626
  if (argv.list) {
74439
74627
  warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
@@ -74499,7 +74687,7 @@ async function handleAddStage(argv) {
74499
74687
  });
74500
74688
  }
74501
74689
  async function handlePreflight(argv) {
74502
- const repo = path58.resolve(argv.repo);
74690
+ const repo = path57.resolve(argv.repo);
74503
74691
  const agentId = validateAgentId(argv.id, repo);
74504
74692
  const result = await preflightEnvironment({
74505
74693
  repoPath: repo,
@@ -74515,7 +74703,7 @@ async function handlePreflight(argv) {
74515
74703
  return finishCommand(result.code);
74516
74704
  }
74517
74705
  async function handleLaunch(argv) {
74518
- const repo = path58.resolve(argv.repo);
74706
+ const repo = path57.resolve(argv.repo);
74519
74707
  const agentId = validateAgentId(argv.id, repo);
74520
74708
  if (!argv.resume) {
74521
74709
  const guard = checkLaunchGuard2(repo, agentId, { worktree: argv.worktree });
@@ -74564,7 +74752,7 @@ async function handleWorkLink(argv) {
74564
74752
  error("Provide --link or both --source and --url");
74565
74753
  return finishCommand(1);
74566
74754
  }
74567
- const harnessRoot = resolveHarnessRoot(path58.resolve(argv.repo));
74755
+ const harnessRoot = resolveHarnessRoot(path57.resolve(argv.repo));
74568
74756
  const links = argv.link ? [parseWorkLinkSpec(argv.link)] : [{ source: argv.source, url: argv.url, label: argv.label }];
74569
74757
  try {
74570
74758
  const record2 = addWorkUnitLinks(harnessRoot, argv.workId, links);
@@ -74590,7 +74778,7 @@ async function handleRecover(argv) {
74590
74778
  });
74591
74779
  }
74592
74780
  async function handleVerify(argv) {
74593
- const repo = path58.resolve(argv.repo);
74781
+ const repo = path57.resolve(argv.repo);
74594
74782
  const agentId = validateAgentId(argv.id, repo);
74595
74783
  const result = await runVerification({
74596
74784
  repoPath: repo,
@@ -74619,7 +74807,7 @@ async function handleVerify(argv) {
74619
74807
  return finishCommand(result.code);
74620
74808
  }
74621
74809
  async function handleTeardown(argv) {
74622
- const repo = path58.resolve(argv.repo);
74810
+ const repo = path57.resolve(argv.repo);
74623
74811
  const agentId = validateAgentId(argv.id, repo);
74624
74812
  const result = await teardownEnvironment({
74625
74813
  repoPath: repo,
@@ -74630,7 +74818,7 @@ async function handleTeardown(argv) {
74630
74818
  return finishCommand(result.code);
74631
74819
  }
74632
74820
  async function handleComplete(argv) {
74633
- const repo = path58.resolve(argv.repo);
74821
+ const repo = path57.resolve(argv.repo);
74634
74822
  const agentId = validateAgentId(argv.id, repo);
74635
74823
  const result = await completeEnvironment({
74636
74824
  repoPath: repo,
@@ -74651,7 +74839,7 @@ async function handleComplete(argv) {
74651
74839
  return finishCommand(result.code);
74652
74840
  }
74653
74841
  async function handleStatus(argv) {
74654
- const repoPath = path58.resolve(argv.repo);
74842
+ const repoPath = path57.resolve(argv.repo);
74655
74843
  if (argv.json) {
74656
74844
  const status = collectEnvironmentStatus(repoPath);
74657
74845
  const output = EnvironmentStatusSchema.parse(status);
@@ -74666,7 +74854,7 @@ async function handleStatus(argv) {
74666
74854
  async function handleCleanup(argv) {
74667
74855
  const keepValues = argv.keep?.split(",").map((value) => value.trim()).filter(Boolean);
74668
74856
  const keep = parseCleanupKeepPins(keepValues);
74669
- const repoPaths = argv.repo ? [path58.resolve(argv.repo)] : void 0;
74857
+ const repoPaths = argv.repo ? [path57.resolve(argv.repo)] : void 0;
74670
74858
  const plan = await discoverCleanupCandidates({
74671
74859
  cwd: process.cwd(),
74672
74860
  repoPaths,
@@ -74715,7 +74903,7 @@ async function handleCleanup(argv) {
74715
74903
  return finishCommand(failed > 0 ? 1 : 0);
74716
74904
  }
74717
74905
  async function handleRunsList(argv) {
74718
- const repoPath = path58.resolve(argv.repo);
74906
+ const repoPath = path57.resolve(argv.repo);
74719
74907
  const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
74720
74908
  if (argv.json) {
74721
74909
  process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
@@ -74732,7 +74920,7 @@ async function handleRunsList(argv) {
74732
74920
  }
74733
74921
  }
74734
74922
  async function handleRunsGet(argv) {
74735
- const run2 = getRun(path58.resolve(argv.repo), argv.runId);
74923
+ const run2 = getRun(path57.resolve(argv.repo), argv.runId);
74736
74924
  if (!run2) {
74737
74925
  error(`Run not found: ${argv.runId}`);
74738
74926
  return finishCommand(1);
@@ -74809,7 +74997,7 @@ function printNextSteps() {
74809
74997
  }
74810
74998
 
74811
74999
  // src/cli/commands/control.ts
74812
- var path63 = __toESM(require("path"));
75000
+ var path62 = __toESM(require("path"));
74813
75001
  init_control_config();
74814
75002
  init_portal_targets();
74815
75003
 
@@ -74818,7 +75006,7 @@ init_control_config();
74818
75006
 
74819
75007
  // src/core/portal-connect.ts
74820
75008
  var fs49 = __toESM(require("fs"));
74821
- var path59 = __toESM(require("path"));
75009
+ var path58 = __toESM(require("path"));
74822
75010
  var import_crypto2 = require("crypto");
74823
75011
  init_control_repo_path();
74824
75012
  init_control_registry();
@@ -74864,7 +75052,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
74864
75052
  const options = typeof openUrlOrOptions === "function" ? { openUrl: openUrlOrOptions } : openUrlOrOptions;
74865
75053
  const openUrl = options.openUrl ?? openBrowser;
74866
75054
  const state = (0, import_crypto.randomUUID)();
74867
- return new Promise((resolve53, reject) => {
75055
+ return new Promise((resolve52, reject) => {
74868
75056
  let timer;
74869
75057
  const server = http.createServer((req, res) => {
74870
75058
  const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
@@ -74892,7 +75080,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
74892
75080
  res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
74893
75081
  cleanup();
74894
75082
  const targets = parseCliTargetsParam(requestUrl.searchParams.get("targets"));
74895
- resolve53({
75083
+ resolve52({
74896
75084
  portalUrl,
74897
75085
  token,
74898
75086
  workspace: workspaceSlug ?? workspace,
@@ -74987,7 +75175,7 @@ function remainingConnections(connections, usedAliases) {
74987
75175
  // src/core/portal-connect.ts
74988
75176
  init_portal_targets();
74989
75177
  function attachRepoIfPresent(alias, repoPath) {
74990
- const resolved = path59.resolve(repoPath ?? ".");
75178
+ const resolved = path58.resolve(repoPath ?? ".");
74991
75179
  if (!fs49.existsSync(resolved)) return null;
74992
75180
  const canonical = canonicalizeControlRepoPath(resolved);
74993
75181
  attachRepoPortalTarget(canonical, alias);
@@ -75055,7 +75243,7 @@ async function runPortalConnect(input) {
75055
75243
  return { record: record2, attachedRepo, extraAttached, mappedInBrowser: true };
75056
75244
  }
75057
75245
  function listRegisteredReposForConnect(repoPath) {
75058
- const resolved = repoPath ? path59.resolve(repoPath) : null;
75246
+ const resolved = repoPath ? path58.resolve(repoPath) : null;
75059
75247
  const current = resolved && fs49.existsSync(resolved) ? canonicalizeControlRepoPath(resolved) : null;
75060
75248
  return [.../* @__PURE__ */ new Set([...current ? [current] : [], ...listRegisteredRepos()])];
75061
75249
  }
@@ -75374,13 +75562,13 @@ init_control_sync();
75374
75562
  // src/core/control-sync-selection.ts
75375
75563
  var fs50 = __toESM(require("fs"));
75376
75564
  var os22 = __toESM(require("os"));
75377
- var path60 = __toESM(require("path"));
75565
+ var path59 = __toESM(require("path"));
75378
75566
  init_control_repo_path();
75379
75567
  function getSelectionPath() {
75380
75568
  if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
75381
- return path60.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
75569
+ return path59.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
75382
75570
  }
75383
- return path60.join(os22.homedir(), ".har", "sync-selection.json");
75571
+ return path59.join(os22.homedir(), ".har", "sync-selection.json");
75384
75572
  }
75385
75573
  function readSyncSelection() {
75386
75574
  const selectionPath = getSelectionPath();
@@ -75396,7 +75584,7 @@ function readSyncSelection() {
75396
75584
  function writeSyncSelection(repos) {
75397
75585
  const selectionPath = getSelectionPath();
75398
75586
  const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
75399
- fs50.mkdirSync(path60.dirname(selectionPath), { recursive: true });
75587
+ fs50.mkdirSync(path59.dirname(selectionPath), { recursive: true });
75400
75588
  fs50.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
75401
75589
  }
75402
75590
  function resolveSyncSelection(input) {
@@ -75425,7 +75613,7 @@ function resolveSyncSelection(input) {
75425
75613
 
75426
75614
  // src/core/control-unregister.ts
75427
75615
  var fs51 = __toESM(require("fs"));
75428
- var path61 = __toESM(require("path"));
75616
+ var path60 = __toESM(require("path"));
75429
75617
  init_control_repo_path();
75430
75618
  init_control_registry();
75431
75619
  init_control_config();
@@ -75435,7 +75623,7 @@ function listUnregisterWorktreeCandidates(repoPath) {
75435
75623
  const harnessRoot = canonicalizeControlRepoPath(repoPath);
75436
75624
  const byPath = /* @__PURE__ */ new Map();
75437
75625
  const add = (partial2) => {
75438
- const resolved = path61.resolve(partial2.worktreePath);
75626
+ const resolved = path60.resolve(partial2.worktreePath);
75439
75627
  if (!resolved || resolved === harnessRoot) return;
75440
75628
  const exists = partial2.exists ?? fs51.existsSync(resolved);
75441
75629
  const prev = byPath.get(resolved);
@@ -75488,8 +75676,8 @@ async function askYesNo6(question) {
75488
75676
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
75489
75677
  const readline8 = await import("readline");
75490
75678
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
75491
- const answer = await new Promise((resolve53) => {
75492
- rl.question(question, resolve53);
75679
+ const answer = await new Promise((resolve52) => {
75680
+ rl.question(question, resolve52);
75493
75681
  });
75494
75682
  rl.close();
75495
75683
  return /^[Yy]$/.test(answer.trim());
@@ -75636,15 +75824,15 @@ init_control_registry();
75636
75824
 
75637
75825
  // src/core/harness-scrub.ts
75638
75826
  var fs52 = __toESM(require("fs"));
75639
- var path62 = __toESM(require("path"));
75827
+ var path61 = __toESM(require("path"));
75640
75828
  var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
75641
75829
  function scrubLocalHarnessDirs(repoPath) {
75642
75830
  const results = [];
75643
- const resolved = path62.resolve(repoPath);
75831
+ const resolved = path61.resolve(repoPath);
75644
75832
  if (!fs52.existsSync(resolved)) {
75645
75833
  for (const directory of HARNESS_SCRUB_DIRS) {
75646
75834
  results.push({
75647
- path: path62.join(resolved, ".har", directory),
75835
+ path: path61.join(resolved, ".har", directory),
75648
75836
  directory,
75649
75837
  deleted: false,
75650
75838
  error: "repository path does not exist"
@@ -75653,7 +75841,7 @@ function scrubLocalHarnessDirs(repoPath) {
75653
75841
  return results;
75654
75842
  }
75655
75843
  for (const directory of HARNESS_SCRUB_DIRS) {
75656
- const target = path62.join(resolved, ".har", directory);
75844
+ const target = path61.join(resolved, ".har", directory);
75657
75845
  if (!fs52.existsSync(target)) {
75658
75846
  results.push({ path: target, directory, deleted: true });
75659
75847
  continue;
@@ -75681,7 +75869,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
75681
75869
  const results = [];
75682
75870
  const seen = /* @__PURE__ */ new Set();
75683
75871
  for (const repoPath of repoPaths) {
75684
- const key = path62.resolve(repoPath);
75872
+ const key = path61.resolve(repoPath);
75685
75873
  if (seen.has(key)) continue;
75686
75874
  seen.add(key);
75687
75875
  results.push(...scrubLocalHarnessDirs(key));
@@ -75694,8 +75882,8 @@ async function askYesNo7(question) {
75694
75882
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
75695
75883
  const readline8 = await import("readline");
75696
75884
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
75697
- const answer = await new Promise((resolve53) => {
75698
- rl.question(question, resolve53);
75885
+ const answer = await new Promise((resolve52) => {
75886
+ rl.question(question, resolve52);
75699
75887
  });
75700
75888
  rl.close();
75701
75889
  return /^[Yy]$/.test(answer.trim());
@@ -75974,7 +76162,7 @@ async function handleDown() {
75974
76162
  return finishCommand(code);
75975
76163
  }
75976
76164
  async function handleRegister(argv) {
75977
- const repoPath = path63.resolve(argv.repo);
76165
+ const repoPath = path62.resolve(argv.repo);
75978
76166
  header("har control register");
75979
76167
  info(`Repository: ${repoPath}`);
75980
76168
  try {
@@ -76072,7 +76260,7 @@ async function handleReset(argv) {
76072
76260
  }
76073
76261
  }
76074
76262
  async function handleUnregister(argv) {
76075
- const repoPath = path63.resolve(argv.repo);
76263
+ const repoPath = path62.resolve(argv.repo);
76076
76264
  const worktrees = listUnregisterWorktreeCandidates(repoPath);
76077
76265
  try {
76078
76266
  let deleteWorktrees = argv.deleteWorktrees;
@@ -76210,7 +76398,7 @@ async function handleSync(argv) {
76210
76398
  );
76211
76399
  }
76212
76400
  }
76213
- const { synced, failed, results } = await syncReposWithControl({
76401
+ const { synced, failed, incomplete, results } = await syncReposWithControl({
76214
76402
  repoPaths,
76215
76403
  apiUrl: argv.apiUrl,
76216
76404
  dryRun: argv.dryRun,
@@ -76219,7 +76407,9 @@ async function handleSync(argv) {
76219
76407
  portalTargets
76220
76408
  });
76221
76409
  if (argv.json) {
76222
- process.stdout.write(JSON.stringify({ ok: failed === 0, synced, failed, results }, null, 2) + "\n");
76410
+ process.stdout.write(
76411
+ JSON.stringify({ ok: failed === 0, synced, failed, incomplete, results }, null, 2) + "\n"
76412
+ );
76223
76413
  if (failed > 0) return finishCommand(1);
76224
76414
  return;
76225
76415
  }
@@ -76228,22 +76418,32 @@ async function handleSync(argv) {
76228
76418
  for (const target of result.targets) {
76229
76419
  const record2 = findPortalTargetRecord(target.alias);
76230
76420
  const label = record2 ? displayPortalTargetLabel(record2) : target.alias;
76231
- if (target.ok) {
76232
- success(`Synced ${result.repoPath} \u2192 ${label}`);
76233
- } else {
76421
+ if (!target.ok) {
76234
76422
  warn(`Failed ${result.repoPath} \u2192 ${label}: ${target.error}`);
76423
+ } else if (target.warnings && target.warnings.length > 0) {
76424
+ warn(`Synced ${result.repoPath} \u2192 ${label} \u2014 incomplete`);
76425
+ } else {
76426
+ success(`Synced ${result.repoPath} \u2192 ${label}`);
76235
76427
  }
76236
76428
  }
76237
76429
  continue;
76238
76430
  }
76239
- if (result.ok) {
76240
- success(`Synced ${result.repoPath}`);
76241
- } else {
76431
+ if (!result.ok) {
76242
76432
  warn(`Failed ${result.repoPath}: ${result.error}`);
76433
+ } else if (result.warnings && result.warnings.length > 0) {
76434
+ warn(`Synced ${result.repoPath} \u2014 incomplete`);
76435
+ } else {
76436
+ success(`Synced ${result.repoPath}`);
76243
76437
  }
76244
76438
  }
76245
- if (synced > 0) {
76246
- success(`Synced ${synced} ${synced === 1 ? "repository" : "repositories"}`);
76439
+ if (synced > incomplete) {
76440
+ const complete = synced - incomplete;
76441
+ success(`Synced ${complete} ${complete === 1 ? "repository" : "repositories"}`);
76442
+ }
76443
+ if (incomplete > 0) {
76444
+ warn(
76445
+ `${incomplete} ${incomplete === 1 ? "repository" : "repositories"} synced with incomplete telemetry \u2014 see the warnings above`
76446
+ );
76247
76447
  }
76248
76448
  if (failed > 0) {
76249
76449
  warn(`${failed} ${failed === 1 ? "repository" : "repositories"} could not be synced`);
@@ -76341,12 +76541,12 @@ async function handleTrajectory(argv) {
76341
76541
  }
76342
76542
 
76343
76543
  // src/cli/commands/hooks.ts
76344
- var path65 = __toESM(require("path"));
76544
+ var path64 = __toESM(require("path"));
76345
76545
  init_hooks();
76346
76546
 
76347
76547
  // src/core/claude-hooks.ts
76348
76548
  var fs53 = __toESM(require("fs"));
76349
- var path64 = __toESM(require("path"));
76549
+ var path63 = __toESM(require("path"));
76350
76550
  var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
76351
76551
  var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
76352
76552
  var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
@@ -76367,7 +76567,7 @@ function readSettings(settingsPath) {
76367
76567
  return parsed;
76368
76568
  }
76369
76569
  function writeSettings(settingsPath, settings) {
76370
- fs53.mkdirSync(path64.dirname(settingsPath), { recursive: true });
76570
+ fs53.mkdirSync(path63.dirname(settingsPath), { recursive: true });
76371
76571
  fs53.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
76372
76572
  }
76373
76573
  function installClaudeGuard(repoPath) {
@@ -76375,11 +76575,11 @@ function installClaudeGuard(repoPath) {
76375
76575
  if (!templatePath) {
76376
76576
  throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
76377
76577
  }
76378
- const guardScript = path64.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
76379
- fs53.mkdirSync(path64.dirname(guardScript), { recursive: true });
76578
+ const guardScript = path63.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
76579
+ fs53.mkdirSync(path63.dirname(guardScript), { recursive: true });
76380
76580
  fs53.copyFileSync(templatePath, guardScript);
76381
76581
  fs53.chmodSync(guardScript, 493);
76382
- const settingsPath = path64.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
76582
+ const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
76383
76583
  const settings = readSettings(settingsPath);
76384
76584
  const hooks = settings.hooks ?? {};
76385
76585
  const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
@@ -76393,14 +76593,14 @@ function installClaudeGuard(repoPath) {
76393
76593
  }
76394
76594
  function uninstallClaudeGuard(repoPath) {
76395
76595
  let removed = false;
76396
- const guardScript = path64.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
76596
+ const guardScript = path63.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
76397
76597
  if (fs53.existsSync(guardScript)) {
76398
76598
  fs53.rmSync(guardScript);
76399
76599
  removed = true;
76400
- const parent = path64.dirname(guardScript);
76600
+ const parent = path63.dirname(guardScript);
76401
76601
  if (fs53.existsSync(parent) && fs53.readdirSync(parent).length === 0) fs53.rmdirSync(parent);
76402
76602
  }
76403
- const settingsPath = path64.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
76603
+ const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
76404
76604
  if (fs53.existsSync(settingsPath)) {
76405
76605
  const settings = readSettings(settingsPath);
76406
76606
  const preToolUse = settings.hooks?.PreToolUse;
@@ -76426,7 +76626,7 @@ function uninstallClaudeGuard(repoPath) {
76426
76626
  return { removed };
76427
76627
  }
76428
76628
  function claudeGuardInstalled(repoPath) {
76429
- const settingsPath = path64.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
76629
+ const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
76430
76630
  if (!fs53.existsSync(settingsPath)) return false;
76431
76631
  try {
76432
76632
  const settings = readSettings(settingsPath);
@@ -76444,7 +76644,7 @@ function repoOption(y) {
76444
76644
  function handleInstall2(argv) {
76445
76645
  try {
76446
76646
  if (argv.claude) {
76447
- const result2 = installClaudeGuard(path65.resolve(argv.repo));
76647
+ const result2 = installClaudeGuard(path64.resolve(argv.repo));
76448
76648
  success("Claude Code worktree guard installed.");
76449
76649
  info(`Guard script: ${result2.guardScript}`);
76450
76650
  info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
@@ -76452,7 +76652,7 @@ function handleInstall2(argv) {
76452
76652
  info("Commit both files so the guard travels with the repo.");
76453
76653
  return;
76454
76654
  }
76455
- const result = installHooks({ repoPath: path65.resolve(argv.repo), force: argv.force });
76655
+ const result = installHooks({ repoPath: path64.resolve(argv.repo), force: argv.force });
76456
76656
  success(`Commit gate installed in ${result.hooksDir}`);
76457
76657
  info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
76458
76658
  info("Commits of unverified change batches will be blocked in agent worktrees.");
@@ -76465,7 +76665,7 @@ function handleInstall2(argv) {
76465
76665
  function handleUninstall(argv) {
76466
76666
  try {
76467
76667
  if (argv.claude) {
76468
- const result2 = uninstallClaudeGuard(path65.resolve(argv.repo));
76668
+ const result2 = uninstallClaudeGuard(path64.resolve(argv.repo));
76469
76669
  if (result2.removed) {
76470
76670
  success("Claude Code worktree guard removed.");
76471
76671
  } else {
@@ -76473,7 +76673,7 @@ function handleUninstall(argv) {
76473
76673
  }
76474
76674
  return;
76475
76675
  }
76476
- const result = uninstallHooks(path65.resolve(argv.repo));
76676
+ const result = uninstallHooks(path64.resolve(argv.repo));
76477
76677
  if (result.removed) {
76478
76678
  success(`Commit gate removed from ${result.hooksDir}`);
76479
76679
  } else {
@@ -76486,7 +76686,7 @@ function handleUninstall(argv) {
76486
76686
  }
76487
76687
  function handleStatus2(argv) {
76488
76688
  try {
76489
- const status = getHooksStatus(path65.resolve(argv.repo));
76689
+ const status = getHooksStatus(path64.resolve(argv.repo));
76490
76690
  if (argv.json) {
76491
76691
  process.stdout.write(`${JSON.stringify(status, null, 2)}
76492
76692
  `);
@@ -76504,7 +76704,7 @@ function handleStatus2(argv) {
76504
76704
  );
76505
76705
  info(`Effective: ${status.effectiveMode} (in this checkout)`);
76506
76706
  info(
76507
- `Claude guard: ${claudeGuardInstalled(path65.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
76707
+ `Claude guard: ${claudeGuardInstalled(path64.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
76508
76708
  );
76509
76709
  } catch (err) {
76510
76710
  error(err instanceof Error ? err.message : String(err));
@@ -76765,10 +76965,10 @@ function assignProp(target, prop, value) {
76765
76965
  configurable: true
76766
76966
  });
76767
76967
  }
76768
- function getElementAtPath(obj, path70) {
76769
- if (!path70)
76968
+ function getElementAtPath(obj, path69) {
76969
+ if (!path69)
76770
76970
  return obj;
76771
- return path70.reduce((acc, key) => acc?.[key], obj);
76971
+ return path69.reduce((acc, key) => acc?.[key], obj);
76772
76972
  }
76773
76973
  function promiseAllObject(promisesObj) {
76774
76974
  const keys = Object.keys(promisesObj);
@@ -77088,11 +77288,11 @@ function aborted(x, startIndex = 0) {
77088
77288
  }
77089
77289
  return false;
77090
77290
  }
77091
- function prefixIssues(path70, issues) {
77291
+ function prefixIssues(path69, issues) {
77092
77292
  return issues.map((iss) => {
77093
77293
  var _a2;
77094
77294
  (_a2 = iss).path ?? (_a2.path = []);
77095
- iss.path.unshift(path70);
77295
+ iss.path.unshift(path69);
77096
77296
  return iss;
77097
77297
  });
77098
77298
  }
@@ -82415,7 +82615,7 @@ var Protocol = class {
82415
82615
  return;
82416
82616
  }
82417
82617
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
82418
- await new Promise((resolve53) => setTimeout(resolve53, pollInterval));
82618
+ await new Promise((resolve52) => setTimeout(resolve52, pollInterval));
82419
82619
  options?.signal?.throwIfAborted();
82420
82620
  }
82421
82621
  } catch (error3) {
@@ -82432,7 +82632,7 @@ var Protocol = class {
82432
82632
  */
82433
82633
  request(request, resultSchema, options) {
82434
82634
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
82435
- return new Promise((resolve53, reject) => {
82635
+ return new Promise((resolve52, reject) => {
82436
82636
  const earlyReject = (error3) => {
82437
82637
  reject(error3);
82438
82638
  };
@@ -82510,7 +82710,7 @@ var Protocol = class {
82510
82710
  if (!parseResult.success) {
82511
82711
  reject(parseResult.error);
82512
82712
  } else {
82513
- resolve53(parseResult.data);
82713
+ resolve52(parseResult.data);
82514
82714
  }
82515
82715
  } catch (error3) {
82516
82716
  reject(error3);
@@ -82771,12 +82971,12 @@ var Protocol = class {
82771
82971
  }
82772
82972
  } catch {
82773
82973
  }
82774
- return new Promise((resolve53, reject) => {
82974
+ return new Promise((resolve52, reject) => {
82775
82975
  if (signal.aborted) {
82776
82976
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
82777
82977
  return;
82778
82978
  }
82779
- const timeoutId = setTimeout(resolve53, interval);
82979
+ const timeoutId = setTimeout(resolve52, interval);
82780
82980
  signal.addEventListener("abort", () => {
82781
82981
  clearTimeout(timeoutId);
82782
82982
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -83566,7 +83766,7 @@ var Server = class extends Protocol {
83566
83766
  };
83567
83767
 
83568
83768
  // src/mcp/server.ts
83569
- var path66 = __toESM(require("path"));
83769
+ var path65 = __toESM(require("path"));
83570
83770
 
83571
83771
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
83572
83772
  var import_node_process3 = __toESM(require("node:process"), 1);
@@ -83649,12 +83849,12 @@ var StdioServerTransport = class {
83649
83849
  this.onclose?.();
83650
83850
  }
83651
83851
  send(message) {
83652
- return new Promise((resolve53) => {
83852
+ return new Promise((resolve52) => {
83653
83853
  const json = serializeMessage(message);
83654
83854
  if (this._stdout.write(json)) {
83655
- resolve53();
83855
+ resolve52();
83656
83856
  } else {
83657
- this._stdout.once("drain", resolve53);
83857
+ this._stdout.once("drain", resolve52);
83658
83858
  }
83659
83859
  });
83660
83860
  }
@@ -84293,7 +84493,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
84293
84493
  const input = ControlUpInputSchema.parse({ ...args, repo });
84294
84494
  const result = await startControlAndSync({
84295
84495
  detach: input.detach,
84296
- cwd: path66.resolve(input.repo)
84496
+ cwd: path65.resolve(input.repo)
84297
84497
  });
84298
84498
  if (result.code !== 0) {
84299
84499
  return {
@@ -84357,11 +84557,11 @@ var mcpCommand = {
84357
84557
  };
84358
84558
 
84359
84559
  // src/cli/commands/onboard.ts
84360
- var path68 = __toESM(require("path"));
84560
+ var path67 = __toESM(require("path"));
84361
84561
  init_stages();
84362
84562
 
84363
84563
  // src/core/onboarding.ts
84364
- var path67 = __toESM(require("path"));
84564
+ var path66 = __toESM(require("path"));
84365
84565
  init_control_config();
84366
84566
  init_control_sync();
84367
84567
  init_otel_hooks();
@@ -84505,7 +84705,7 @@ async function defaultEnsureControl(options) {
84505
84705
  return { started: true, apiUrl: result.apiUrl };
84506
84706
  }
84507
84707
  async function runOnboarding(options, deps = {}) {
84508
- const repoPath = path67.resolve(options.repoPath);
84708
+ const repoPath = path66.resolve(options.repoPath);
84509
84709
  const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
84510
84710
  const ensureControl = deps.ensureControl ?? defaultEnsureControl;
84511
84711
  const init = deps.initHarness ?? initHarness;
@@ -84703,7 +84903,7 @@ async function promptChoices(args, docker) {
84703
84903
  };
84704
84904
  }
84705
84905
  const pluginChoices = listPluginChoices();
84706
- const repoPath = path68.resolve(args.repo);
84906
+ const repoPath = path67.resolve(args.repo);
84707
84907
  const alreadyPresent = harnessExists(repoPath);
84708
84908
  const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
84709
84909
  const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
@@ -84824,7 +85024,7 @@ function printSummary(result) {
84824
85024
  console.error("");
84825
85025
  }
84826
85026
  async function handleOnboard(argv) {
84827
- const repoPath = path68.resolve(argv.repo);
85027
+ const repoPath = path67.resolve(argv.repo);
84828
85028
  header("har onboard");
84829
85029
  info(`Repository: ${repoPath}`);
84830
85030
  try {
@@ -85058,7 +85258,7 @@ var preferencesCommand = {
85058
85258
  };
85059
85259
 
85060
85260
  // src/cli/commands/telemetry.ts
85061
- var path69 = __toESM(require("path"));
85261
+ var path68 = __toESM(require("path"));
85062
85262
  init_control_config();
85063
85263
  init_control_sync();
85064
85264
  init_manifest();
@@ -85151,7 +85351,7 @@ async function handleOff() {
85151
85351
  info("Mission Control will not auto-start. Existing usage rows are kept.");
85152
85352
  }
85153
85353
  async function handleWriteEnv(argv) {
85154
- const repoPath = path69.resolve(argv.repo);
85354
+ const repoPath = path68.resolve(argv.repo);
85155
85355
  const harnessRoot = resolveHarnessRoot(repoPath);
85156
85356
  const session = readSlotRegistry(harnessRoot, argv.agentId);
85157
85357
  const workDir = argv.workDir ?? session?.workDir ?? repoPath;
@@ -85163,7 +85363,7 @@ async function handleWriteEnv(argv) {
85163
85363
  suffix,
85164
85364
  createdAt: session?.createdAt
85165
85365
  });
85166
- const envFile = argv.envFile ?? path69.join(workDir, `.env.agent.${argv.agentId}`);
85366
+ const envFile = argv.envFile ?? path68.join(workDir, `.env.agent.${argv.agentId}`);
85167
85367
  const attrs = {
85168
85368
  sessionKey,
85169
85369
  agentId: argv.agentId,
@@ -85179,7 +85379,7 @@ async function handleWriteEnv(argv) {
85179
85379
  success(`Wrote session attribution to ${envFile}`);
85180
85380
  }
85181
85381
  function handlePrintEnv(argv) {
85182
- const repoPath = path69.resolve(argv.repo);
85382
+ const repoPath = path68.resolve(argv.repo);
85183
85383
  const workDir = argv.workDir ?? repoPath;
85184
85384
  const sessionKey = buildSessionKey({
85185
85385
  branch: argv.branch,