@osfactory/har 0.57.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +854 -247
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -553,8 +553,8 @@ var init_parseUtil = __esm({
553
553
  init_errors();
554
554
  init_en();
555
555
  makeIssue = (params) => {
556
- const { data, path: path65, errorMaps, issueData } = params;
557
- const fullPath = [...path65, ...issueData.path || []];
556
+ const { data, path: path66, errorMaps, issueData } = params;
557
+ const fullPath = [...path66, ...issueData.path || []];
558
558
  const fullIssue = {
559
559
  ...issueData,
560
560
  path: fullPath
@@ -862,11 +862,11 @@ var init_types = __esm({
862
862
  init_parseUtil();
863
863
  init_util();
864
864
  ParseInputLazyPath = class {
865
- constructor(parent, value, path65, key) {
865
+ constructor(parent, value, path66, key) {
866
866
  this._cachedPath = [];
867
867
  this.parent = parent;
868
868
  this.data = value;
869
- this._path = path65;
869
+ this._path = path66;
870
870
  this._key = key;
871
871
  }
872
872
  get path() {
@@ -4248,7 +4248,7 @@ var init_zod = __esm({
4248
4248
  });
4249
4249
 
4250
4250
  // packages/schemas/src/schema.ts
4251
- 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, 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, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
4251
+ 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, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
4252
4252
  var init_schema = __esm({
4253
4253
  "packages/schemas/src/schema.ts"() {
4254
4254
  "use strict";
@@ -4413,12 +4413,18 @@ var init_schema = __esm({
4413
4413
  "work unit id must start with an alphanumeric character and contain only stable identifier characters"
4414
4414
  );
4415
4415
  WorkAttemptIdSchema = external_exports.string().uuid();
4416
+ WorkUnitRelatedLinkSchema = external_exports.object({
4417
+ source: external_exports.string().min(1).max(64),
4418
+ url: external_exports.string().url(),
4419
+ label: external_exports.string().min(1).max(128).optional()
4420
+ });
4416
4421
  WorkUnitMetadataSchema = external_exports.object({
4417
4422
  workUnitId: WorkUnitIdSchema,
4418
4423
  source: external_exports.string().min(1).max(64).optional(),
4419
4424
  sourceUrl: external_exports.string().url().optional(),
4420
4425
  title: external_exports.string().min(1).max(256).optional(),
4421
- parentWorkUnitId: WorkUnitIdSchema.optional()
4426
+ parentWorkUnitId: WorkUnitIdSchema.optional(),
4427
+ relatedLinks: external_exports.array(WorkUnitRelatedLinkSchema).optional()
4422
4428
  });
4423
4429
  WorkUnitOutcomeSchema = external_exports.object({
4424
4430
  decision: external_exports.enum(["completed", "abandoned"]),
@@ -28758,7 +28764,7 @@ function runScript(scriptPath, args = [], options = {}) {
28758
28764
  function runScriptCapture(scriptPath, args = [], options = {}) {
28759
28765
  const stream = options.stream ?? false;
28760
28766
  const { stream: _stream, ...spawnOptions } = options;
28761
- return new Promise((resolve49) => {
28767
+ return new Promise((resolve50) => {
28762
28768
  const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
28763
28769
  ...spawnOptions,
28764
28770
  stdio: ["inherit", "pipe", "pipe"]
@@ -28773,13 +28779,13 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
28773
28779
  stderr += d;
28774
28780
  if (stream) process.stderr.write(d);
28775
28781
  });
28776
- proc.on("close", (code) => resolve49({ stdout, stderr, code: code ?? 0 }));
28782
+ proc.on("close", (code) => resolve50({ stdout, stderr, code: code ?? 0 }));
28777
28783
  });
28778
28784
  }
28779
28785
  function runShellCommand(command2, options = {}) {
28780
28786
  const stream = options.stream ?? false;
28781
28787
  const { stream: _stream, ...spawnOptions } = options;
28782
- return new Promise((resolve49) => {
28788
+ return new Promise((resolve50) => {
28783
28789
  const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
28784
28790
  ...spawnOptions,
28785
28791
  stdio: ["inherit", "pipe", "pipe"]
@@ -28794,7 +28800,7 @@ function runShellCommand(command2, options = {}) {
28794
28800
  stderr += d;
28795
28801
  if (stream) process.stderr.write(d);
28796
28802
  });
28797
- proc.on("close", (code) => resolve49({ stdout, stderr, code: code ?? 0 }));
28803
+ proc.on("close", (code) => resolve50({ stdout, stderr, code: code ?? 0 }));
28798
28804
  });
28799
28805
  }
28800
28806
  var import_child_process;
@@ -28863,11 +28869,16 @@ function getRegistryPath() {
28863
28869
  }
28864
28870
  return path9.join(os3.homedir(), ".har", "repos.json");
28865
28871
  }
28872
+ function normalizeRegistry(raw) {
28873
+ const repos = Array.isArray(raw?.repos) ? raw.repos.filter((p) => typeof p === "string") : [];
28874
+ const portalOptOut = Array.isArray(raw?.portalOptOut) ? raw.portalOptOut.filter((p) => typeof p === "string") : void 0;
28875
+ return portalOptOut && portalOptOut.length > 0 ? { repos, portalOptOut } : { repos };
28876
+ }
28866
28877
  function readRegistry() {
28867
28878
  const registryPath = getRegistryPath();
28868
28879
  try {
28869
28880
  if (!fs9.existsSync(registryPath)) return { repos: [] };
28870
- return JSON.parse(fs9.readFileSync(registryPath, "utf8"));
28881
+ return normalizeRegistry(JSON.parse(fs9.readFileSync(registryPath, "utf8")));
28871
28882
  } catch {
28872
28883
  return { repos: [] };
28873
28884
  }
@@ -28875,12 +28886,37 @@ function readRegistry() {
28875
28886
  function writeRegistry(registry2) {
28876
28887
  const registryPath = getRegistryPath();
28877
28888
  fs9.mkdirSync(path9.dirname(registryPath), { recursive: true });
28878
- fs9.writeFileSync(registryPath, JSON.stringify(registry2, null, 2) + "\n");
28889
+ const normalized = normalizeRegistry(registry2);
28890
+ fs9.writeFileSync(registryPath, JSON.stringify(normalized, null, 2) + "\n");
28879
28891
  }
28880
28892
  function registryChanged(before, after) {
28881
28893
  if (before.length !== after.length) return true;
28882
28894
  return before.some((repoPath, index) => repoPath !== after[index]);
28883
28895
  }
28896
+ function pathEqualsCanonical(entry, resolved) {
28897
+ try {
28898
+ return canonicalizeControlRepoPath(entry) === resolved;
28899
+ } catch {
28900
+ return path9.resolve(entry) === resolved;
28901
+ }
28902
+ }
28903
+ function prunePortalOptOut(registry2, keptRepos) {
28904
+ const kept = new Set(keptRepos);
28905
+ const next = [];
28906
+ const seen = /* @__PURE__ */ new Set();
28907
+ for (const entry of registry2.portalOptOut ?? []) {
28908
+ let canonical;
28909
+ try {
28910
+ canonical = canonicalizeControlRepoPath(entry);
28911
+ } catch {
28912
+ canonical = path9.resolve(entry);
28913
+ }
28914
+ if (!kept.has(canonical) || seen.has(canonical)) continue;
28915
+ seen.add(canonical);
28916
+ next.push(canonical);
28917
+ }
28918
+ return next.length > 0 ? next : void 0;
28919
+ }
28884
28920
  function recordRepoForControlSync(repoPath) {
28885
28921
  if (process.env.HAR_CONTROL_DISABLED === "true") return;
28886
28922
  const resolved = canonicalizeControlRepoPath(repoPath);
@@ -28891,18 +28927,40 @@ function recordRepoForControlSync(repoPath) {
28891
28927
  registry2.repos.push(resolved);
28892
28928
  writeRegistry(registry2);
28893
28929
  }
28894
- function removeRegisteredRepo(repoPath) {
28930
+ function isRepoPortalSyncEnabled(repoPath) {
28895
28931
  const resolved = canonicalizeControlRepoPath(repoPath);
28896
28932
  const registry2 = readRegistry();
28897
- const next = registry2.repos.filter((entry) => {
28898
- try {
28899
- return canonicalizeControlRepoPath(entry) !== resolved;
28900
- } catch {
28901
- return path9.resolve(entry) !== resolved;
28902
- }
28933
+ return !(registry2.portalOptOut ?? []).some((entry) => pathEqualsCanonical(entry, resolved));
28934
+ }
28935
+ function setRepoPortalSync(repoPath, enabled) {
28936
+ const resolved = canonicalizeControlRepoPath(repoPath);
28937
+ const registry2 = readRegistry();
28938
+ const current = registry2.portalOptOut ?? [];
28939
+ const without = current.filter((entry) => !pathEqualsCanonical(entry, resolved));
28940
+ if (enabled) {
28941
+ if (without.length === current.length) return;
28942
+ writeRegistry({
28943
+ repos: registry2.repos,
28944
+ ...without.length > 0 ? { portalOptOut: without } : {}
28945
+ });
28946
+ return;
28947
+ }
28948
+ if (without.length !== current.length) return;
28949
+ writeRegistry({
28950
+ repos: registry2.repos,
28951
+ portalOptOut: [...without, resolved]
28903
28952
  });
28953
+ }
28954
+ function removeRegisteredRepo(repoPath) {
28955
+ const resolved = canonicalizeControlRepoPath(repoPath);
28956
+ const registry2 = readRegistry();
28957
+ const next = registry2.repos.filter((entry) => !pathEqualsCanonical(entry, resolved));
28904
28958
  if (next.length === registry2.repos.length) return false;
28905
- writeRegistry({ repos: next });
28959
+ const portalOptOut = prunePortalOptOut(registry2, next);
28960
+ writeRegistry({
28961
+ repos: next,
28962
+ ...portalOptOut ? { portalOptOut } : {}
28963
+ });
28906
28964
  return true;
28907
28965
  }
28908
28966
  function listRegisteredRepos() {
@@ -28917,15 +28975,21 @@ function listRegisteredRepos() {
28917
28975
  seen.add(canonical);
28918
28976
  kept.push(canonical);
28919
28977
  }
28920
- if (registryChanged(registry2.repos, kept)) {
28921
- writeRegistry({ repos: kept });
28978
+ const prunedOptOut = prunePortalOptOut(registry2, kept);
28979
+ const optOutBefore = registry2.portalOptOut ?? [];
28980
+ const optOutChanged = (prunedOptOut?.length ?? 0) !== optOutBefore.length || (prunedOptOut ?? []).some((p, i) => p !== optOutBefore[i]);
28981
+ if (registryChanged(registry2.repos, kept) || optOutChanged) {
28982
+ writeRegistry({
28983
+ repos: kept,
28984
+ ...prunedOptOut ? { portalOptOut: prunedOptOut } : {}
28985
+ });
28922
28986
  }
28923
28987
  return kept;
28924
28988
  }
28925
28989
  function clearRegisteredRepos() {
28926
28990
  const registry2 = readRegistry();
28927
28991
  const count = registry2.repos.length;
28928
- if (count === 0) return 0;
28992
+ if (count === 0 && !registry2.portalOptOut?.length) return 0;
28929
28993
  writeRegistry({ repos: [] });
28930
28994
  return count;
28931
28995
  }
@@ -30904,6 +30968,29 @@ function listRecords(harnessRoot, dir, parse4) {
30904
30968
  }
30905
30969
  return records;
30906
30970
  }
30971
+ function parseWorkLinkSpec(spec) {
30972
+ const parts = spec.split("|");
30973
+ if (parts.length < 2) {
30974
+ throw new Error(
30975
+ `Invalid work link "${spec}" \u2014 use source|url or source|url|label (example: github|https://github.com/org/repo/pull/42|PR #42)`
30976
+ );
30977
+ }
30978
+ const [source, url, ...labelParts] = parts;
30979
+ const label = labelParts.length > 0 ? labelParts.join("|") : void 0;
30980
+ return WorkUnitRelatedLinkSchema.parse({ source, url, label });
30981
+ }
30982
+ function mergeRelatedLinks(existing, incoming, primaryUrl) {
30983
+ if (!incoming?.length) return existing?.length ? existing : void 0;
30984
+ const seen = /* @__PURE__ */ new Set();
30985
+ const merged = [];
30986
+ for (const link of [...existing ?? [], ...incoming]) {
30987
+ if (primaryUrl && link.url === primaryUrl) continue;
30988
+ if (seen.has(link.url)) continue;
30989
+ seen.add(link.url);
30990
+ merged.push(link);
30991
+ }
30992
+ return merged.length > 0 ? merged : void 0;
30993
+ }
30907
30994
  function findWorkUnit(harnessRoot, workUnitId) {
30908
30995
  const metadata = WorkUnitMetadataSchema.parse({ workUnitId });
30909
30996
  const file = hashedRecordPath(harnessRoot, WORK_UNITS_DIR, metadata.workUnitId);
@@ -30933,13 +31020,19 @@ function upsertWorkUnit(harnessRoot, input) {
30933
31020
  }
30934
31021
  }
30935
31022
  const now = (/* @__PURE__ */ new Date()).toISOString();
31023
+ const sourceUrl = existing?.sourceUrl ?? metadata.sourceUrl;
30936
31024
  const record2 = WorkUnitRecordSchema.parse({
30937
31025
  ...existing,
30938
31026
  workUnitId: metadata.workUnitId,
30939
31027
  source: existing?.source ?? metadata.source,
30940
- sourceUrl: existing?.sourceUrl ?? metadata.sourceUrl,
31028
+ sourceUrl,
30941
31029
  title: existing?.title ?? metadata.title,
30942
31030
  parentWorkUnitId: existing?.parentWorkUnitId ?? metadata.parentWorkUnitId,
31031
+ relatedLinks: mergeRelatedLinks(
31032
+ existing?.relatedLinks,
31033
+ metadata.relatedLinks,
31034
+ sourceUrl
31035
+ ),
30943
31036
  version: 1,
30944
31037
  createdAt: existing?.createdAt ?? now,
30945
31038
  updatedAt: now,
@@ -30952,6 +31045,23 @@ function upsertWorkUnit(harnessRoot, input) {
30952
31045
  markDirty(harnessRoot);
30953
31046
  return record2;
30954
31047
  }
31048
+ function addWorkUnitLinks(harnessRoot, workUnitId, links) {
31049
+ const existing = findWorkUnit(harnessRoot, workUnitId);
31050
+ if (!existing) throw new Error(`Unknown work unit: ${workUnitId}`);
31051
+ const parsed = links.map((link) => WorkUnitRelatedLinkSchema.parse(link));
31052
+ const relatedLinks = mergeRelatedLinks(existing.relatedLinks, parsed, existing.sourceUrl);
31053
+ const record2 = WorkUnitRecordSchema.parse({
31054
+ ...existing,
31055
+ relatedLinks,
31056
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
31057
+ });
31058
+ writeRecord2(
31059
+ hashedRecordPath(harnessRoot, WORK_UNITS_DIR, workUnitId),
31060
+ record2
31061
+ );
31062
+ markDirty(harnessRoot);
31063
+ return record2;
31064
+ }
30955
31065
  function listWorkUnits(harnessRoot) {
30956
31066
  return listRecords(
30957
31067
  harnessRoot,
@@ -32431,7 +32541,7 @@ async function postForResponse(url, headers, payload) {
32431
32541
  } catch (err) {
32432
32542
  lastErr = err;
32433
32543
  if (attempt < MAX_FETCH_ATTEMPTS) {
32434
- await new Promise((resolve49) => setTimeout(resolve49, attempt * 100));
32544
+ await new Promise((resolve50) => setTimeout(resolve50, attempt * 100));
32435
32545
  }
32436
32546
  }
32437
32547
  }
@@ -32631,7 +32741,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
32631
32741
  const deadline = Date.now() + timeoutMs;
32632
32742
  while (Date.now() < deadline) {
32633
32743
  if (await isControlApiReachable(apiUrl)) return true;
32634
- await new Promise((resolve49) => setTimeout(resolve49, intervalMs));
32744
+ await new Promise((resolve50) => setTimeout(resolve50, intervalMs));
32635
32745
  }
32636
32746
  return false;
32637
32747
  }
@@ -32734,6 +32844,7 @@ async function syncRepoWithLocalControl(options) {
32734
32844
  }
32735
32845
  }
32736
32846
  async function syncRepoWithPortal(options, controlApiUrl) {
32847
+ if (!isRepoPortalSyncEnabled(options.repoPath)) return;
32737
32848
  const portal = getPortalTarget();
32738
32849
  if (!portal) return;
32739
32850
  const { repoPath, dryRun, full } = options;
@@ -32956,6 +33067,7 @@ async function syncRunWithControlAsync(repoPath, run2) {
32956
33067
  }
32957
33068
  const portal = getPortalTarget();
32958
33069
  if (!portal) return;
33070
+ if (!isRepoPortalSyncEnabled(canonical)) return;
32959
33071
  try {
32960
33072
  if (!await isControlApiReachable(portal.url)) return;
32961
33073
  await postPortal(portal, "/api/sync", { path: canonical, runs: [run2] });
@@ -34128,15 +34240,15 @@ var require_route = __commonJS({
34128
34240
  };
34129
34241
  }
34130
34242
  function wrapConversion(toModel, graph) {
34131
- const path65 = [graph[toModel].parent, toModel];
34243
+ const path66 = [graph[toModel].parent, toModel];
34132
34244
  let fn = conversions[graph[toModel].parent][toModel];
34133
34245
  let cur = graph[toModel].parent;
34134
34246
  while (graph[cur].parent) {
34135
- path65.unshift(graph[cur].parent);
34247
+ path66.unshift(graph[cur].parent);
34136
34248
  fn = link(conversions[graph[cur].parent][cur], fn);
34137
34249
  cur = graph[cur].parent;
34138
34250
  }
34139
- fn.conversion = path65;
34251
+ fn.conversion = path66;
34140
34252
  return fn;
34141
34253
  }
34142
34254
  module2.exports = function(fromModel) {
@@ -40066,7 +40178,7 @@ var require_iso2022 = __commonJS({
40066
40178
  // node_modules/chardet/index.js
40067
40179
  var require_chardet = __commonJS({
40068
40180
  "node_modules/chardet/index.js"(exports2, module2) {
40069
- var fs51 = require("fs");
40181
+ var fs52 = require("fs");
40070
40182
  var utf8 = require_utf8();
40071
40183
  var unicode = require_unicode();
40072
40184
  var mbcs = require_mbcs();
@@ -40140,28 +40252,28 @@ var require_chardet = __commonJS({
40140
40252
  var fd;
40141
40253
  var handler = function(err, buffer) {
40142
40254
  if (fd) {
40143
- fs51.closeSync(fd);
40255
+ fs52.closeSync(fd);
40144
40256
  }
40145
40257
  if (err) return cb(err, null);
40146
40258
  cb(null, self.detect(buffer, opts));
40147
40259
  };
40148
40260
  if (opts && opts.sampleSize) {
40149
- fd = fs51.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40150
- fs51.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40261
+ fd = fs52.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
40262
+ fs52.read(fd, sample, 0, opts.sampleSize, null, function(err) {
40151
40263
  handler(err, sample);
40152
40264
  });
40153
40265
  return;
40154
40266
  }
40155
- fs51.readFile(filepath, handler);
40267
+ fs52.readFile(filepath, handler);
40156
40268
  };
40157
40269
  module2.exports.detectFileSync = function(filepath, opts) {
40158
40270
  if (opts && opts.sampleSize) {
40159
- var fd = fs51.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40160
- fs51.readSync(fd, sample2, 0, opts.sampleSize);
40161
- fs51.closeSync(fd);
40271
+ var fd = fs52.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
40272
+ fs52.readSync(fd, sample2, 0, opts.sampleSize);
40273
+ fs52.closeSync(fd);
40162
40274
  return self.detect(sample2, opts);
40163
40275
  }
40164
- return self.detect(fs51.readFileSync(filepath), opts);
40276
+ return self.detect(fs52.readFileSync(filepath), opts);
40165
40277
  };
40166
40278
  module2.exports.detectAll = function(buffer, opts) {
40167
40279
  if (typeof opts !== "object") {
@@ -43626,16 +43738,16 @@ var require_os_tmpdir = __commonJS({
43626
43738
  var isWindows = process.platform === "win32";
43627
43739
  var trailingSlashRe = isWindows ? /[^:]\\$/ : /.\/$/;
43628
43740
  module2.exports = function() {
43629
- var path65;
43741
+ var path66;
43630
43742
  if (isWindows) {
43631
- path65 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43743
+ path66 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
43632
43744
  } else {
43633
- path65 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43745
+ path66 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
43634
43746
  }
43635
- if (trailingSlashRe.test(path65)) {
43636
- path65 = path65.slice(0, -1);
43747
+ if (trailingSlashRe.test(path66)) {
43748
+ path66 = path66.slice(0, -1);
43637
43749
  }
43638
- return path65;
43750
+ return path66;
43639
43751
  };
43640
43752
  }
43641
43753
  });
@@ -43643,8 +43755,8 @@ var require_os_tmpdir = __commonJS({
43643
43755
  // node_modules/tmp/lib/tmp.js
43644
43756
  var require_tmp = __commonJS({
43645
43757
  "node_modules/tmp/lib/tmp.js"(exports2, module2) {
43646
- var fs51 = require("fs");
43647
- var path65 = require("path");
43758
+ var fs52 = require("fs");
43759
+ var path66 = require("path");
43648
43760
  var crypto6 = require("crypto");
43649
43761
  var osTmpDir = require_os_tmpdir();
43650
43762
  var _c2 = process.binding("constants");
@@ -43686,7 +43798,7 @@ var require_tmp = __commonJS({
43686
43798
  }
43687
43799
  function _generateTmpName(opts) {
43688
43800
  if (opts.name) {
43689
- return path65.join(opts.dir || tmpDir, opts.name);
43801
+ return path66.join(opts.dir || tmpDir, opts.name);
43690
43802
  }
43691
43803
  if (opts.template) {
43692
43804
  return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
@@ -43697,7 +43809,7 @@ var require_tmp = __commonJS({
43697
43809
  _randomChars(12),
43698
43810
  opts.postfix || ""
43699
43811
  ].join("");
43700
- return path65.join(opts.dir || tmpDir, name);
43812
+ return path66.join(opts.dir || tmpDir, name);
43701
43813
  }
43702
43814
  function tmpName(options, callback) {
43703
43815
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1], tries = opts.name ? 1 : opts.tries || DEFAULT_TRIES;
@@ -43707,7 +43819,7 @@ var require_tmp = __commonJS({
43707
43819
  return cb(new Error("Invalid template provided"));
43708
43820
  (function _getUniqueName() {
43709
43821
  const name = _generateTmpName(opts);
43710
- fs51.stat(name, function(err) {
43822
+ fs52.stat(name, function(err) {
43711
43823
  if (!err) {
43712
43824
  if (tries-- > 0) return _getUniqueName();
43713
43825
  return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
@@ -43725,7 +43837,7 @@ var require_tmp = __commonJS({
43725
43837
  do {
43726
43838
  const name = _generateTmpName(opts);
43727
43839
  try {
43728
- fs51.statSync(name);
43840
+ fs52.statSync(name);
43729
43841
  } catch (e) {
43730
43842
  return name;
43731
43843
  }
@@ -43737,13 +43849,13 @@ var require_tmp = __commonJS({
43737
43849
  opts.postfix = _isUndefined(opts.postfix) ? ".tmp" : opts.postfix;
43738
43850
  tmpName(opts, function _tmpNameCreated(err, name) {
43739
43851
  if (err) return cb(err);
43740
- fs51.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43852
+ fs52.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
43741
43853
  if (err2) return cb(err2);
43742
43854
  if (opts.discardDescriptor) {
43743
- return fs51.close(fd, function _discardCallback(err3) {
43855
+ return fs52.close(fd, function _discardCallback(err3) {
43744
43856
  if (err3) {
43745
43857
  try {
43746
- fs51.unlinkSync(name);
43858
+ fs52.unlinkSync(name);
43747
43859
  } catch (e) {
43748
43860
  if (!isENOENT(e)) {
43749
43861
  err3 = e;
@@ -43766,9 +43878,9 @@ var require_tmp = __commonJS({
43766
43878
  opts.postfix = opts.postfix || ".tmp";
43767
43879
  const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
43768
43880
  const name = tmpNameSync(opts);
43769
- var fd = fs51.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43881
+ var fd = fs52.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
43770
43882
  if (opts.discardDescriptor) {
43771
- fs51.closeSync(fd);
43883
+ fs52.closeSync(fd);
43772
43884
  fd = void 0;
43773
43885
  }
43774
43886
  return {
@@ -43780,9 +43892,9 @@ var require_tmp = __commonJS({
43780
43892
  function _rmdirRecursiveSync(root) {
43781
43893
  const dirs = [root];
43782
43894
  do {
43783
- var dir2 = dirs.pop(), deferred = false, files = fs51.readdirSync(dir2);
43895
+ var dir2 = dirs.pop(), deferred = false, files = fs52.readdirSync(dir2);
43784
43896
  for (var i = 0, length = files.length; i < length; i++) {
43785
- var file2 = path65.join(dir2, files[i]), stat = fs51.lstatSync(file2);
43897
+ var file2 = path66.join(dir2, files[i]), stat = fs52.lstatSync(file2);
43786
43898
  if (stat.isDirectory()) {
43787
43899
  if (!deferred) {
43788
43900
  deferred = true;
@@ -43790,11 +43902,11 @@ var require_tmp = __commonJS({
43790
43902
  }
43791
43903
  dirs.push(file2);
43792
43904
  } else {
43793
- fs51.unlinkSync(file2);
43905
+ fs52.unlinkSync(file2);
43794
43906
  }
43795
43907
  }
43796
43908
  if (!deferred) {
43797
- fs51.rmdirSync(dir2);
43909
+ fs52.rmdirSync(dir2);
43798
43910
  }
43799
43911
  } while (dirs.length !== 0);
43800
43912
  }
@@ -43802,7 +43914,7 @@ var require_tmp = __commonJS({
43802
43914
  var args = _parseArguments(options, callback), opts = args[0], cb = args[1];
43803
43915
  tmpName(opts, function _tmpNameCreated(err, name) {
43804
43916
  if (err) return cb(err);
43805
- fs51.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43917
+ fs52.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
43806
43918
  if (err2) return cb(err2);
43807
43919
  cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
43808
43920
  });
@@ -43811,7 +43923,7 @@ var require_tmp = __commonJS({
43811
43923
  function dirSync(options) {
43812
43924
  var args = _parseArguments(options), opts = args[0];
43813
43925
  const name = tmpNameSync(opts);
43814
- fs51.mkdirSync(name, opts.mode || DIR_MODE);
43926
+ fs52.mkdirSync(name, opts.mode || DIR_MODE);
43815
43927
  return {
43816
43928
  name,
43817
43929
  removeCallback: _prepareTmpDirRemoveCallback(name, opts)
@@ -43821,7 +43933,7 @@ var require_tmp = __commonJS({
43821
43933
  const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
43822
43934
  try {
43823
43935
  if (0 <= fdPath[0]) {
43824
- fs51.closeSync(fdPath[0]);
43936
+ fs52.closeSync(fdPath[0]);
43825
43937
  }
43826
43938
  } catch (e) {
43827
43939
  if (!isEBADF(e) && !isENOENT(e)) {
@@ -43829,7 +43941,7 @@ var require_tmp = __commonJS({
43829
43941
  }
43830
43942
  }
43831
43943
  try {
43832
- fs51.unlinkSync(fdPath[1]);
43944
+ fs52.unlinkSync(fdPath[1]);
43833
43945
  } catch (e) {
43834
43946
  if (!isENOENT(e)) {
43835
43947
  throw e;
@@ -43842,7 +43954,7 @@ var require_tmp = __commonJS({
43842
43954
  return removeCallback;
43843
43955
  }
43844
43956
  function _prepareTmpDirRemoveCallback(name, opts) {
43845
- const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs51.rmdirSync.bind(fs51);
43957
+ const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs52.rmdirSync.bind(fs52);
43846
43958
  const removeCallback = _prepareRemoveCallback(removeFunction, name);
43847
43959
  if (!opts.keep) {
43848
43960
  _removeObjects.unshift(removeCallback);
@@ -44993,7 +45105,7 @@ var require_Observable = __commonJS({
44993
45105
  Observable2.prototype.forEach = function(next, promiseCtor) {
44994
45106
  var _this = this;
44995
45107
  promiseCtor = getPromiseCtor(promiseCtor);
44996
- return new promiseCtor(function(resolve49, reject) {
45108
+ return new promiseCtor(function(resolve50, reject) {
44997
45109
  var subscriber = new Subscriber_1.SafeSubscriber({
44998
45110
  next: function(value) {
44999
45111
  try {
@@ -45004,7 +45116,7 @@ var require_Observable = __commonJS({
45004
45116
  }
45005
45117
  },
45006
45118
  error: reject,
45007
- complete: resolve49
45119
+ complete: resolve50
45008
45120
  });
45009
45121
  _this.subscribe(subscriber);
45010
45122
  });
@@ -45026,14 +45138,14 @@ var require_Observable = __commonJS({
45026
45138
  Observable2.prototype.toPromise = function(promiseCtor) {
45027
45139
  var _this = this;
45028
45140
  promiseCtor = getPromiseCtor(promiseCtor);
45029
- return new promiseCtor(function(resolve49, reject) {
45141
+ return new promiseCtor(function(resolve50, reject) {
45030
45142
  var value;
45031
45143
  _this.subscribe(function(x) {
45032
45144
  return value = x;
45033
45145
  }, function(err) {
45034
45146
  return reject(err);
45035
45147
  }, function() {
45036
- return resolve49(value);
45148
+ return resolve50(value);
45037
45149
  });
45038
45150
  });
45039
45151
  };
@@ -47129,11 +47241,11 @@ var require_innerFrom = __commonJS({
47129
47241
  "use strict";
47130
47242
  var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
47131
47243
  function adopt(value) {
47132
- return value instanceof P2 ? value : new P2(function(resolve49) {
47133
- resolve49(value);
47244
+ return value instanceof P2 ? value : new P2(function(resolve50) {
47245
+ resolve50(value);
47134
47246
  });
47135
47247
  }
47136
- return new (P2 || (P2 = Promise))(function(resolve49, reject) {
47248
+ return new (P2 || (P2 = Promise))(function(resolve50, reject) {
47137
47249
  function fulfilled(value) {
47138
47250
  try {
47139
47251
  step(generator.next(value));
@@ -47149,7 +47261,7 @@ var require_innerFrom = __commonJS({
47149
47261
  }
47150
47262
  }
47151
47263
  function step(result) {
47152
- result.done ? resolve49(result.value) : adopt(result.value).then(fulfilled, rejected);
47264
+ result.done ? resolve50(result.value) : adopt(result.value).then(fulfilled, rejected);
47153
47265
  }
47154
47266
  step((generator = generator.apply(thisArg, _arguments || [])).next());
47155
47267
  });
@@ -47231,14 +47343,14 @@ var require_innerFrom = __commonJS({
47231
47343
  }, i);
47232
47344
  function verb(n) {
47233
47345
  i[n] = o[n] && function(v2) {
47234
- return new Promise(function(resolve49, reject) {
47235
- v2 = o[n](v2), settle(resolve49, reject, v2.done, v2.value);
47346
+ return new Promise(function(resolve50, reject) {
47347
+ v2 = o[n](v2), settle(resolve50, reject, v2.done, v2.value);
47236
47348
  });
47237
47349
  };
47238
47350
  }
47239
- function settle(resolve49, reject, d, v2) {
47351
+ function settle(resolve50, reject, d, v2) {
47240
47352
  Promise.resolve(v2).then(function(v3) {
47241
- resolve49({ value: v3, done: d });
47353
+ resolve50({ value: v3, done: d });
47242
47354
  }, reject);
47243
47355
  }
47244
47356
  };
@@ -47857,7 +47969,7 @@ var require_lastValueFrom = __commonJS({
47857
47969
  var EmptyError_1 = require_EmptyError();
47858
47970
  function lastValueFrom2(source, config2) {
47859
47971
  var hasConfig = typeof config2 === "object";
47860
- return new Promise(function(resolve49, reject) {
47972
+ return new Promise(function(resolve50, reject) {
47861
47973
  var _hasValue = false;
47862
47974
  var _value;
47863
47975
  source.subscribe({
@@ -47868,9 +47980,9 @@ var require_lastValueFrom = __commonJS({
47868
47980
  error: reject,
47869
47981
  complete: function() {
47870
47982
  if (_hasValue) {
47871
- resolve49(_value);
47983
+ resolve50(_value);
47872
47984
  } else if (hasConfig) {
47873
- resolve49(config2.defaultValue);
47985
+ resolve50(config2.defaultValue);
47874
47986
  } else {
47875
47987
  reject(new EmptyError_1.EmptyError());
47876
47988
  }
@@ -47892,16 +48004,16 @@ var require_firstValueFrom = __commonJS({
47892
48004
  var Subscriber_1 = require_Subscriber();
47893
48005
  function firstValueFrom(source, config2) {
47894
48006
  var hasConfig = typeof config2 === "object";
47895
- return new Promise(function(resolve49, reject) {
48007
+ return new Promise(function(resolve50, reject) {
47896
48008
  var subscriber = new Subscriber_1.SafeSubscriber({
47897
48009
  next: function(value) {
47898
- resolve49(value);
48010
+ resolve50(value);
47899
48011
  subscriber.unsubscribe();
47900
48012
  },
47901
48013
  error: reject,
47902
48014
  complete: function() {
47903
48015
  if (hasConfig) {
47904
- resolve49(config2.defaultValue);
48016
+ resolve50(config2.defaultValue);
47905
48017
  } else {
47906
48018
  reject(new EmptyError_1.EmptyError());
47907
48019
  }
@@ -53694,14 +53806,14 @@ var require_run_async = __commonJS({
53694
53806
  return function() {
53695
53807
  var args = arguments;
53696
53808
  var originalThis = this;
53697
- var promise = new Promise(function(resolve49, reject) {
53809
+ var promise = new Promise(function(resolve50, reject) {
53698
53810
  var resolved = false;
53699
53811
  const wrappedResolve = function(value) {
53700
53812
  if (resolved) {
53701
53813
  console.warn("Run-async promise already resolved.");
53702
53814
  }
53703
53815
  resolved = true;
53704
- resolve49(value);
53816
+ resolve50(value);
53705
53817
  };
53706
53818
  var rejected = false;
53707
53819
  const wrappedReject = function(value) {
@@ -57213,7 +57325,7 @@ var require_compile = __commonJS({
57213
57325
  const schOrFunc = root.refs[ref];
57214
57326
  if (schOrFunc)
57215
57327
  return schOrFunc;
57216
- let _sch = resolve49.call(this, root, ref);
57328
+ let _sch = resolve50.call(this, root, ref);
57217
57329
  if (_sch === void 0) {
57218
57330
  const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
57219
57331
  const { schemaId } = this.opts;
@@ -57240,7 +57352,7 @@ var require_compile = __commonJS({
57240
57352
  function sameSchemaEnv(s1, s2) {
57241
57353
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
57242
57354
  }
57243
- function resolve49(root, ref) {
57355
+ function resolve50(root, ref) {
57244
57356
  let sch;
57245
57357
  while (typeof (sch = this.refs[ref]) == "string")
57246
57358
  ref = sch;
@@ -57458,8 +57570,8 @@ var require_utils = __commonJS({
57458
57570
  }
57459
57571
  return ind;
57460
57572
  }
57461
- function removeDotSegments(path65) {
57462
- let input = path65;
57573
+ function removeDotSegments(path66) {
57574
+ let input = path66;
57463
57575
  const output = [];
57464
57576
  let nextSlash = -1;
57465
57577
  let len = 0;
@@ -57711,8 +57823,8 @@ var require_schemes = __commonJS({
57711
57823
  wsComponent.secure = void 0;
57712
57824
  }
57713
57825
  if (wsComponent.resourceName) {
57714
- const [path65, query] = wsComponent.resourceName.split("?");
57715
- wsComponent.path = path65 && path65 !== "/" ? path65 : void 0;
57826
+ const [path66, query] = wsComponent.resourceName.split("?");
57827
+ wsComponent.path = path66 && path66 !== "/" ? path66 : void 0;
57716
57828
  wsComponent.query = query;
57717
57829
  wsComponent.resourceName = void 0;
57718
57830
  }
@@ -57871,7 +57983,7 @@ var require_fast_uri = __commonJS({
57871
57983
  }
57872
57984
  return uri;
57873
57985
  }
57874
- function resolve49(baseURI, relativeURI, options) {
57986
+ function resolve50(baseURI, relativeURI, options) {
57875
57987
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
57876
57988
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
57877
57989
  schemelessOptions.skipEscape = true;
@@ -58129,7 +58241,7 @@ var require_fast_uri = __commonJS({
58129
58241
  var fastUri = {
58130
58242
  SCHEMES,
58131
58243
  normalize: normalize3,
58132
- resolve: resolve49,
58244
+ resolve: resolve50,
58133
58245
  resolveComponent,
58134
58246
  equal,
58135
58247
  serialize,
@@ -61105,12 +61217,12 @@ var require_dist = __commonJS({
61105
61217
  throw new Error(`Unknown format "${name}"`);
61106
61218
  return f;
61107
61219
  };
61108
- function addFormats(ajv, list, fs51, exportName) {
61220
+ function addFormats(ajv, list, fs52, exportName) {
61109
61221
  var _a2;
61110
61222
  var _b2;
61111
61223
  (_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
61112
61224
  for (const f of list)
61113
- ajv.addFormat(f, fs51[f]);
61225
+ ajv.addFormat(f, fs52[f]);
61114
61226
  }
61115
61227
  module2.exports = exports2 = formatsPlugin;
61116
61228
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -62394,11 +62506,11 @@ var parser = new YargsParser({
62394
62506
  resolve: import_path2.resolve,
62395
62507
  // TODO: figure out a way to combine ESM and CJS coverage, such that
62396
62508
  // we can exercise all the lines below:
62397
- require: (path65) => {
62509
+ require: (path66) => {
62398
62510
  if (typeof require !== "undefined") {
62399
- return require(path65);
62400
- } else if (path65.match(/\.json$/)) {
62401
- return JSON.parse((0, import_fs2.readFileSync)(path65, "utf8"));
62511
+ return require(path66);
62512
+ } else if (path66.match(/\.json$/)) {
62513
+ return JSON.parse((0, import_fs2.readFileSync)(path66, "utf8"));
62402
62514
  } else {
62403
62515
  throw Error("only .json config files are supported in ESM");
62404
62516
  }
@@ -64924,12 +65036,12 @@ var YargsInstance = class {
64924
65036
  async getCompletion(args, done) {
64925
65037
  argsert("<array> [function]", [args, done], arguments.length);
64926
65038
  if (!done) {
64927
- return new Promise((resolve49, reject) => {
65039
+ return new Promise((resolve50, reject) => {
64928
65040
  __classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
64929
65041
  if (err)
64930
65042
  reject(err);
64931
65043
  else
64932
- resolve49(completions);
65044
+ resolve50(completions);
64933
65045
  });
64934
65046
  });
64935
65047
  } else {
@@ -66218,16 +66330,16 @@ async function handleAgentSkills(options) {
66218
66330
  }
66219
66331
  async function askYesNo(question) {
66220
66332
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
66221
- return new Promise((resolve49) => {
66333
+ return new Promise((resolve50) => {
66222
66334
  process.stderr.write(`${question} `);
66223
66335
  rl.once("line", (answer) => {
66224
66336
  rl.close();
66225
66337
  const trimmed = answer.trim();
66226
66338
  if (trimmed === "") {
66227
- resolve49(true);
66339
+ resolve50(true);
66228
66340
  return;
66229
66341
  }
66230
- resolve49(/^y(es)?$/i.test(trimmed));
66342
+ resolve50(/^y(es)?$/i.test(trimmed));
66231
66343
  });
66232
66344
  });
66233
66345
  }
@@ -66307,7 +66419,7 @@ function handleRemove(argv) {
66307
66419
  }
66308
66420
 
66309
66421
  // src/cli/commands/env.ts
66310
- var path54 = __toESM(require("path"));
66422
+ var path55 = __toESM(require("path"));
66311
66423
 
66312
66424
  // src/cli/finish-command.ts
66313
66425
  init_sync_context();
@@ -67632,13 +67744,13 @@ var PromisePolyfill = class extends Promise {
67632
67744
  // Available starting from Node 22
67633
67745
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
67634
67746
  static withResolver() {
67635
- let resolve49;
67747
+ let resolve50;
67636
67748
  let reject;
67637
67749
  const promise = new Promise((res, rej) => {
67638
- resolve49 = res;
67750
+ resolve50 = res;
67639
67751
  reject = rej;
67640
67752
  });
67641
- return { promise, resolve: resolve49, reject };
67753
+ return { promise, resolve: resolve50, reject };
67642
67754
  }
67643
67755
  };
67644
67756
 
@@ -67655,7 +67767,7 @@ function createPrompt(view) {
67655
67767
  output
67656
67768
  });
67657
67769
  const screen = new ScreenManager(rl);
67658
- const { promise, resolve: resolve49, reject } = PromisePolyfill.withResolver();
67770
+ const { promise, resolve: resolve50, reject } = PromisePolyfill.withResolver();
67659
67771
  const cancel = () => reject(new CancelPromptError());
67660
67772
  if (signal) {
67661
67773
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -67679,7 +67791,7 @@ function createPrompt(view) {
67679
67791
  cycle(() => {
67680
67792
  try {
67681
67793
  const nextView = view(config2, (value) => {
67682
- setImmediate(() => resolve49(value));
67794
+ setImmediate(() => resolve50(value));
67683
67795
  });
67684
67796
  const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
67685
67797
  screen.render(content, bottomContent);
@@ -68666,9 +68778,9 @@ var import_run_async = __toESM(require_run_async(), 1);
68666
68778
  var import_mute_stream2 = __toESM(require_lib(), 1);
68667
68779
  var import_ansi_escapes5 = __toESM(require_ansi_escapes(), 1);
68668
68780
  var _ = {
68669
- set: (obj, path65 = "", value) => {
68781
+ set: (obj, path66 = "", value) => {
68670
68782
  let pointer = obj;
68671
- path65.split(".").forEach((key, index, arr) => {
68783
+ path66.split(".").forEach((key, index, arr) => {
68672
68784
  if (key === "__proto__" || key === "constructor")
68673
68785
  return;
68674
68786
  if (index === arr.length - 1) {
@@ -68679,8 +68791,8 @@ var _ = {
68679
68791
  pointer = pointer[key];
68680
68792
  });
68681
68793
  },
68682
- get: (obj, path65 = "", defaultValue) => {
68683
- const travel = (regexp) => String.prototype.split.call(path65, regexp).filter(Boolean).reduce(
68794
+ get: (obj, path66 = "", defaultValue) => {
68795
+ const travel = (regexp) => String.prototype.split.call(path66, regexp).filter(Boolean).reduce(
68684
68796
  // @ts-expect-error implicit any on res[key]
68685
68797
  (res, key) => res !== null && res !== void 0 ? res[key] : res,
68686
68798
  obj
@@ -68794,7 +68906,7 @@ var PromptsRunner = class {
68794
68906
  throw new Error(`Prompt for type ${question.type} not found`);
68795
68907
  }
68796
68908
  let cleanupSignal;
68797
- const promptFn = isPromptConstructor(prompt2) ? (q, { signal: signal2 } = {}) => new Promise((resolve49, reject) => {
68909
+ const promptFn = isPromptConstructor(prompt2) ? (q, { signal: signal2 } = {}) => new Promise((resolve50, reject) => {
68798
68910
  const rl = import_node_readline.default.createInterface(setupReadlineOptions(this.opt));
68799
68911
  rl.resume();
68800
68912
  const onClose = () => {
@@ -68830,7 +68942,7 @@ var PromptsRunner = class {
68830
68942
  cleanupSignal = void 0;
68831
68943
  };
68832
68944
  }
68833
- activePrompt.run().then(resolve49, reject).finally(cleanup);
68945
+ activePrompt.run().then(resolve50, reject).finally(cleanup);
68834
68946
  }) : prompt2;
68835
68947
  const { signal: moduleSignal } = this.opt;
68836
68948
  if (moduleSignal?.aborted) {
@@ -71185,12 +71297,12 @@ function printAdaptationPrompt(content) {
71185
71297
  }
71186
71298
  function askYesNo2(question) {
71187
71299
  const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
71188
- return new Promise((resolve49) => {
71300
+ return new Promise((resolve50) => {
71189
71301
  process.stderr.write(`${question} `);
71190
71302
  rl.once("line", (answer) => {
71191
71303
  rl.close();
71192
71304
  const trimmed = answer.trim();
71193
- resolve49(trimmed === "" || /^y(es)?$/i.test(trimmed));
71305
+ resolve50(trimmed === "" || /^y(es)?$/i.test(trimmed));
71194
71306
  });
71195
71307
  });
71196
71308
  }
@@ -71279,16 +71391,16 @@ async function promptScaffoldCursorRule(exists) {
71279
71391
  }
71280
71392
  async function askYesNo3(question) {
71281
71393
  const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
71282
- return new Promise((resolve49) => {
71394
+ return new Promise((resolve50) => {
71283
71395
  process.stderr.write(`${question} `);
71284
71396
  rl.once("line", (answer) => {
71285
71397
  rl.close();
71286
71398
  const trimmed = answer.trim();
71287
71399
  if (trimmed === "") {
71288
- resolve49(true);
71400
+ resolve50(true);
71289
71401
  return;
71290
71402
  }
71291
- resolve49(/^y(es)?$/i.test(trimmed));
71403
+ resolve50(/^y(es)?$/i.test(trimmed));
71292
71404
  });
71293
71405
  });
71294
71406
  }
@@ -71728,7 +71840,8 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
71728
71840
  source: options.source,
71729
71841
  sourceUrl: options.sourceUrl,
71730
71842
  title: options.title,
71731
- parentWorkUnitId: options.parentWorkUnitId
71843
+ parentWorkUnitId: options.parentWorkUnitId,
71844
+ relatedLinks: options.relatedLinks
71732
71845
  });
71733
71846
  createWorkAttempt(harnessRoot, {
71734
71847
  attemptId,
@@ -72005,21 +72118,319 @@ var getEnvironmentLogs = defaultRunService.getEnvironmentLogs.bind(defaultRunSer
72005
72118
 
72006
72119
  // src/cli/commands/env.ts
72007
72120
  init_runs();
72121
+ init_work_units();
72122
+ init_manifest();
72123
+ init_slot_status();
72124
+
72125
+ // src/core/cleanup-service.ts
72126
+ var fs46 = __toESM(require("fs"));
72127
+ var os18 = __toESM(require("os"));
72128
+ var path53 = __toESM(require("path"));
72129
+ var import_child_process14 = require("child_process");
72130
+ init_control_sync();
72131
+ init_control_repo_path();
72008
72132
  init_slot_status();
72133
+ init_manifest();
72134
+ var DEFAULT_STALE_DAYS = 7;
72135
+ function getWorktreesRoot() {
72136
+ if (process.env.HAR_WORKTREES_ROOT) {
72137
+ return path53.resolve(process.env.HAR_WORKTREES_ROOT);
72138
+ }
72139
+ return path53.join(process.env.HOME || os18.homedir(), "worktrees");
72140
+ }
72141
+ function runGit3(cwd, args) {
72142
+ try {
72143
+ return (0, import_child_process14.execSync)(`git ${args}`, {
72144
+ cwd,
72145
+ encoding: "utf8",
72146
+ stdio: ["pipe", "pipe", "ignore"]
72147
+ }).trim();
72148
+ } catch {
72149
+ return void 0;
72150
+ }
72151
+ }
72152
+ function basenameRepo(repoPath) {
72153
+ return path53.basename(canonicalizeControlRepoPath(repoPath));
72154
+ }
72155
+ function ageDaysFrom(iso) {
72156
+ if (!iso) return void 0;
72157
+ const created = Date.parse(iso);
72158
+ if (Number.isNaN(created)) return void 0;
72159
+ return Math.floor((Date.now() - created) / (24 * 60 * 60 * 1e3));
72160
+ }
72161
+ function matchesKeep(candidate, keep) {
72162
+ if (!keep?.length) return false;
72163
+ for (const pin of keep) {
72164
+ if (pin.worktreePath && candidate.worktreePath) {
72165
+ if (path53.resolve(pin.worktreePath) === path53.resolve(candidate.worktreePath)) return true;
72166
+ }
72167
+ if (pin.repoPath && pin.agentId !== void 0 && candidate.agentId !== void 0) {
72168
+ const repo = canonicalizeControlRepoPath(pin.repoPath);
72169
+ const candidateRepo = path53.resolve(candidate.repoPath);
72170
+ if ((repo === candidateRepo || path53.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
72171
+ return true;
72172
+ }
72173
+ }
72174
+ if (pin.repoPath && pin.agentId === void 0 && !pin.worktreePath) {
72175
+ if (canonicalizeControlRepoPath(pin.repoPath) === candidate.repoPath) return true;
72176
+ }
72177
+ }
72178
+ return false;
72179
+ }
72180
+ function classifySlotCandidate(repoPath, projectName, slot, options) {
72181
+ if (!slot.active && !slot.worktreePath) return void 0;
72182
+ const candidate = {
72183
+ kind: "active_slot",
72184
+ repoPath,
72185
+ projectName,
72186
+ agentId: slot.agentId,
72187
+ worktreePath: slot.worktreePath ?? slot.workDir,
72188
+ branch: slot.branch,
72189
+ active: slot.active,
72190
+ dirty: slot.dirty,
72191
+ ageDays: ageDaysFrom(slot.sessionCreatedAt),
72192
+ sessionCreatedAt: slot.sessionCreatedAt,
72193
+ recommendation: "review",
72194
+ reason: "active session"
72195
+ };
72196
+ if (matchesKeep(candidate, options?.keep)) {
72197
+ candidate.recommendation = "keep";
72198
+ candidate.reason = "pinned with --keep";
72199
+ return candidate;
72200
+ }
72201
+ if (slot.dirty) {
72202
+ candidate.recommendation = "review";
72203
+ candidate.reason = "uncommitted changes \u2014 review before teardown";
72204
+ return candidate;
72205
+ }
72206
+ if (slot.sessionStatus === "failed" || slot.sessionStatus === "starting") {
72207
+ candidate.recommendation = "review";
72208
+ candidate.reason = "failed or resumable session \u2014 recover or teardown manually";
72209
+ return candidate;
72210
+ }
72211
+ const staleDays = options?.staleDays ?? DEFAULT_STALE_DAYS;
72212
+ const age = candidate.ageDays;
72213
+ if (age !== void 0 && age >= staleDays) {
72214
+ candidate.recommendation = "teardown";
72215
+ candidate.reason = `idle ${age}d, clean`;
72216
+ return candidate;
72217
+ }
72218
+ if (slot.active) {
72219
+ candidate.recommendation = "review";
72220
+ candidate.reason = age !== void 0 ? `active session (${age}d) \u2014 keep unless finished` : "active session \u2014 keep unless finished";
72221
+ }
72222
+ return candidate;
72223
+ }
72224
+ function resolveRepoForWorktree(worktreePath) {
72225
+ if (!fs46.existsSync(worktreePath)) return void 0;
72226
+ const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
72227
+ if (!commonDir) return void 0;
72228
+ const gitRoot = path53.resolve(worktreePath, commonDir, "..");
72229
+ if (!readManifest(gitRoot)) return void 0;
72230
+ return canonicalizeControlRepoPath(gitRoot);
72231
+ }
72232
+ function discoverOrphanWorktrees(knownPaths) {
72233
+ const worktreesRoot = getWorktreesRoot();
72234
+ if (!fs46.existsSync(worktreesRoot)) return [];
72235
+ const orphans = [];
72236
+ for (const entry of fs46.readdirSync(worktreesRoot, { withFileTypes: true })) {
72237
+ if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
72238
+ const worktreePath = path53.resolve(path53.join(worktreesRoot, entry.name));
72239
+ if (knownPaths.has(worktreePath)) continue;
72240
+ const repoPath = resolveRepoForWorktree(worktreePath) ?? worktreesRoot;
72241
+ const porcelain = runGit3(worktreePath, "status --porcelain");
72242
+ const dirty = porcelain !== void 0 ? porcelain.length > 0 : void 0;
72243
+ const branch = runGit3(worktreePath, "rev-parse --abbrev-ref HEAD");
72244
+ orphans.push({
72245
+ kind: "orphan_worktree",
72246
+ repoPath,
72247
+ projectName: basenameRepo(repoPath),
72248
+ worktreePath,
72249
+ branch: branch && branch !== "HEAD" ? branch : void 0,
72250
+ active: false,
72251
+ dirty,
72252
+ recommendation: dirty ? "review" : "remove_orphan",
72253
+ reason: dirty ? "orphan worktree with uncommitted changes" : "orphan worktree \u2014 no slot registry"
72254
+ });
72255
+ }
72256
+ return orphans.sort((a, b2) => (a.worktreePath ?? "").localeCompare(b2.worktreePath ?? ""));
72257
+ }
72258
+ async function discoverCleanupCandidates(options = {}) {
72259
+ const repoPaths = options.repoPaths ?? await discoverHarRepos({ cwd: options.cwd ?? process.cwd() });
72260
+ const candidates = [];
72261
+ const knownWorktreePaths = /* @__PURE__ */ new Set();
72262
+ for (const repoPath of repoPaths) {
72263
+ if (!fs46.existsSync(repoPath) || !readManifest(repoPath)) continue;
72264
+ const harnessRoot = resolveHarnessRoot(repoPath);
72265
+ const canonicalRepo = canonicalizeControlRepoPath(harnessRoot);
72266
+ const status = collectEnvironmentStatus(harnessRoot);
72267
+ const projectName = basenameRepo(harnessRoot);
72268
+ for (const slot of status.slots) {
72269
+ if (slot.worktreePath) knownWorktreePaths.add(path53.resolve(slot.worktreePath));
72270
+ if (slot.workDir) knownWorktreePaths.add(path53.resolve(slot.workDir));
72271
+ const candidate = classifySlotCandidate(canonicalRepo, projectName, slot, {
72272
+ staleDays: options.staleDays,
72273
+ keep: options.keep
72274
+ });
72275
+ if (!candidate) continue;
72276
+ if (candidate.recommendation === "review" && !options.includeReview) {
72277
+ }
72278
+ candidates.push(candidate);
72279
+ }
72280
+ }
72281
+ if (options.orphans !== false) {
72282
+ for (const orphan of discoverOrphanWorktrees(knownWorktreePaths)) {
72283
+ if (matchesKeep(orphan, options.keep)) {
72284
+ orphan.recommendation = "keep";
72285
+ orphan.reason = "pinned with --keep";
72286
+ }
72287
+ candidates.push(orphan);
72288
+ }
72289
+ }
72290
+ return {
72291
+ candidates: candidates.sort((a, b2) => {
72292
+ const repo = a.repoPath.localeCompare(b2.repoPath);
72293
+ if (repo !== 0) return repo;
72294
+ return (a.agentId ?? 0) - (b2.agentId ?? 0);
72295
+ }),
72296
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
72297
+ };
72298
+ }
72299
+ function selectAutoApprovedCandidates(plan, options) {
72300
+ return plan.candidates.filter((candidate) => {
72301
+ if (candidate.recommendation === "keep") return false;
72302
+ if (candidate.recommendation === "review") return options?.includeReview === true;
72303
+ return candidate.recommendation === "teardown" || candidate.recommendation === "remove_orphan";
72304
+ });
72305
+ }
72306
+ function formatCleanupPlan(plan) {
72307
+ if (plan.candidates.length === 0) {
72308
+ return "No session worktrees or orphans found.";
72309
+ }
72310
+ const lines2 = [];
72311
+ lines2.push(
72312
+ `${"REC".padEnd(8)} ${"REPO".padEnd(18)} ${"SLOT".padEnd(6)} ${"AGE".padEnd(5)} WORKTREE / REASON`
72313
+ );
72314
+ lines2.push("-".repeat(100));
72315
+ for (const candidate of plan.candidates) {
72316
+ const slot = candidate.agentId !== void 0 ? String(candidate.agentId) : "-";
72317
+ const age = candidate.ageDays !== void 0 ? `${candidate.ageDays}d` : "-";
72318
+ const target = candidate.worktreePath ?? candidate.repoPath;
72319
+ lines2.push(
72320
+ `${candidate.recommendation.padEnd(8)} ${candidate.projectName.padEnd(18)} ${slot.padEnd(6)} ${age.padEnd(5)} ${target}`
72321
+ );
72322
+ lines2.push(` ${candidate.reason}`);
72323
+ }
72324
+ return lines2.join("\n");
72325
+ }
72326
+ async function askYesNo4(question) {
72327
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
72328
+ const readline8 = await import("readline");
72329
+ const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
72330
+ const answer = await new Promise((resolve50) => {
72331
+ rl.question(question, resolve50);
72332
+ });
72333
+ rl.close();
72334
+ return /^[Yy]$/.test(answer.trim());
72335
+ }
72336
+ async function confirmCleanupSelection(candidates) {
72337
+ if (candidates.length === 0) return [];
72338
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
72339
+ throw new Error("Non-interactive terminal \u2014 pass --yes (and optionally --include-review)");
72340
+ }
72341
+ const approved = [];
72342
+ for (const candidate of candidates) {
72343
+ if (candidate.recommendation === "keep") continue;
72344
+ const label = candidate.kind === "orphan_worktree" ? `orphan ${candidate.worktreePath}` : `${candidate.projectName} agent ${candidate.agentId}`;
72345
+ const action = candidate.recommendation === "remove_orphan" ? "remove" : "teardown";
72346
+ const ok = await askYesNo4(`${action} ${label}? [${candidate.recommendation === "teardown" || candidate.recommendation === "remove_orphan" ? "Y" : "y"}/n] `);
72347
+ if (ok) approved.push(candidate);
72348
+ }
72349
+ return approved;
72350
+ }
72351
+ async function executeCleanupCandidates(candidates, options = {}) {
72352
+ const service = createRunService();
72353
+ const outcomes = [];
72354
+ for (const candidate of candidates) {
72355
+ if (candidate.recommendation === "keep") continue;
72356
+ if (options.dryRun) {
72357
+ outcomes.push({ candidate, ok: true });
72358
+ continue;
72359
+ }
72360
+ try {
72361
+ if (candidate.kind === "active_slot" && candidate.agentId !== void 0) {
72362
+ const result = await service.teardownEnvironment({
72363
+ repoPath: candidate.repoPath,
72364
+ agentId: candidate.agentId,
72365
+ capture: false,
72366
+ trigger: "cli"
72367
+ });
72368
+ outcomes.push({
72369
+ candidate,
72370
+ ok: result.code === 0,
72371
+ error: result.code === 0 ? void 0 : result.stderr?.trim() || `exit ${result.code}`
72372
+ });
72373
+ continue;
72374
+ }
72375
+ if (candidate.kind === "orphan_worktree" && candidate.worktreePath) {
72376
+ if (fs46.existsSync(candidate.worktreePath)) {
72377
+ const repoRoot = candidate.repoPath !== getWorktreesRoot() ? candidate.repoPath : resolveRepoForWorktree(candidate.worktreePath);
72378
+ if (repoRoot) {
72379
+ try {
72380
+ (0, import_child_process14.execSync)(`git worktree remove --force ${JSON.stringify(candidate.worktreePath)}`, {
72381
+ cwd: repoRoot,
72382
+ stdio: ["pipe", "pipe", "ignore"]
72383
+ });
72384
+ } catch {
72385
+ }
72386
+ }
72387
+ if (fs46.existsSync(candidate.worktreePath)) {
72388
+ fs46.rmSync(candidate.worktreePath, { recursive: true, force: true });
72389
+ }
72390
+ }
72391
+ outcomes.push({ candidate, ok: true });
72392
+ continue;
72393
+ }
72394
+ outcomes.push({ candidate, ok: false, error: "unsupported candidate" });
72395
+ } catch (err) {
72396
+ outcomes.push({
72397
+ candidate,
72398
+ ok: false,
72399
+ error: err instanceof Error ? err.message : String(err)
72400
+ });
72401
+ }
72402
+ }
72403
+ return outcomes;
72404
+ }
72405
+ function parseCleanupKeepPins(values) {
72406
+ if (!values?.length) return [];
72407
+ return values.map((raw) => {
72408
+ const agentMatch = raw.match(/^(.+):(\d+)$/);
72409
+ if (agentMatch) {
72410
+ return { repoPath: agentMatch[1], agentId: Number(agentMatch[2]) };
72411
+ }
72412
+ if (raw.startsWith("/") || raw.startsWith("~")) {
72413
+ return {
72414
+ worktreePath: raw.startsWith("~") ? path53.join(process.env.HOME || os18.homedir(), raw.slice(2)) : path53.resolve(raw)
72415
+ };
72416
+ }
72417
+ return { repoPath: raw };
72418
+ });
72419
+ }
72009
72420
 
72010
72421
  // src/core/commit-gate-onboarding.ts
72011
72422
  var readline7 = __toESM(require("readline"));
72012
72423
  init_hooks();
72013
72424
  init_stages();
72014
72425
  init_logging();
72015
- function askYesNo4(question) {
72426
+ function askYesNo5(question) {
72016
72427
  const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
72017
- return new Promise((resolve49) => {
72428
+ return new Promise((resolve50) => {
72018
72429
  process.stderr.write(`${question} `);
72019
72430
  rl.once("line", (answer) => {
72020
72431
  rl.close();
72021
72432
  const trimmed = answer.trim();
72022
- resolve49(trimmed === "" || /^y(es)?$/i.test(trimmed));
72433
+ resolve50(trimmed === "" || /^y(es)?$/i.test(trimmed));
72023
72434
  });
72024
72435
  });
72025
72436
  }
@@ -72044,7 +72455,7 @@ async function handleCommitGateOnboarding(options) {
72044
72455
  const status = getHooksStatus(options.repoPath);
72045
72456
  let shouldInstall = status.preCommitInstalled || status.postCommitInstalled || options.install === "always" || options.autoYes === true;
72046
72457
  if (!shouldInstall && options.install === "prompt" && process.stdin.isTTY && process.stdout.isTTY) {
72047
- shouldInstall = await askYesNo4("Install the HAR commit gate for this repository? [Y/n]");
72458
+ shouldInstall = await askYesNo5("Install the HAR commit gate for this repository? [Y/n]");
72048
72459
  }
72049
72460
  if (!shouldInstall) {
72050
72461
  info("Commit gate is not installed; run `har hooks install` when ready.");
@@ -72061,21 +72472,21 @@ async function handleCommitGateOnboarding(options) {
72061
72472
  }
72062
72473
 
72063
72474
  // src/core/onboarding-preferences.ts
72064
- var fs46 = __toESM(require("fs"));
72065
- var os18 = __toESM(require("os"));
72066
- var path53 = __toESM(require("path"));
72475
+ var fs47 = __toESM(require("fs"));
72476
+ var os19 = __toESM(require("os"));
72477
+ var path54 = __toESM(require("path"));
72067
72478
  init_schema2();
72068
72479
  function getOnboardingPreferencesPath() {
72069
72480
  if (process.env.HAR_PREFERENCES_PATH) {
72070
- return path53.resolve(process.env.HAR_PREFERENCES_PATH);
72481
+ return path54.resolve(process.env.HAR_PREFERENCES_PATH);
72071
72482
  }
72072
- return path53.join(os18.homedir(), ".har", "preferences.json");
72483
+ return path54.join(os19.homedir(), ".har", "preferences.json");
72073
72484
  }
72074
72485
  function readOnboardingPreferences() {
72075
72486
  const preferencePath = getOnboardingPreferencesPath();
72076
72487
  try {
72077
- if (!fs46.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
72078
- return OnboardingPreferencesSchema.parse(JSON.parse(fs46.readFileSync(preferencePath, "utf8")));
72488
+ if (!fs47.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
72489
+ return OnboardingPreferencesSchema.parse(JSON.parse(fs47.readFileSync(preferencePath, "utf8")));
72079
72490
  } catch {
72080
72491
  return OnboardingPreferencesSchema.parse({});
72081
72492
  }
@@ -72100,8 +72511,8 @@ function writeOnboardingPreferences(overrides) {
72100
72511
  };
72101
72512
  const parsed = OnboardingPreferencesSchema.parse(preference);
72102
72513
  const preferencePath = getOnboardingPreferencesPath();
72103
- fs46.mkdirSync(path53.dirname(preferencePath), { recursive: true });
72104
- fs46.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
72514
+ fs47.mkdirSync(path54.dirname(preferencePath), { recursive: true });
72515
+ fs47.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
72105
72516
  `);
72106
72517
  return parsed;
72107
72518
  }
@@ -72165,6 +72576,14 @@ feature branch.
72165
72576
  Failed launch: har env recover 1 # or: har env launch 1 --resume`;
72166
72577
 
72167
72578
  // src/cli/commands/env.ts
72579
+ var workLinkOptions = (y) => y.option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("work-id", {
72580
+ type: "string",
72581
+ demandOption: true,
72582
+ describe: "Repo-scoped work unit id (same as --work-id at launch)"
72583
+ }).option("link", {
72584
+ type: "string",
72585
+ describe: "Link as source|url or source|url|label"
72586
+ }).option("source", { type: "string", describe: "Tracker provider (e.g. github, jira)" }).option("url", { type: "string", describe: "Canonical URL for the link" }).option("label", { type: "string", describe: "Optional display label" });
72168
72587
  var envCommand = {
72169
72588
  command: "env <subcommand>",
72170
72589
  describe: "Manage agent environments (launch \u2192 verify \u2192 complete)",
@@ -72324,8 +72743,17 @@ var envCommand = {
72324
72743
  }).option("parent-work-id", {
72325
72744
  type: "string",
72326
72745
  describe: "Optional parent work unit identifier"
72746
+ }).option("work-link", {
72747
+ type: "array",
72748
+ string: true,
72749
+ describe: "Additional tracker link: source|url or source|url|label (repeatable)"
72327
72750
  }).epilog(LAUNCH_EPILOG),
72328
72751
  handleLaunch
72752
+ ).command(
72753
+ "work-link",
72754
+ "Append a related external link to an existing work unit",
72755
+ workLinkOptions,
72756
+ handleWorkLink
72329
72757
  ).command(
72330
72758
  "recover <id>",
72331
72759
  "Resume a failed or partial launch (alias for launch --resume)",
@@ -72364,6 +72792,38 @@ var envCommand = {
72364
72792
  "Show status of all running agents",
72365
72793
  (y) => y.option("repo", { type: "string", default: "." }).option("json", { type: "boolean", default: false, describe: "Structured JSON output" }),
72366
72794
  handleStatus
72795
+ ).command(
72796
+ "cleanup",
72797
+ "Discover stale session worktrees across registered repos and tear them down",
72798
+ (y) => y.option("repo", {
72799
+ type: "string",
72800
+ describe: "Limit cleanup scan to one repository path"
72801
+ }).option("dry-run", {
72802
+ type: "boolean",
72803
+ default: false,
72804
+ describe: "Show the cleanup plan without executing"
72805
+ }).option("yes", {
72806
+ alias: "y",
72807
+ type: "boolean",
72808
+ default: false,
72809
+ describe: "Approve teardown/remove for recommended rows without prompting"
72810
+ }).option("keep", {
72811
+ type: "string",
72812
+ describe: "Pin sessions to keep (comma-separated repoPath:agentId or worktree paths)"
72813
+ }).option("stale", {
72814
+ type: "number",
72815
+ default: 7,
72816
+ describe: "Age in days before a clean idle session is recommended for teardown"
72817
+ }).option("orphans", {
72818
+ type: "boolean",
72819
+ default: true,
72820
+ describe: "Include orphan worktree directories under ~/worktrees"
72821
+ }).option("include-review", {
72822
+ type: "boolean",
72823
+ default: false,
72824
+ describe: "With --yes, also teardown/remove rows marked review (dirty or recent active)"
72825
+ }).option("json", { type: "boolean", default: false, describe: "Structured JSON output" }),
72826
+ handleCleanup
72367
72827
  ).command(
72368
72828
  "runs",
72369
72829
  "Inspect harness run history",
@@ -72386,13 +72846,13 @@ var envCommand = {
72386
72846
  }
72387
72847
  ).demandCommand(
72388
72848
  1,
72389
- "Please specify a subcommand: init, maintain, add-stage, launch, recover, verify, complete, teardown, status, runs"
72849
+ "Please specify a subcommand: init, maintain, add-stage, launch, recover, verify, complete, teardown, status, cleanup, runs"
72390
72850
  ).epilog(HAR_ENV_EPILOG),
72391
72851
  handler: () => {
72392
72852
  }
72393
72853
  };
72394
72854
  async function handleInit(argv) {
72395
- const repoPath = path54.resolve(argv.repo);
72855
+ const repoPath = path55.resolve(argv.repo);
72396
72856
  const onboarding = resolveOnboardingOptions(argv);
72397
72857
  header("har env init");
72398
72858
  info(`Repository: ${repoPath}`);
@@ -72438,7 +72898,7 @@ async function handleInit(argv) {
72438
72898
  }
72439
72899
  }
72440
72900
  async function handleMaintain(argv) {
72441
- const repoPath = path54.resolve(argv.repo);
72901
+ const repoPath = path55.resolve(argv.repo);
72442
72902
  const onboarding = resolveOnboardingOptions(argv);
72443
72903
  header("har env maintain");
72444
72904
  info(`Repository: ${repoPath}`);
@@ -72569,7 +73029,7 @@ async function applyAgentIntegrations(options) {
72569
73029
  }
72570
73030
  }
72571
73031
  async function handleAddPlugin(argv) {
72572
- const repoPath = path54.resolve(argv.repo);
73032
+ const repoPath = path55.resolve(argv.repo);
72573
73033
  const available = listPluginIds();
72574
73034
  if (argv.list) {
72575
73035
  for (const id of available) {
@@ -72609,7 +73069,7 @@ async function handleAddPlugin(argv) {
72609
73069
  }
72610
73070
  }
72611
73071
  async function handleAddStage(argv) {
72612
- const repoPath = path54.resolve(argv.repo);
73072
+ const repoPath = path55.resolve(argv.repo);
72613
73073
  const available = listPluginIds();
72614
73074
  if (argv.list) {
72615
73075
  warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
@@ -72675,7 +73135,7 @@ async function handleAddStage(argv) {
72675
73135
  });
72676
73136
  }
72677
73137
  async function handlePreflight(argv) {
72678
- const repo = path54.resolve(argv.repo);
73138
+ const repo = path55.resolve(argv.repo);
72679
73139
  const agentId = validateAgentId(argv.id, repo);
72680
73140
  const result = await preflightEnvironment({
72681
73141
  repoPath: repo,
@@ -72691,7 +73151,7 @@ async function handlePreflight(argv) {
72691
73151
  return finishCommand(result.code);
72692
73152
  }
72693
73153
  async function handleLaunch(argv) {
72694
- const repo = path54.resolve(argv.repo);
73154
+ const repo = path55.resolve(argv.repo);
72695
73155
  const agentId = validateAgentId(argv.id, repo);
72696
73156
  if (!argv.resume) {
72697
73157
  const guard = checkLaunchGuard2(repo, agentId, { worktree: argv.worktree });
@@ -72714,6 +73174,7 @@ async function handleLaunch(argv) {
72714
73174
  sourceUrl: argv.workUrl,
72715
73175
  title: argv.workTitle,
72716
73176
  parentWorkUnitId: argv.parentWorkId,
73177
+ relatedLinks: argv.workLink?.map(parseWorkLinkSpec),
72717
73178
  capture: false
72718
73179
  });
72719
73180
  if (result.blocked) {
@@ -72734,6 +73195,22 @@ async function handleLaunch(argv) {
72734
73195
  }
72735
73196
  return finishCommand(result.code);
72736
73197
  }
73198
+ async function handleWorkLink(argv) {
73199
+ if (!argv.link && !(argv.source && argv.url)) {
73200
+ error("Provide --link or both --source and --url");
73201
+ return finishCommand(1);
73202
+ }
73203
+ const harnessRoot = resolveHarnessRoot(path55.resolve(argv.repo));
73204
+ const links = argv.link ? [parseWorkLinkSpec(argv.link)] : [{ source: argv.source, url: argv.url, label: argv.label }];
73205
+ try {
73206
+ const record2 = addWorkUnitLinks(harnessRoot, argv.workId, links);
73207
+ success(`Added link to work unit ${record2.workUnitId}`);
73208
+ return finishCommand(0);
73209
+ } catch (err) {
73210
+ error(err instanceof Error ? err.message : String(err));
73211
+ return finishCommand(1);
73212
+ }
73213
+ }
72737
73214
  async function handleRecover(argv) {
72738
73215
  return handleLaunch({
72739
73216
  id: argv.id,
@@ -72749,7 +73226,7 @@ async function handleRecover(argv) {
72749
73226
  });
72750
73227
  }
72751
73228
  async function handleVerify(argv) {
72752
- const repo = path54.resolve(argv.repo);
73229
+ const repo = path55.resolve(argv.repo);
72753
73230
  const agentId = validateAgentId(argv.id, repo);
72754
73231
  const result = await runVerification({
72755
73232
  repoPath: repo,
@@ -72761,7 +73238,7 @@ async function handleVerify(argv) {
72761
73238
  return finishCommand(result.code);
72762
73239
  }
72763
73240
  async function handleTeardown(argv) {
72764
- const repo = path54.resolve(argv.repo);
73241
+ const repo = path55.resolve(argv.repo);
72765
73242
  const agentId = validateAgentId(argv.id, repo);
72766
73243
  const result = await teardownEnvironment({
72767
73244
  repoPath: repo,
@@ -72772,7 +73249,7 @@ async function handleTeardown(argv) {
72772
73249
  return finishCommand(result.code);
72773
73250
  }
72774
73251
  async function handleComplete(argv) {
72775
- const repo = path54.resolve(argv.repo);
73252
+ const repo = path55.resolve(argv.repo);
72776
73253
  const agentId = validateAgentId(argv.id, repo);
72777
73254
  const result = await completeEnvironment({
72778
73255
  repoPath: repo,
@@ -72793,7 +73270,7 @@ async function handleComplete(argv) {
72793
73270
  return finishCommand(result.code);
72794
73271
  }
72795
73272
  async function handleStatus(argv) {
72796
- const repoPath = path54.resolve(argv.repo);
73273
+ const repoPath = path55.resolve(argv.repo);
72797
73274
  if (argv.json) {
72798
73275
  const status = collectEnvironmentStatus(repoPath);
72799
73276
  const output = EnvironmentStatusSchema.parse(status);
@@ -72805,8 +73282,59 @@ async function handleStatus(argv) {
72805
73282
  capture: false
72806
73283
  });
72807
73284
  }
73285
+ async function handleCleanup(argv) {
73286
+ const keepValues = argv.keep?.split(",").map((value) => value.trim()).filter(Boolean);
73287
+ const keep = parseCleanupKeepPins(keepValues);
73288
+ const repoPaths = argv.repo ? [path55.resolve(argv.repo)] : void 0;
73289
+ const plan = await discoverCleanupCandidates({
73290
+ cwd: process.cwd(),
73291
+ repoPaths,
73292
+ keep,
73293
+ staleDays: argv.stale,
73294
+ orphans: argv.orphans
73295
+ });
73296
+ if (argv.json) {
73297
+ process.stdout.write(JSON.stringify(plan, null, 2) + "\n");
73298
+ if (argv.dryRun) return;
73299
+ } else {
73300
+ header("har env cleanup");
73301
+ process.stdout.write(`${formatCleanupPlan(plan)}
73302
+
73303
+ `);
73304
+ if (argv.dryRun) {
73305
+ info("Dry run \u2014 no changes made.");
73306
+ return;
73307
+ }
73308
+ }
73309
+ let selected = selectAutoApprovedCandidates(plan, { includeReview: argv.includeReview });
73310
+ if (!argv.yes) {
73311
+ try {
73312
+ const interactive = await confirmCleanupSelection(plan.candidates);
73313
+ selected = interactive;
73314
+ } catch (err) {
73315
+ error(err instanceof Error ? err.message : String(err));
73316
+ return finishCommand(1);
73317
+ }
73318
+ }
73319
+ if (selected.length === 0) {
73320
+ info("Nothing selected for cleanup.");
73321
+ return;
73322
+ }
73323
+ const outcomes = await executeCleanupCandidates(selected, { dryRun: false });
73324
+ let failed = 0;
73325
+ for (const outcome of outcomes) {
73326
+ const label = outcome.candidate.kind === "orphan_worktree" ? outcome.candidate.worktreePath : `${outcome.candidate.projectName} agent ${outcome.candidate.agentId}`;
73327
+ if (outcome.ok) {
73328
+ success(`Cleaned ${label}`);
73329
+ } else {
73330
+ failed++;
73331
+ error(`${label}: ${outcome.error ?? "failed"}`);
73332
+ }
73333
+ }
73334
+ return finishCommand(failed > 0 ? 1 : 0);
73335
+ }
72808
73336
  async function handleRunsList(argv) {
72809
- const repoPath = path54.resolve(argv.repo);
73337
+ const repoPath = path55.resolve(argv.repo);
72810
73338
  const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
72811
73339
  if (argv.json) {
72812
73340
  process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
@@ -72823,7 +73351,7 @@ async function handleRunsList(argv) {
72823
73351
  }
72824
73352
  }
72825
73353
  async function handleRunsGet(argv) {
72826
- const run2 = getRun(path54.resolve(argv.repo), argv.runId);
73354
+ const run2 = getRun(path55.resolve(argv.repo), argv.runId);
72827
73355
  if (!run2) {
72828
73356
  error(`Run not found: ${argv.runId}`);
72829
73357
  return finishCommand(1);
@@ -72905,27 +73433,27 @@ function printNextSteps() {
72905
73433
  }
72906
73434
 
72907
73435
  // src/cli/commands/control.ts
72908
- var path58 = __toESM(require("path"));
73436
+ var path59 = __toESM(require("path"));
72909
73437
  init_control_config();
72910
73438
  init_control_port();
72911
73439
  init_control_sync();
72912
73440
 
72913
73441
  // src/core/control-sync-selection.ts
72914
- var fs47 = __toESM(require("fs"));
72915
- var os19 = __toESM(require("os"));
72916
- var path55 = __toESM(require("path"));
73442
+ var fs48 = __toESM(require("fs"));
73443
+ var os20 = __toESM(require("os"));
73444
+ var path56 = __toESM(require("path"));
72917
73445
  init_control_repo_path();
72918
73446
  function getSelectionPath() {
72919
73447
  if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
72920
- return path55.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
73448
+ return path56.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
72921
73449
  }
72922
- return path55.join(os19.homedir(), ".har", "sync-selection.json");
73450
+ return path56.join(os20.homedir(), ".har", "sync-selection.json");
72923
73451
  }
72924
73452
  function readSyncSelection() {
72925
73453
  const selectionPath = getSelectionPath();
72926
73454
  try {
72927
- if (!fs47.existsSync(selectionPath)) return null;
72928
- const parsed = JSON.parse(fs47.readFileSync(selectionPath, "utf8"));
73455
+ if (!fs48.existsSync(selectionPath)) return null;
73456
+ const parsed = JSON.parse(fs48.readFileSync(selectionPath, "utf8"));
72929
73457
  if (!Array.isArray(parsed.repos)) return null;
72930
73458
  return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
72931
73459
  } catch {
@@ -72935,8 +73463,8 @@ function readSyncSelection() {
72935
73463
  function writeSyncSelection(repos) {
72936
73464
  const selectionPath = getSelectionPath();
72937
73465
  const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
72938
- fs47.mkdirSync(path55.dirname(selectionPath), { recursive: true });
72939
- fs47.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
73466
+ fs48.mkdirSync(path56.dirname(selectionPath), { recursive: true });
73467
+ fs48.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
72940
73468
  }
72941
73469
  function resolveSyncSelection(input) {
72942
73470
  const { discovered, stored, forceSelect, isTTY } = input;
@@ -72968,13 +73496,13 @@ init_portal_credentials();
72968
73496
  // src/core/portal-login.ts
72969
73497
  var http = __toESM(require("http"));
72970
73498
  var import_crypto = require("crypto");
72971
- var import_child_process14 = require("child_process");
73499
+ var import_child_process15 = require("child_process");
72972
73500
  var CALLBACK_PATH = "/callback";
72973
73501
  var LOGIN_TIMEOUT_MS = 3 * 6e4;
72974
73502
  function openBrowser(url) {
72975
73503
  const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
72976
73504
  try {
72977
- const child = (0, import_child_process14.spawn)(cmd, args, { stdio: "ignore", detached: true });
73505
+ const child = (0, import_child_process15.spawn)(cmd, args, { stdio: "ignore", detached: true });
72978
73506
  child.on("error", () => {
72979
73507
  });
72980
73508
  child.unref();
@@ -72983,7 +73511,7 @@ function openBrowser(url) {
72983
73511
  }
72984
73512
  async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
72985
73513
  const state = (0, import_crypto.randomUUID)();
72986
- return new Promise((resolve49, reject) => {
73514
+ return new Promise((resolve50, reject) => {
72987
73515
  let timer;
72988
73516
  const server = http.createServer((req, res) => {
72989
73517
  const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
@@ -73008,7 +73536,7 @@ async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
73008
73536
  res.writeHead(200, { "Content-Type": "text/html" });
73009
73537
  res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
73010
73538
  cleanup();
73011
- resolve49({
73539
+ resolve50({
73012
73540
  portalUrl,
73013
73541
  token,
73014
73542
  workspace,
@@ -73043,8 +73571,8 @@ If your browser did not open, paste that URL.
73043
73571
  }
73044
73572
 
73045
73573
  // src/core/control-unregister.ts
73046
- var fs48 = __toESM(require("fs"));
73047
- var path56 = __toESM(require("path"));
73574
+ var fs49 = __toESM(require("fs"));
73575
+ var path57 = __toESM(require("path"));
73048
73576
  init_control_repo_path();
73049
73577
  init_control_registry();
73050
73578
  init_control_config();
@@ -73054,9 +73582,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
73054
73582
  const harnessRoot = canonicalizeControlRepoPath(repoPath);
73055
73583
  const byPath = /* @__PURE__ */ new Map();
73056
73584
  const add = (partial2) => {
73057
- const resolved = path56.resolve(partial2.worktreePath);
73585
+ const resolved = path57.resolve(partial2.worktreePath);
73058
73586
  if (!resolved || resolved === harnessRoot) return;
73059
- const exists = partial2.exists ?? fs48.existsSync(resolved);
73587
+ const exists = partial2.exists ?? fs49.existsSync(resolved);
73060
73588
  const prev = byPath.get(resolved);
73061
73589
  if (prev) {
73062
73590
  byPath.set(resolved, {
@@ -73103,12 +73631,12 @@ function listUnregisterWorktreeCandidates(repoPath) {
73103
73631
  }
73104
73632
  return [...byPath.values()].sort((a, b2) => a.agentId - b2.agentId);
73105
73633
  }
73106
- async function askYesNo5(question) {
73634
+ async function askYesNo6(question) {
73107
73635
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
73108
73636
  const readline8 = await import("readline");
73109
73637
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
73110
- const answer = await new Promise((resolve49) => {
73111
- rl.question(question, resolve49);
73638
+ const answer = await new Promise((resolve50) => {
73639
+ rl.question(question, resolve50);
73112
73640
  });
73113
73641
  rl.close();
73114
73642
  return /^[Yy]$/.test(answer.trim());
@@ -73120,7 +73648,7 @@ async function confirmUnregister(options) {
73120
73648
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
73121
73649
  throw new Error("Non-interactive terminal \u2014 pass --yes (and optionally --delete-worktrees)");
73122
73650
  }
73123
- const proceed = await askYesNo5("Unregister this repository from Mission Control? [y/N] ");
73651
+ const proceed = await askYesNo6("Unregister this repository from Mission Control? [y/N] ");
73124
73652
  if (!proceed) return { proceed: false, deleteWorktrees: false };
73125
73653
  const existing = options.worktrees.filter((w2) => w2.exists);
73126
73654
  if (existing.length === 0) {
@@ -73132,7 +73660,7 @@ async function confirmUnregister(options) {
73132
73660
  process.stderr.write(` agent-${wt.agentId}: ${wt.worktreePath}${dirty}
73133
73661
  `);
73134
73662
  }
73135
- const deleteWorktrees = await askYesNo5(
73663
+ const deleteWorktrees = await askYesNo6(
73136
73664
  `Also delete ${existing.length} session worktree(s) on disk? [y/N] `
73137
73665
  );
73138
73666
  return { proceed: true, deleteWorktrees };
@@ -73170,28 +73698,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
73170
73698
  trigger: "cli"
73171
73699
  });
73172
73700
  if (result.code !== 0) {
73173
- if (fs48.existsSync(candidate.worktreePath)) {
73174
- fs48.rmSync(candidate.worktreePath, { recursive: true, force: true });
73701
+ if (fs49.existsSync(candidate.worktreePath)) {
73702
+ fs49.rmSync(candidate.worktreePath, { recursive: true, force: true });
73175
73703
  }
73176
73704
  }
73177
73705
  outcomes.push({
73178
73706
  path: candidate.worktreePath,
73179
73707
  agentId: candidate.agentId,
73180
- deleted: !fs48.existsSync(candidate.worktreePath),
73181
- error: result.code !== 0 && fs48.existsSync(candidate.worktreePath) ? result.stderr : void 0
73708
+ deleted: !fs49.existsSync(candidate.worktreePath),
73709
+ error: result.code !== 0 && fs49.existsSync(candidate.worktreePath) ? result.stderr : void 0
73182
73710
  });
73183
73711
  } catch (err) {
73184
73712
  const message = err instanceof Error ? err.message : String(err);
73185
73713
  try {
73186
- if (fs48.existsSync(candidate.worktreePath)) {
73187
- fs48.rmSync(candidate.worktreePath, { recursive: true, force: true });
73714
+ if (fs49.existsSync(candidate.worktreePath)) {
73715
+ fs49.rmSync(candidate.worktreePath, { recursive: true, force: true });
73188
73716
  }
73189
73717
  } catch {
73190
73718
  }
73191
73719
  outcomes.push({
73192
73720
  path: candidate.worktreePath,
73193
73721
  agentId: candidate.agentId,
73194
- deleted: !fs48.existsSync(candidate.worktreePath),
73722
+ deleted: !fs49.existsSync(candidate.worktreePath),
73195
73723
  error: message
73196
73724
  });
73197
73725
  }
@@ -73254,16 +73782,16 @@ init_control_config();
73254
73782
  init_control_registry();
73255
73783
 
73256
73784
  // src/core/harness-scrub.ts
73257
- var fs49 = __toESM(require("fs"));
73258
- var path57 = __toESM(require("path"));
73785
+ var fs50 = __toESM(require("fs"));
73786
+ var path58 = __toESM(require("path"));
73259
73787
  var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
73260
73788
  function scrubLocalHarnessDirs(repoPath) {
73261
73789
  const results = [];
73262
- const resolved = path57.resolve(repoPath);
73263
- if (!fs49.existsSync(resolved)) {
73790
+ const resolved = path58.resolve(repoPath);
73791
+ if (!fs50.existsSync(resolved)) {
73264
73792
  for (const directory of HARNESS_SCRUB_DIRS) {
73265
73793
  results.push({
73266
- path: path57.join(resolved, ".har", directory),
73794
+ path: path58.join(resolved, ".har", directory),
73267
73795
  directory,
73268
73796
  deleted: false,
73269
73797
  error: "repository path does not exist"
@@ -73272,24 +73800,24 @@ function scrubLocalHarnessDirs(repoPath) {
73272
73800
  return results;
73273
73801
  }
73274
73802
  for (const directory of HARNESS_SCRUB_DIRS) {
73275
- const target = path57.join(resolved, ".har", directory);
73276
- if (!fs49.existsSync(target)) {
73803
+ const target = path58.join(resolved, ".har", directory);
73804
+ if (!fs50.existsSync(target)) {
73277
73805
  results.push({ path: target, directory, deleted: true });
73278
73806
  continue;
73279
73807
  }
73280
73808
  try {
73281
- fs49.rmSync(target, { recursive: true, force: true });
73809
+ fs50.rmSync(target, { recursive: true, force: true });
73282
73810
  results.push({
73283
73811
  path: target,
73284
73812
  directory,
73285
- deleted: !fs49.existsSync(target),
73286
- error: fs49.existsSync(target) ? "failed to remove directory" : void 0
73813
+ deleted: !fs50.existsSync(target),
73814
+ error: fs50.existsSync(target) ? "failed to remove directory" : void 0
73287
73815
  });
73288
73816
  } catch (err) {
73289
73817
  results.push({
73290
73818
  path: target,
73291
73819
  directory,
73292
- deleted: !fs49.existsSync(target),
73820
+ deleted: !fs50.existsSync(target),
73293
73821
  error: err instanceof Error ? err.message : String(err)
73294
73822
  });
73295
73823
  }
@@ -73300,7 +73828,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
73300
73828
  const results = [];
73301
73829
  const seen = /* @__PURE__ */ new Set();
73302
73830
  for (const repoPath of repoPaths) {
73303
- const key = path57.resolve(repoPath);
73831
+ const key = path58.resolve(repoPath);
73304
73832
  if (seen.has(key)) continue;
73305
73833
  seen.add(key);
73306
73834
  results.push(...scrubLocalHarnessDirs(key));
@@ -73309,12 +73837,12 @@ function scrubLocalHarnessForRepos(repoPaths) {
73309
73837
  }
73310
73838
 
73311
73839
  // src/core/control-reset.ts
73312
- async function askYesNo6(question) {
73840
+ async function askYesNo7(question) {
73313
73841
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
73314
73842
  const readline8 = await import("readline");
73315
73843
  const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
73316
- const answer = await new Promise((resolve49) => {
73317
- rl.question(question, resolve49);
73844
+ const answer = await new Promise((resolve50) => {
73845
+ rl.question(question, resolve50);
73318
73846
  });
73319
73847
  rl.close();
73320
73848
  return /^[Yy]$/.test(answer.trim());
@@ -73324,7 +73852,7 @@ async function confirmControlReset(options) {
73324
73852
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
73325
73853
  throw new Error("Non-interactive terminal \u2014 pass --yes");
73326
73854
  }
73327
- return askYesNo6(
73855
+ return askYesNo7(
73328
73856
  `Clear Mission Control data for ${options.repoCount} registered repositor${options.repoCount === 1 ? "y" : "ies"} (and scrub local .har history)? [y/N] `
73329
73857
  );
73330
73858
  }
@@ -73434,6 +73962,9 @@ var controlCommand = {
73434
73962
  type: "boolean",
73435
73963
  default: false,
73436
73964
  describe: "Re-register even if previously unregistered"
73965
+ }).option("portal", {
73966
+ type: "boolean",
73967
+ describe: "Sync this repo to the hosted portal when logged in. Use --no-portal to keep it local-only."
73437
73968
  }),
73438
73969
  handleRegister
73439
73970
  ).command(
@@ -73559,12 +74090,15 @@ async function handleDown() {
73559
74090
  return finishCommand(code);
73560
74091
  }
73561
74092
  async function handleRegister(argv) {
73562
- const repoPath = path58.resolve(argv.repo);
74093
+ const repoPath = path59.resolve(argv.repo);
73563
74094
  header("har control register");
73564
74095
  info(`Repository: ${repoPath}`);
73565
74096
  try {
73566
74097
  if (!argv.dryRun) {
73567
74098
  recordRepoForControlSync(repoPath);
74099
+ if (argv.portal !== void 0) {
74100
+ setRepoPortalSync(repoPath, argv.portal);
74101
+ }
73568
74102
  }
73569
74103
  await syncRepoWithControl({
73570
74104
  repoPath,
@@ -73576,6 +74110,9 @@ async function handleRegister(argv) {
73576
74110
  info("Dry run \u2014 no API call made");
73577
74111
  } else {
73578
74112
  success("Registered and synced with Mission Control");
74113
+ if (!isRepoPortalSyncEnabled(repoPath)) {
74114
+ info("Local-only \u2014 skipped hosted portal sync");
74115
+ }
73579
74116
  }
73580
74117
  } catch (err) {
73581
74118
  error(err.message);
@@ -73651,7 +74188,7 @@ async function handleReset(argv) {
73651
74188
  }
73652
74189
  }
73653
74190
  async function handleUnregister(argv) {
73654
- const repoPath = path58.resolve(argv.repo);
74191
+ const repoPath = path59.resolve(argv.repo);
73655
74192
  const worktrees = listUnregisterWorktreeCandidates(repoPath);
73656
74193
  try {
73657
74194
  let deleteWorktrees = argv.deleteWorktrees;
@@ -73833,12 +74370,12 @@ async function handleLogin(argv) {
73833
74370
  }
73834
74371
 
73835
74372
  // src/cli/commands/hooks.ts
73836
- var path60 = __toESM(require("path"));
74373
+ var path61 = __toESM(require("path"));
73837
74374
  init_hooks();
73838
74375
 
73839
74376
  // src/core/claude-hooks.ts
73840
- var fs50 = __toESM(require("fs"));
73841
- var path59 = __toESM(require("path"));
74377
+ var fs51 = __toESM(require("fs"));
74378
+ var path60 = __toESM(require("path"));
73842
74379
  var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
73843
74380
  var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
73844
74381
  var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
@@ -73849,8 +74386,8 @@ function isHarGuardEntry(entry) {
73849
74386
  );
73850
74387
  }
73851
74388
  function readSettings(settingsPath) {
73852
- if (!fs50.existsSync(settingsPath)) return {};
73853
- const raw = fs50.readFileSync(settingsPath, "utf8").trim();
74389
+ if (!fs51.existsSync(settingsPath)) return {};
74390
+ const raw = fs51.readFileSync(settingsPath, "utf8").trim();
73854
74391
  if (raw === "") return {};
73855
74392
  const parsed = JSON.parse(raw);
73856
74393
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -73859,19 +74396,19 @@ function readSettings(settingsPath) {
73859
74396
  return parsed;
73860
74397
  }
73861
74398
  function writeSettings(settingsPath, settings) {
73862
- fs50.mkdirSync(path59.dirname(settingsPath), { recursive: true });
73863
- fs50.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
74399
+ fs51.mkdirSync(path60.dirname(settingsPath), { recursive: true });
74400
+ fs51.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
73864
74401
  }
73865
74402
  function installClaudeGuard(repoPath) {
73866
74403
  const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
73867
74404
  if (!templatePath) {
73868
74405
  throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
73869
74406
  }
73870
- const guardScript = path59.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73871
- fs50.mkdirSync(path59.dirname(guardScript), { recursive: true });
73872
- fs50.copyFileSync(templatePath, guardScript);
73873
- fs50.chmodSync(guardScript, 493);
73874
- const settingsPath = path59.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
74407
+ const guardScript = path60.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
74408
+ fs51.mkdirSync(path60.dirname(guardScript), { recursive: true });
74409
+ fs51.copyFileSync(templatePath, guardScript);
74410
+ fs51.chmodSync(guardScript, 493);
74411
+ const settingsPath = path60.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73875
74412
  const settings = readSettings(settingsPath);
73876
74413
  const hooks = settings.hooks ?? {};
73877
74414
  const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
@@ -73885,15 +74422,15 @@ function installClaudeGuard(repoPath) {
73885
74422
  }
73886
74423
  function uninstallClaudeGuard(repoPath) {
73887
74424
  let removed = false;
73888
- const guardScript = path59.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
73889
- if (fs50.existsSync(guardScript)) {
73890
- fs50.rmSync(guardScript);
74425
+ const guardScript = path60.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
74426
+ if (fs51.existsSync(guardScript)) {
74427
+ fs51.rmSync(guardScript);
73891
74428
  removed = true;
73892
- const parent = path59.dirname(guardScript);
73893
- if (fs50.existsSync(parent) && fs50.readdirSync(parent).length === 0) fs50.rmdirSync(parent);
74429
+ const parent = path60.dirname(guardScript);
74430
+ if (fs51.existsSync(parent) && fs51.readdirSync(parent).length === 0) fs51.rmdirSync(parent);
73894
74431
  }
73895
- const settingsPath = path59.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73896
- if (fs50.existsSync(settingsPath)) {
74432
+ const settingsPath = path60.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
74433
+ if (fs51.existsSync(settingsPath)) {
73897
74434
  const settings = readSettings(settingsPath);
73898
74435
  const preToolUse = settings.hooks?.PreToolUse;
73899
74436
  if (preToolUse) {
@@ -73918,8 +74455,8 @@ function uninstallClaudeGuard(repoPath) {
73918
74455
  return { removed };
73919
74456
  }
73920
74457
  function claudeGuardInstalled(repoPath) {
73921
- const settingsPath = path59.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
73922
- if (!fs50.existsSync(settingsPath)) return false;
74458
+ const settingsPath = path60.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
74459
+ if (!fs51.existsSync(settingsPath)) return false;
73923
74460
  try {
73924
74461
  const settings = readSettings(settingsPath);
73925
74462
  return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
@@ -73936,7 +74473,7 @@ function repoOption(y) {
73936
74473
  function handleInstall2(argv) {
73937
74474
  try {
73938
74475
  if (argv.claude) {
73939
- const result2 = installClaudeGuard(path60.resolve(argv.repo));
74476
+ const result2 = installClaudeGuard(path61.resolve(argv.repo));
73940
74477
  success("Claude Code worktree guard installed.");
73941
74478
  info(`Guard script: ${result2.guardScript}`);
73942
74479
  info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
@@ -73944,7 +74481,7 @@ function handleInstall2(argv) {
73944
74481
  info("Commit both files so the guard travels with the repo.");
73945
74482
  return;
73946
74483
  }
73947
- const result = installHooks({ repoPath: path60.resolve(argv.repo), force: argv.force });
74484
+ const result = installHooks({ repoPath: path61.resolve(argv.repo), force: argv.force });
73948
74485
  success(`Commit gate installed in ${result.hooksDir}`);
73949
74486
  info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
73950
74487
  info("Commits of unverified change batches will be blocked in agent worktrees.");
@@ -73957,7 +74494,7 @@ function handleInstall2(argv) {
73957
74494
  function handleUninstall(argv) {
73958
74495
  try {
73959
74496
  if (argv.claude) {
73960
- const result2 = uninstallClaudeGuard(path60.resolve(argv.repo));
74497
+ const result2 = uninstallClaudeGuard(path61.resolve(argv.repo));
73961
74498
  if (result2.removed) {
73962
74499
  success("Claude Code worktree guard removed.");
73963
74500
  } else {
@@ -73965,7 +74502,7 @@ function handleUninstall(argv) {
73965
74502
  }
73966
74503
  return;
73967
74504
  }
73968
- const result = uninstallHooks(path60.resolve(argv.repo));
74505
+ const result = uninstallHooks(path61.resolve(argv.repo));
73969
74506
  if (result.removed) {
73970
74507
  success(`Commit gate removed from ${result.hooksDir}`);
73971
74508
  } else {
@@ -73978,7 +74515,7 @@ function handleUninstall(argv) {
73978
74515
  }
73979
74516
  function handleStatus2(argv) {
73980
74517
  try {
73981
- const status = getHooksStatus(path60.resolve(argv.repo));
74518
+ const status = getHooksStatus(path61.resolve(argv.repo));
73982
74519
  if (argv.json) {
73983
74520
  process.stdout.write(`${JSON.stringify(status, null, 2)}
73984
74521
  `);
@@ -73996,7 +74533,7 @@ function handleStatus2(argv) {
73996
74533
  );
73997
74534
  info(`Effective: ${status.effectiveMode} (in this checkout)`);
73998
74535
  info(
73999
- `Claude guard: ${claudeGuardInstalled(path60.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
74536
+ `Claude guard: ${claudeGuardInstalled(path61.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
74000
74537
  );
74001
74538
  } catch (err) {
74002
74539
  error(err instanceof Error ? err.message : String(err));
@@ -74257,10 +74794,10 @@ function assignProp(target, prop, value) {
74257
74794
  configurable: true
74258
74795
  });
74259
74796
  }
74260
- function getElementAtPath(obj, path65) {
74261
- if (!path65)
74797
+ function getElementAtPath(obj, path66) {
74798
+ if (!path66)
74262
74799
  return obj;
74263
- return path65.reduce((acc, key) => acc?.[key], obj);
74800
+ return path66.reduce((acc, key) => acc?.[key], obj);
74264
74801
  }
74265
74802
  function promiseAllObject(promisesObj) {
74266
74803
  const keys = Object.keys(promisesObj);
@@ -74580,11 +75117,11 @@ function aborted(x, startIndex = 0) {
74580
75117
  }
74581
75118
  return false;
74582
75119
  }
74583
- function prefixIssues(path65, issues) {
75120
+ function prefixIssues(path66, issues) {
74584
75121
  return issues.map((iss) => {
74585
75122
  var _a2;
74586
75123
  (_a2 = iss).path ?? (_a2.path = []);
74587
- iss.path.unshift(path65);
75124
+ iss.path.unshift(path66);
74588
75125
  return iss;
74589
75126
  });
74590
75127
  }
@@ -79907,7 +80444,7 @@ var Protocol = class {
79907
80444
  return;
79908
80445
  }
79909
80446
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
79910
- await new Promise((resolve49) => setTimeout(resolve49, pollInterval));
80447
+ await new Promise((resolve50) => setTimeout(resolve50, pollInterval));
79911
80448
  options?.signal?.throwIfAborted();
79912
80449
  }
79913
80450
  } catch (error3) {
@@ -79924,7 +80461,7 @@ var Protocol = class {
79924
80461
  */
79925
80462
  request(request, resultSchema, options) {
79926
80463
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
79927
- return new Promise((resolve49, reject) => {
80464
+ return new Promise((resolve50, reject) => {
79928
80465
  const earlyReject = (error3) => {
79929
80466
  reject(error3);
79930
80467
  };
@@ -80002,7 +80539,7 @@ var Protocol = class {
80002
80539
  if (!parseResult.success) {
80003
80540
  reject(parseResult.error);
80004
80541
  } else {
80005
- resolve49(parseResult.data);
80542
+ resolve50(parseResult.data);
80006
80543
  }
80007
80544
  } catch (error3) {
80008
80545
  reject(error3);
@@ -80263,12 +80800,12 @@ var Protocol = class {
80263
80800
  }
80264
80801
  } catch {
80265
80802
  }
80266
- return new Promise((resolve49, reject) => {
80803
+ return new Promise((resolve50, reject) => {
80267
80804
  if (signal.aborted) {
80268
80805
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
80269
80806
  return;
80270
80807
  }
80271
- const timeoutId = setTimeout(resolve49, interval);
80808
+ const timeoutId = setTimeout(resolve50, interval);
80272
80809
  signal.addEventListener("abort", () => {
80273
80810
  clearTimeout(timeoutId);
80274
80811
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -81058,7 +81595,7 @@ var Server = class extends Protocol {
81058
81595
  };
81059
81596
 
81060
81597
  // src/mcp/server.ts
81061
- var path61 = __toESM(require("path"));
81598
+ var path62 = __toESM(require("path"));
81062
81599
 
81063
81600
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
81064
81601
  var import_node_process3 = __toESM(require("node:process"), 1);
@@ -81141,12 +81678,12 @@ var StdioServerTransport = class {
81141
81678
  this.onclose?.();
81142
81679
  }
81143
81680
  send(message) {
81144
- return new Promise((resolve49) => {
81681
+ return new Promise((resolve50) => {
81145
81682
  const json = serializeMessage(message);
81146
81683
  if (this._stdout.write(json)) {
81147
- resolve49();
81684
+ resolve50();
81148
81685
  } else {
81149
- this._stdout.once("drain", resolve49);
81686
+ this._stdout.once("drain", resolve50);
81150
81687
  }
81151
81688
  });
81152
81689
  }
@@ -81155,6 +81692,8 @@ var StdioServerTransport = class {
81155
81692
  // src/mcp/server.ts
81156
81693
  init_telemetry_config();
81157
81694
  init_runs();
81695
+ init_work_units();
81696
+ init_manifest();
81158
81697
 
81159
81698
  // src/mcp/schema-tools.ts
81160
81699
  init_schema2();
@@ -81239,7 +81778,21 @@ var LaunchEnvironmentInputSchema = external_exports.object({
81239
81778
  source: external_exports.string().min(1).max(64).optional(),
81240
81779
  sourceUrl: external_exports.string().url().optional(),
81241
81780
  title: external_exports.string().min(1).max(256).optional(),
81242
- parentWorkUnitId: external_exports.string().min(1).max(128).optional()
81781
+ parentWorkUnitId: external_exports.string().min(1).max(128).optional(),
81782
+ relatedLinks: external_exports.array(
81783
+ external_exports.object({
81784
+ source: external_exports.string().min(1).max(64),
81785
+ url: external_exports.string().url(),
81786
+ label: external_exports.string().min(1).max(128).optional()
81787
+ })
81788
+ ).optional()
81789
+ });
81790
+ var AddWorkUnitLinkInputSchema = external_exports.object({
81791
+ repo: external_exports.string().default("."),
81792
+ workUnitId: external_exports.string().min(1).max(128),
81793
+ source: external_exports.string().min(1).max(64),
81794
+ url: external_exports.string().url(),
81795
+ label: external_exports.string().min(1).max(128).optional()
81243
81796
  });
81244
81797
  var LaunchEnvironmentOutputSchema = ShellRunOutputSchema.extend({
81245
81798
  previewUrls: external_exports.record(external_exports.string()).optional(),
@@ -81386,11 +81939,41 @@ var HAR_MCP_TOOLS = [
81386
81939
  parentWorkUnitId: {
81387
81940
  type: "string",
81388
81941
  description: "Optional parent work unit identifier."
81942
+ },
81943
+ relatedLinks: {
81944
+ type: "array",
81945
+ description: "Additional tracker links (append-only). Each item: source, url, optional label.",
81946
+ items: {
81947
+ type: "object",
81948
+ properties: {
81949
+ source: { type: "string" },
81950
+ url: { type: "string" },
81951
+ label: { type: "string" }
81952
+ },
81953
+ required: ["source", "url"]
81954
+ }
81389
81955
  }
81390
81956
  },
81391
81957
  ["agentId"]
81392
81958
  )
81393
81959
  },
81960
+ {
81961
+ name: "har_add_work_unit_link",
81962
+ description: "Append a related external link (PR, mirrored issue, alternate tracker) to an existing work unit.",
81963
+ inputSchema: objectJsonSchema(
81964
+ {
81965
+ repo: repoJsonProperty,
81966
+ workUnitId: {
81967
+ type: "string",
81968
+ description: "Repo-scoped work unit id bound at launch."
81969
+ },
81970
+ source: { type: "string", description: "Tracker provider (e.g. github, jira)." },
81971
+ url: { type: "string", description: "Canonical URL for the link." },
81972
+ label: { type: "string", description: "Optional display label." }
81973
+ },
81974
+ ["workUnitId", "source", "url"]
81975
+ )
81976
+ },
81394
81977
  {
81395
81978
  name: "har_recover_environment",
81396
81979
  description: "Resume a failed or partial agent launch without replacing the worktree. Alias for har_launch_environment with resume=true.",
@@ -81561,6 +82144,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
81561
82144
  sourceUrl: input.sourceUrl,
81562
82145
  title: input.title,
81563
82146
  parentWorkUnitId: input.parentWorkUnitId,
82147
+ relatedLinks: input.relatedLinks,
81564
82148
  capture: true
81565
82149
  });
81566
82150
  const parsed = LaunchEnvironmentOutputSchema.parse(result);
@@ -81583,6 +82167,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
81583
82167
  sourceUrl: input.sourceUrl,
81584
82168
  title: input.title,
81585
82169
  parentWorkUnitId: input.parentWorkUnitId,
82170
+ relatedLinks: input.relatedLinks,
81586
82171
  capture: true
81587
82172
  });
81588
82173
  const parsed = LaunchEnvironmentOutputSchema.parse(result);
@@ -81591,6 +82176,28 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
81591
82176
  ...result.blocked ? { isError: true } : {}
81592
82177
  };
81593
82178
  }
82179
+ case "har_add_work_unit_link": {
82180
+ const input = AddWorkUnitLinkInputSchema.parse({ ...args, repo });
82181
+ const harnessRoot = resolveHarnessRoot(repo);
82182
+ try {
82183
+ const record2 = addWorkUnitLinks(harnessRoot, input.workUnitId, [
82184
+ { source: input.source, url: input.url, label: input.label }
82185
+ ]);
82186
+ return jsonContent({
82187
+ ok: true,
82188
+ workUnitId: record2.workUnitId,
82189
+ relatedLinks: record2.relatedLinks
82190
+ });
82191
+ } catch (err) {
82192
+ return {
82193
+ ...jsonContent({
82194
+ ok: false,
82195
+ error: err instanceof Error ? err.message : String(err)
82196
+ }),
82197
+ isError: true
82198
+ };
82199
+ }
82200
+ }
81594
82201
  case "har_preflight_environment": {
81595
82202
  const input = PreflightEnvironmentInputSchema.parse({ ...args, repo });
81596
82203
  const agentId = validateAgentId(input.agentId, repo);
@@ -81701,7 +82308,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
81701
82308
  const input = ControlUpInputSchema.parse({ ...args, repo });
81702
82309
  const result = await startControlAndSync({
81703
82310
  detach: input.detach,
81704
- cwd: path61.resolve(input.repo)
82311
+ cwd: path62.resolve(input.repo)
81705
82312
  });
81706
82313
  if (result.code !== 0) {
81707
82314
  return {
@@ -81765,11 +82372,11 @@ var mcpCommand = {
81765
82372
  };
81766
82373
 
81767
82374
  // src/cli/commands/onboard.ts
81768
- var path63 = __toESM(require("path"));
82375
+ var path64 = __toESM(require("path"));
81769
82376
  init_stages();
81770
82377
 
81771
82378
  // src/core/onboarding.ts
81772
- var path62 = __toESM(require("path"));
82379
+ var path63 = __toESM(require("path"));
81773
82380
  init_control_config();
81774
82381
  init_control_sync();
81775
82382
  init_otel_hooks();
@@ -81905,7 +82512,7 @@ async function defaultEnsureControl(options) {
81905
82512
  return { started: true, apiUrl: result.apiUrl };
81906
82513
  }
81907
82514
  async function runOnboarding(options, deps = {}) {
81908
- const repoPath = path62.resolve(options.repoPath);
82515
+ const repoPath = path63.resolve(options.repoPath);
81909
82516
  const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
81910
82517
  const ensureControl = deps.ensureControl ?? defaultEnsureControl;
81911
82518
  const init = deps.initHarness ?? initHarness;
@@ -82093,7 +82700,7 @@ async function promptChoices(args) {
82093
82700
  };
82094
82701
  }
82095
82702
  const pluginChoices = listPluginChoices();
82096
- const repoPath = path63.resolve(args.repo);
82703
+ const repoPath = path64.resolve(args.repo);
82097
82704
  const alreadyPresent = harnessExists(repoPath);
82098
82705
  const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
82099
82706
  const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
@@ -82210,7 +82817,7 @@ function printSummary(result) {
82210
82817
  console.error("");
82211
82818
  }
82212
82819
  async function handleOnboard(argv) {
82213
- const repoPath = path63.resolve(argv.repo);
82820
+ const repoPath = path64.resolve(argv.repo);
82214
82821
  header("har onboard");
82215
82822
  info(`Repository: ${repoPath}`);
82216
82823
  try {
@@ -82441,7 +83048,7 @@ var preferencesCommand = {
82441
83048
  };
82442
83049
 
82443
83050
  // src/cli/commands/telemetry.ts
82444
- var path64 = __toESM(require("path"));
83051
+ var path65 = __toESM(require("path"));
82445
83052
  init_control_config();
82446
83053
  init_control_sync();
82447
83054
  init_manifest();
@@ -82534,7 +83141,7 @@ async function handleOff() {
82534
83141
  info("Mission Control will not auto-start. Existing usage rows are kept.");
82535
83142
  }
82536
83143
  async function handleWriteEnv(argv) {
82537
- const repoPath = path64.resolve(argv.repo);
83144
+ const repoPath = path65.resolve(argv.repo);
82538
83145
  const harnessRoot = resolveHarnessRoot(repoPath);
82539
83146
  const session = readSlotRegistry(harnessRoot, argv.agentId);
82540
83147
  const workDir = argv.workDir ?? session?.workDir ?? repoPath;
@@ -82546,7 +83153,7 @@ async function handleWriteEnv(argv) {
82546
83153
  suffix,
82547
83154
  createdAt: session?.createdAt
82548
83155
  });
82549
- const envFile = argv.envFile ?? path64.join(workDir, `.env.agent.${argv.agentId}`);
83156
+ const envFile = argv.envFile ?? path65.join(workDir, `.env.agent.${argv.agentId}`);
82550
83157
  const attrs = {
82551
83158
  sessionKey,
82552
83159
  agentId: argv.agentId,
@@ -82562,7 +83169,7 @@ async function handleWriteEnv(argv) {
82562
83169
  success(`Wrote session attribution to ${envFile}`);
82563
83170
  }
82564
83171
  function handlePrintEnv(argv) {
82565
- const repoPath = path64.resolve(argv.repo);
83172
+ const repoPath = path65.resolve(argv.repo);
82566
83173
  const workDir = argv.workDir ?? repoPath;
82567
83174
  const sessionKey = buildSessionKey({
82568
83175
  branch: argv.branch,