@osfactory/har 0.58.0 → 0.60.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 +82 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28869,11 +28869,16 @@ function getRegistryPath() {
28869
28869
  }
28870
28870
  return path9.join(os3.homedir(), ".har", "repos.json");
28871
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
+ }
28872
28877
  function readRegistry() {
28873
28878
  const registryPath = getRegistryPath();
28874
28879
  try {
28875
28880
  if (!fs9.existsSync(registryPath)) return { repos: [] };
28876
- return JSON.parse(fs9.readFileSync(registryPath, "utf8"));
28881
+ return normalizeRegistry(JSON.parse(fs9.readFileSync(registryPath, "utf8")));
28877
28882
  } catch {
28878
28883
  return { repos: [] };
28879
28884
  }
@@ -28881,12 +28886,37 @@ function readRegistry() {
28881
28886
  function writeRegistry(registry2) {
28882
28887
  const registryPath = getRegistryPath();
28883
28888
  fs9.mkdirSync(path9.dirname(registryPath), { recursive: true });
28884
- fs9.writeFileSync(registryPath, JSON.stringify(registry2, null, 2) + "\n");
28889
+ const normalized = normalizeRegistry(registry2);
28890
+ fs9.writeFileSync(registryPath, JSON.stringify(normalized, null, 2) + "\n");
28885
28891
  }
28886
28892
  function registryChanged(before, after) {
28887
28893
  if (before.length !== after.length) return true;
28888
28894
  return before.some((repoPath, index) => repoPath !== after[index]);
28889
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
+ }
28890
28920
  function recordRepoForControlSync(repoPath) {
28891
28921
  if (process.env.HAR_CONTROL_DISABLED === "true") return;
28892
28922
  const resolved = canonicalizeControlRepoPath(repoPath);
@@ -28897,18 +28927,40 @@ function recordRepoForControlSync(repoPath) {
28897
28927
  registry2.repos.push(resolved);
28898
28928
  writeRegistry(registry2);
28899
28929
  }
28900
- function removeRegisteredRepo(repoPath) {
28930
+ function isRepoPortalSyncEnabled(repoPath) {
28901
28931
  const resolved = canonicalizeControlRepoPath(repoPath);
28902
28932
  const registry2 = readRegistry();
28903
- const next = registry2.repos.filter((entry) => {
28904
- try {
28905
- return canonicalizeControlRepoPath(entry) !== resolved;
28906
- } catch {
28907
- return path9.resolve(entry) !== resolved;
28908
- }
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]
28909
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));
28910
28958
  if (next.length === registry2.repos.length) return false;
28911
- writeRegistry({ repos: next });
28959
+ const portalOptOut = prunePortalOptOut(registry2, next);
28960
+ writeRegistry({
28961
+ repos: next,
28962
+ ...portalOptOut ? { portalOptOut } : {}
28963
+ });
28912
28964
  return true;
28913
28965
  }
28914
28966
  function listRegisteredRepos() {
@@ -28923,15 +28975,21 @@ function listRegisteredRepos() {
28923
28975
  seen.add(canonical);
28924
28976
  kept.push(canonical);
28925
28977
  }
28926
- if (registryChanged(registry2.repos, kept)) {
28927
- 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
+ });
28928
28986
  }
28929
28987
  return kept;
28930
28988
  }
28931
28989
  function clearRegisteredRepos() {
28932
28990
  const registry2 = readRegistry();
28933
28991
  const count = registry2.repos.length;
28934
- if (count === 0) return 0;
28992
+ if (count === 0 && !registry2.portalOptOut?.length) return 0;
28935
28993
  writeRegistry({ repos: [] });
28936
28994
  return count;
28937
28995
  }
@@ -32786,6 +32844,7 @@ async function syncRepoWithLocalControl(options) {
32786
32844
  }
32787
32845
  }
32788
32846
  async function syncRepoWithPortal(options, controlApiUrl) {
32847
+ if (!isRepoPortalSyncEnabled(options.repoPath)) return;
32789
32848
  const portal = getPortalTarget();
32790
32849
  if (!portal) return;
32791
32850
  const { repoPath, dryRun, full } = options;
@@ -33008,6 +33067,7 @@ async function syncRunWithControlAsync(repoPath, run2) {
33008
33067
  }
33009
33068
  const portal = getPortalTarget();
33010
33069
  if (!portal) return;
33070
+ if (!isRepoPortalSyncEnabled(canonical)) return;
33011
33071
  try {
33012
33072
  if (!await isControlApiReachable(portal.url)) return;
33013
33073
  await postPortal(portal, "/api/sync", { path: canonical, runs: [run2] });
@@ -73902,6 +73962,9 @@ var controlCommand = {
73902
73962
  type: "boolean",
73903
73963
  default: false,
73904
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."
73905
73968
  }),
73906
73969
  handleRegister
73907
73970
  ).command(
@@ -74033,6 +74096,9 @@ async function handleRegister(argv) {
74033
74096
  try {
74034
74097
  if (!argv.dryRun) {
74035
74098
  recordRepoForControlSync(repoPath);
74099
+ if (argv.portal !== void 0) {
74100
+ setRepoPortalSync(repoPath, argv.portal);
74101
+ }
74036
74102
  }
74037
74103
  await syncRepoWithControl({
74038
74104
  repoPath,
@@ -74044,6 +74110,9 @@ async function handleRegister(argv) {
74044
74110
  info("Dry run \u2014 no API call made");
74045
74111
  } else {
74046
74112
  success("Registered and synced with Mission Control");
74113
+ if (!isRepoPortalSyncEnabled(repoPath)) {
74114
+ info("Local-only \u2014 skipped hosted portal sync");
74115
+ }
74047
74116
  }
74048
74117
  } catch (err) {
74049
74118
  error(err.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.58.0",
3
+ "version": "0.60.0",
4
4
  "description": "Open harness for reproducible multi-agent coding workflows",
5
5
  "keywords": [
6
6
  "har",