failproofai 1.0.9-beta.1 → 1.0.9

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 (115) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +4 -4
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +14 -14
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  41. package/.next/standalone/.next/server/app/policies/page.js +1 -1
  42. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  52. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  55. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  58. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  59. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  60. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
  62. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
  63. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +2 -2
  67. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__03m2iw6._.js → [root-of-the-server]__1ec94jt._.js} +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/{_11ilmst._.js → _0xq-p5o._.js} +2 -2
  75. package/.next/standalone/.next/server/chunks/ssr/{_1jatlmf._.js → _1g7s7di._.js} +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +3 -3
  77. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  79. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
  84. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  85. package/.next/standalone/.next/server/pages/404.html +1 -1
  86. package/.next/standalone/.next/server/pages/500.html +1 -1
  87. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  89. package/.next/standalone/.next/static/chunks/{1uec0n0lcx5h1.js → 03madt33xbsx2.js} +1 -1
  90. package/.next/standalone/.next/static/chunks/0w8_n30wmnorq.js +1 -0
  91. package/.next/standalone/.next/static/chunks/{3vp54x0dyrrm6.js → 0zlixskj11-yh.js} +1 -1
  92. package/.next/standalone/.next/static/chunks/{21qlo00jis4w-.js → 1-n1o5wh4wfy6.js} +1 -1
  93. package/.next/standalone/.next/static/chunks/{2n00c3zqyloy9.js → 1t6tmwe_1myeo.js} +1 -1
  94. package/.next/standalone/.next/static/chunks/{3tv107_for_n7.js → 28z6u4u7hdrnd.js} +1 -1
  95. package/.next/standalone/.next/static/chunks/{1r74hmr1wm_sd.js → 2dj6xq9mueqb6.js} +1 -1
  96. package/.next/standalone/.next/static/chunks/{1-d48e9k-7e1a.js → 2lczelmvvc2yg.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/{08ckontevw-0w.js → 3fbsuyflx-2qi.js} +1 -1
  98. package/.next/standalone/.next/static/chunks/{21-pqc3-l9ak2.js → 3jffngwvgxm5q.js} +1 -1
  99. package/.next/standalone/package.json +9 -9
  100. package/.next/standalone/sdk/typescript/CHANGELOG.md +39 -0
  101. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +3 -3
  102. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +1 -1
  103. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +16 -113
  104. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +3 -1
  105. package/.next/standalone/server.js +1 -1
  106. package/dist/cli.mjs +254 -124
  107. package/dist/worker.mjs +1 -1
  108. package/package.json +9 -9
  109. package/src/hooks/daemon-service.ts +14 -1
  110. package/src/hooks/integrations.ts +133 -31
  111. package/src/hooks/safe-config-write.ts +80 -7
  112. package/.next/standalone/.next/static/chunks/0pefjgvu4x-sx.js +0 -1
  113. /package/.next/standalone/.next/static/{ozuWoyIwOTqeUUjKqOKiH → Q2PyL8ZdGGdvVnn-3FrL2}/_buildManifest.js +0 -0
  114. /package/.next/standalone/.next/static/{ozuWoyIwOTqeUUjKqOKiH → Q2PyL8ZdGGdvVnn-3FrL2}/_clientMiddlewareManifest.js +0 -0
  115. /package/.next/standalone/.next/static/{ozuWoyIwOTqeUUjKqOKiH → Q2PyL8ZdGGdvVnn-3FrL2}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "1.0.9-beta.1",
3
+ "version": "1.0.9",
4
4
  "description": "Observability and enforcement for AI agent harnesses. 40 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
5
5
  "bin": {
6
6
  "failproofai": "./dist/cli.mjs",
@@ -122,15 +122,15 @@
122
122
  "browserslist": "4.28.8"
123
123
  },
124
124
  "optionalDependencies": {
125
- "@failproofai/failproofaid-linux-x64": "1.0.9-beta.1",
126
- "@failproofai/failproofaid-linux-arm64": "1.0.9-beta.1",
127
- "@failproofai/failproofaid-darwin-x64": "1.0.9-beta.1",
128
- "@failproofai/failproofaid-darwin-arm64": "1.0.9-beta.1"
125
+ "@failproofai/failproofaid-linux-x64": "1.0.9",
126
+ "@failproofai/failproofaid-linux-arm64": "1.0.9",
127
+ "@failproofai/failproofaid-darwin-x64": "1.0.9",
128
+ "@failproofai/failproofaid-darwin-arm64": "1.0.9"
129
129
  },
130
130
  "failproofaidBinaries": {
131
- "linux-x64": "a0db1ad28bc0584bb4554b1dc60b55353fad9d982354880f9cc1e1ee567e5d36",
132
- "linux-arm64": "b8d2797db8d93ce0deec86707093dd22ecd2d3fe2b137944938f4851d31718f1",
133
- "darwin-x64": "94dc7ea33121c884736eadafc8281b0b752824b5c7fbe1726745bd1fa2b2a577",
134
- "darwin-arm64": "8da18bbede18b8c112e8c46b6f0de798e84445c163a91a80edeef6d9e21da8ad"
131
+ "linux-x64": "c406199fbd5682ee84eb3bdd679fe48d1f78a26e97710f05bcfe42771e33ca4a",
132
+ "linux-arm64": "8ec339035013aaf069bd882660b89eefde137a5fb3c66bed9c65bfbfa1afaa19",
133
+ "darwin-x64": "fdf77e2432131ff6081769555c0a87d709d3380c78bc33de92743694dd20a83b",
134
+ "darwin-arm64": "a85e7e2af98fbcc09b6dfdd7fba8289d309757eab6482770ca64d3eeb81407d5"
135
135
  }
136
136
  }
@@ -1556,10 +1556,23 @@ export async function refreshDaemonToCliVersion(
1556
1556
  const prime = deps.prime ?? primeElevation;
1557
1557
  const interactive =
1558
1558
  deps.interactive ?? (() => Boolean(process.stdin.isTTY && process.stdout.isTTY));
1559
- if (status() === "not-installed") {
1559
+ const current = status();
1560
+ if (current === "not-installed") {
1560
1561
  return { ok: true, lines: ["No failproofaid service on this machine; nothing to update."] };
1561
1562
  }
1562
1563
 
1564
+ // Already this version: nothing to install, so nothing to ask root for. The
1565
+ // reinstall below is idempotent, but it needs sudo, so without this every
1566
+ // `update` after the daemon was brought current either prompted for a password
1567
+ // for no reason or — with no TTY to prompt on (a fleet box, CI) — failed with
1568
+ // "root privileges are required" and exited 1 on a machine that was fine.
1569
+ // `VERSION.daemon` is written only after an install succeeds, and the binary
1570
+ // it names must still be on disk.
1571
+ const recorded = readVersionFile()?.daemon;
1572
+ if (current === "running" && recorded === version && existsSync(installedBinaryPath(version))) {
1573
+ return { ok: true, lines: [`failproofaid ${version} is already installed and running; nothing to update.`] };
1574
+ }
1575
+
1563
1576
  // `installDaemonService()`, not a binary fetch plus a restart.
1564
1577
  //
1565
1578
  // The first version of this did the latter, and it did not work: it called
@@ -1178,7 +1178,7 @@ export const opencode: Integration = {
1178
1178
  // (a) Write the shim file. mkdirSync is recursive so the plugins/ dir
1179
1179
  // is created on first install.
1180
1180
  mkdirSync(dirname(pluginPath), { recursive: true });
1181
- writeConfigFileAtomic(pluginPath, buildOpenCodePluginShim(binaryPath, effectiveScope));
1181
+ writeConfigFileAtomic(pluginPath, buildOpenCodePluginShim(binaryPath, effectiveScope), { symlinks: "replace" });
1182
1182
 
1183
1183
  // (b) Merge our entry into the plugin array idempotently. Replace any
1184
1184
  // existing failproofai-marked entry; otherwise append.
@@ -1518,17 +1518,61 @@ function hasAllHermesPluginFiles(dir: string): boolean {
1518
1518
  }
1519
1519
 
1520
1520
  /**
1521
- * Whether `dir` is a FailproofAI `hermes-plugin` directory (or was one: a link
1522
- * whose target vanished during an npm upgrade or uninstall is still ours).
1523
- * The basename is the package layout; the manifest name confirms it when the
1524
- * target is readable, so a link to someone else's plugin is never claimed.
1521
+ * The record FailproofAI keeps beside a link it created:
1522
+ * `<profile>/plugins/.failproofai-link`, holding the link's target. It lives
1523
+ * OUTSIDE the linked directory on purpose — anything inside the target is
1524
+ * content whoever owns that directory controls. Hermes' plugin scan skips it
1525
+ * (a file, not a directory).
1525
1526
  */
1526
- function isFailproofaiHermesPluginSource(dir: string): boolean {
1527
- if (basename(dir) !== HERMES_PLUGIN_SOURCE_DIR) return false;
1528
- if (!existsSync(dir)) return true;
1527
+ const HERMES_LINK_RECORD = ".failproofai-link";
1528
+
1529
+ function hermesLinkRecordPath(pluginPath: string): string {
1530
+ return resolve(dirname(pluginPath), HERMES_LINK_RECORD);
1531
+ }
1532
+
1533
+ function readHermesLinkRecord(pluginPath: string): string | null {
1534
+ try {
1535
+ const recorded = readFileSync(hermesLinkRecordPath(pluginPath), "utf8").trim();
1536
+ return recorded === "" ? null : resolve(recorded);
1537
+ } catch {
1538
+ return null;
1539
+ }
1540
+ }
1541
+
1542
+ function writeHermesLinkRecord(pluginPath: string, target: string): void {
1543
+ writeConfigFileAtomic(hermesLinkRecordPath(pluginPath), resolve(target) + "\n", { backup: false, symlinks: "replace" });
1544
+ }
1545
+
1546
+ function removeHermesLinkRecord(pluginPath: string): void {
1547
+ rmSync(hermesLinkRecordPath(pluginPath), { force: true });
1548
+ }
1549
+
1550
+ /**
1551
+ * Whether a link at `pluginPath` pointing at `target` is FailproofAI's.
1552
+ *
1553
+ * A directory name and a manifest `name:` are things any plugin can copy, so
1554
+ * neither proves anything. Ownership is one of two verifiable facts:
1555
+ *
1556
+ * 1. our record: the link target equals what `.failproofai-link` says we
1557
+ * linked (every link this build creates is recorded), or
1558
+ * 2. provenance, for links created before the record existed (the 1.0.9
1559
+ * betas): the target IS this package's `hermes-plugin/`, or it is
1560
+ * `…/node_modules/failproofai/hermes-plugin` inside a directory whose
1561
+ * `package.json` names the package `failproofai`.
1562
+ *
1563
+ * Anything else — including a same-named, same-manifest plugin somewhere
1564
+ * else, or a dangling link with no record — is foreign and never touched.
1565
+ */
1566
+ function isOwnedHermesPluginLink(pluginPath: string, target: string): boolean {
1567
+ const recorded = readHermesLinkRecord(pluginPath);
1568
+ if (recorded && resolve(target) === recorded) return true;
1569
+ if (samePath(target, getHermesPluginSourcePath())) return true;
1570
+ const pkgRoot = dirname(resolve(target));
1571
+ if (basename(resolve(target)) !== HERMES_PLUGIN_SOURCE_DIR) return false;
1572
+ if (basename(pkgRoot) !== "failproofai" || basename(dirname(pkgRoot)) !== "node_modules") return false;
1529
1573
  try {
1530
- const manifest = readFileSync(resolve(dir, "plugin.yaml"), "utf8");
1531
- return /^name:\s*["']?failproofai["']?\s*$/m.test(manifest);
1574
+ const pkg = JSON.parse(readFileSync(resolve(pkgRoot, "package.json"), "utf8")) as { name?: unknown };
1575
+ return pkg.name === "failproofai";
1532
1576
  } catch {
1533
1577
  return false;
1534
1578
  }
@@ -1578,7 +1622,7 @@ function hermesPluginState(settingsPath: string): HermesPluginState {
1578
1622
  } catch {
1579
1623
  return { kind: "foreign" };
1580
1624
  }
1581
- if (!isFailproofaiHermesPluginSource(target)) return { kind: "foreign" };
1625
+ if (!isOwnedHermesPluginLink(pluginPath, target)) return { kind: "foreign" };
1582
1626
  return {
1583
1627
  kind: "link",
1584
1628
  target,
@@ -1636,7 +1680,18 @@ export function installHermesPlugin(
1636
1680
  `Move it aside or install FailproofAI under a different Hermes profile.`,
1637
1681
  );
1638
1682
  }
1639
- if (existing.kind === "link" && existing.current) return "unchanged";
1683
+ if (existing.kind === "link" && existing.current) {
1684
+ // A link from a 1.0.9 beta was proven ours by provenance; record it now so
1685
+ // ownership no longer depends on where npm keeps the package.
1686
+ if (readHermesLinkRecord(destination) !== resolve(existing.target)) {
1687
+ try {
1688
+ writeHermesLinkRecord(destination, existing.target);
1689
+ } catch {
1690
+ // Provenance still proves it on the next run; not worth failing over.
1691
+ }
1692
+ }
1693
+ return "unchanged";
1694
+ }
1640
1695
 
1641
1696
  mkdirSync(dirname(destination), { recursive: true });
1642
1697
  const suffix = `${process.pid}-${Date.now()}`;
@@ -1673,6 +1728,7 @@ export function installHermesPlugin(
1673
1728
  if (linked && (existing.kind === "absent" || existing.kind === "link")) {
1674
1729
  try {
1675
1730
  renameSync(temporary, destination);
1731
+ writeHermesLinkRecord(destination, source);
1676
1732
  return "linked";
1677
1733
  } catch (err) {
1678
1734
  // Windows cannot always rename a junction over another junction; the
@@ -1695,6 +1751,8 @@ export function installHermesPlugin(
1695
1751
  renameSync(temporary, destination);
1696
1752
  // fs.rm never follows a symlink, so a backed-up link removes only itself.
1697
1753
  if (movedExisting) rmSync(backup, { recursive: true, force: true });
1754
+ if (linked) writeHermesLinkRecord(destination, source);
1755
+ else removeHermesLinkRecord(destination);
1698
1756
  } catch (err) {
1699
1757
  rmSync(temporary, { recursive: true, force: true });
1700
1758
  if (movedExisting && !pathPresent(destination) && pathPresent(backup)) {
@@ -1711,6 +1769,7 @@ function removeManagedHermesPlugin(settingsPath: string): boolean {
1711
1769
  if (state.kind === "link") {
1712
1770
  // Only the link goes; the package directory it points at is npm's.
1713
1771
  unlinkSync(pluginPath);
1772
+ removeHermesLinkRecord(pluginPath);
1714
1773
  return true;
1715
1774
  }
1716
1775
  // The marker is the ownership boundary. Remove even an incomplete managed
@@ -1748,28 +1807,44 @@ function removeLegacyHermesHooks(doc: Document): number {
1748
1807
  }
1749
1808
 
1750
1809
  function hermesConfigState(settingsPath: string): {
1810
+ /** Hermes will load it: listed in `plugins.enabled` AND not in `plugins.disabled`. */
1751
1811
  pluginEnabled: boolean;
1812
+ /** Listed in `plugins.enabled`, whatever `plugins.disabled` says. */
1813
+ pluginListed: boolean;
1814
+ /** Listed in `plugins.disabled`, which Hermes checks first and which wins. */
1815
+ pluginDisabled: boolean;
1752
1816
  legacyShellHookPresent: boolean;
1753
1817
  unreadable?: boolean;
1754
1818
  } {
1755
1819
  if (!existsSync(settingsPath)) {
1756
- return { pluginEnabled: false, legacyShellHookPresent: false };
1820
+ return { pluginEnabled: false, pluginListed: false, pluginDisabled: false, legacyShellHookPresent: false };
1757
1821
  }
1758
1822
  const doc = inspectYamlDoc(settingsPath);
1759
- if (!doc) return { pluginEnabled: false, legacyShellHookPresent: false, unreadable: true };
1823
+ if (!doc) {
1824
+ return { pluginEnabled: false, pluginListed: false, pluginDisabled: false, legacyShellHookPresent: false, unreadable: true };
1825
+ }
1760
1826
  const js = (doc.toJS() ?? {}) as {
1761
1827
  hooks?: Record<string, HermesHookEntry[]>;
1762
1828
  plugins?: HermesPluginsConfig;
1763
1829
  };
1764
1830
  const enabled = js.plugins?.enabled;
1831
+ const disabled = js.plugins?.disabled;
1765
1832
  const legacyShellHookPresent =
1766
1833
  !!js.hooks &&
1767
1834
  typeof js.hooks === "object" &&
1768
1835
  Object.values(js.hooks).some(
1769
1836
  (entries) => Array.isArray(entries) && entries.some((entry) => isMarkedHook(entry)),
1770
1837
  );
1838
+ // Hermes gates `plugins.disabled` before `plugins.enabled`
1839
+ // (hermes_cli/plugins_discovery.py `gate_manifest`), so a plugin in both
1840
+ // lists never loads. Treating that as enabled reported a switched-off plugin
1841
+ // healthy and let `update` skip it as "already current".
1842
+ const pluginListed = Array.isArray(enabled) && enabled.includes(HERMES_PLUGIN_ID);
1843
+ const pluginDisabled = Array.isArray(disabled) && disabled.includes(HERMES_PLUGIN_ID);
1771
1844
  return {
1772
- pluginEnabled: Array.isArray(enabled) && enabled.includes(HERMES_PLUGIN_ID),
1845
+ pluginEnabled: pluginListed && !pluginDisabled,
1846
+ pluginListed,
1847
+ pluginDisabled,
1773
1848
  legacyShellHookPresent,
1774
1849
  };
1775
1850
  }
@@ -1835,6 +1910,9 @@ export async function migrateHermesProfiles(opts: {
1835
1910
  const results: HermesProfileMigration[] = [];
1836
1911
  let daemonOk: boolean | undefined;
1837
1912
  for (const profile of listHermesProfiles()) {
1913
+ // One profile's surprise (a file removed mid-run, a permission change) is
1914
+ // that profile's failed line — never the end of the report for the rest.
1915
+ try {
1838
1916
  if (!existsSync(profile.home)) continue;
1839
1917
  const settingsPath = resolve(profile.home, "config.yaml");
1840
1918
  const pluginPath = hermesPluginPathForSettings(settingsPath);
@@ -1867,11 +1945,20 @@ export async function migrateHermesProfiles(opts: {
1867
1945
  continue;
1868
1946
  }
1869
1947
 
1870
- if (!legacy && !ours && !config.pluginEnabled) {
1948
+ if (!legacy && !ours && !config.pluginListed && !config.pluginDisabled) {
1871
1949
  results.push({ ...base, status: "untouched", detail: "no failproofai integration", legacyShellHooksRemain: false });
1872
1950
  continue;
1873
1951
  }
1874
1952
  if (plugin.kind === "link" && plugin.current && plugin.complete && config.pluginEnabled && !legacy) {
1953
+ // A link a 1.0.9 beta created was proven ours by provenance; record it
1954
+ // so ownership stops depending on where npm keeps the package.
1955
+ if (readHermesLinkRecord(pluginPath) !== resolve(plugin.target)) {
1956
+ try {
1957
+ writeHermesLinkRecord(pluginPath, plugin.target);
1958
+ } catch {
1959
+ // Provenance still proves it on the next run.
1960
+ }
1961
+ }
1875
1962
  results.push({ ...base, status: "current", detail: "already linked", legacyShellHooksRemain: false });
1876
1963
  continue;
1877
1964
  }
@@ -1886,19 +1973,6 @@ export async function migrateHermesProfiles(opts: {
1886
1973
  });
1887
1974
  continue;
1888
1975
  }
1889
- if (existsSync(settingsPath)) {
1890
- const errors = parseDocument(readFileSync(settingsPath, "utf8")).errors;
1891
- if (errors.length > 0) {
1892
- results.push({
1893
- ...base,
1894
- status: "failed",
1895
- detail: `${settingsPath} does not parse as YAML; left untouched`,
1896
- legacyShellHooksRemain: legacy,
1897
- });
1898
- continue;
1899
- }
1900
- }
1901
-
1902
1976
  if (daemonOk === undefined) daemonOk = await opts.daemonSupportsPolicyEvaluation();
1903
1977
  if (!daemonOk) {
1904
1978
  results.push({
@@ -1919,6 +1993,7 @@ export async function migrateHermesProfiles(opts: {
1919
1993
  const doc = readYamlDoc(settingsPath);
1920
1994
  enableHermesPluginInDoc(doc);
1921
1995
  writeYamlDoc(settingsPath, doc);
1996
+ const reenabledOnly = !legacy && plugin.kind === "link" && plugin.current && mode === "unchanged";
1922
1997
  const from = legacy
1923
1998
  ? "shell hooks"
1924
1999
  : plugin.kind === "copy"
@@ -1927,7 +2002,12 @@ export async function migrateHermesProfiles(opts: {
1927
2002
  ? "old plugin link"
1928
2003
  : "enabled but missing plugin";
1929
2004
  const to = mode === "copied" ? "plugin copy (symlink not possible here)" : "linked plugin";
1930
- results.push({ ...base, status: "migrated", detail: `${from} → ${to}`, legacyShellHooksRemain: false });
2005
+ const detail = reenabledOnly
2006
+ ? config.pluginDisabled
2007
+ ? "plugin re-enabled (was listed in plugins.disabled)"
2008
+ : "plugin enabled in config.yaml"
2009
+ : `${from} → ${to}`;
2010
+ results.push({ ...base, status: "migrated", detail, legacyShellHooksRemain: false });
1931
2011
  } catch (err) {
1932
2012
  results.push({
1933
2013
  ...base,
@@ -1936,6 +2016,15 @@ export async function migrateHermesProfiles(opts: {
1936
2016
  legacyShellHooksRemain: hermesConfigState(settingsPath).legacyShellHookPresent,
1937
2017
  });
1938
2018
  }
2019
+ } catch (err) {
2020
+ results.push({
2021
+ name: profile.name,
2022
+ home: profile.home,
2023
+ status: "failed",
2024
+ detail: `could not inspect this profile (${err instanceof Error ? err.message : String(err)}); left untouched`,
2025
+ legacyShellHooksRemain: false,
2026
+ });
2027
+ }
1939
2028
  }
1940
2029
  return results;
1941
2030
  }
@@ -1948,6 +2037,8 @@ export interface HermesProfileHealth {
1948
2037
  /** How the plugin is installed: a link into the package, a copy, or neither. */
1949
2038
  pluginMode: "link" | "copy" | null;
1950
2039
  pluginEnabled: boolean;
2040
+ /** failproofai is listed in `plugins.disabled`, so Hermes will not load it. */
2041
+ pluginDisabled: boolean;
1951
2042
  legacyShellHookPresent: boolean;
1952
2043
  /**
1953
2044
  * Still enforced only by legacy config.yaml shell hooks. Hermes cron jobs run
@@ -1956,6 +2047,8 @@ export interface HermesProfileHealth {
1956
2047
  cronUnchecked: boolean;
1957
2048
  /** config.yaml exists but does not parse; failproofai will not touch it. */
1958
2049
  configUnreadable: boolean;
2050
+ /** Another plugin (not provably FailproofAI's) occupies plugins/failproofai. */
2051
+ pluginForeign: boolean;
1959
2052
  healthy: boolean;
1960
2053
  }
1961
2054
 
@@ -1974,9 +2067,11 @@ export function hermesProfileHealth(): HermesProfileHealth[] {
1974
2067
  pluginInstalled,
1975
2068
  pluginMode: plugin.kind === "link" || plugin.kind === "copy" ? plugin.kind : null,
1976
2069
  pluginEnabled: config.pluginEnabled,
2070
+ pluginDisabled: config.pluginDisabled,
1977
2071
  legacyShellHookPresent: config.legacyShellHookPresent,
1978
2072
  cronUnchecked: config.legacyShellHookPresent && !pluginWorks,
1979
2073
  configUnreadable: config.unreadable === true,
2074
+ pluginForeign: plugin.kind === "foreign",
1980
2075
  healthy: pluginWorks && !config.legacyShellHookPresent && config.unreadable !== true,
1981
2076
  };
1982
2077
  });
@@ -1988,6 +2083,12 @@ export function hermesProfileStatusRows(): Array<[string, string]> {
1988
2083
  .filter((profile) => existsSync(profile.home))
1989
2084
  .map((profile) => {
1990
2085
  const label = "hermes/" + profile.name;
2086
+ if (profile.pluginForeign) {
2087
+ return [
2088
+ label,
2089
+ `UNHEALTHY — another plugin occupies ${resolve(profile.home, "plugins", "failproofai")}; failproofai will not replace it. Move it aside, then run update`,
2090
+ ];
2091
+ }
1991
2092
  if (profile.configUnreadable) {
1992
2093
  return [label, `UNHEALTHY — ${profile.settingsPath} does not parse; failproofai leaves it untouched until it is fixed`];
1993
2094
  }
@@ -2001,7 +2102,8 @@ export function hermesProfileStatusRows(): Array<[string, string]> {
2001
2102
  }
2002
2103
  const problems: string[] = [];
2003
2104
  if (!profile.pluginInstalled) problems.push("plugin files missing or incomplete");
2004
- if (!profile.pluginEnabled) problems.push("plugin not enabled");
2105
+ if (profile.pluginDisabled) problems.push("plugin disabled (listed in plugins.disabled)");
2106
+ else if (!profile.pluginEnabled) problems.push("plugin not enabled");
2005
2107
  if (profile.legacyShellHookPresent) problems.push("legacy shell hook also present");
2006
2108
  if (problems.length > 0) return [label, "UNHEALTHY — " + problems.join("; ")];
2007
2109
  return [
@@ -29,12 +29,14 @@
29
29
  import {
30
30
  chmodSync,
31
31
  closeSync,
32
+ constants as fsConstants,
32
33
  copyFileSync,
33
34
  existsSync,
34
35
  fsyncSync,
35
36
  lstatSync,
36
37
  mkdirSync,
37
38
  openSync,
39
+ readlinkSync,
38
40
  realpathSync,
39
41
  renameSync,
40
42
  rmSync,
@@ -52,26 +54,97 @@ export function configBackupPath(path: string): string {
52
54
  /** Hooks for tests to simulate an interruption at the one step that matters. */
53
55
  export interface AtomicWriteDeps {
54
56
  rename?: (from: string, to: string) => void;
57
+ /** Keep `<name>.failproofai-backup` of the previous version (default true). */
58
+ backup?: boolean;
59
+ /**
60
+ * What to do when the path is a symlink. `follow` (default) writes through to
61
+ * the target — right for a user's config, which is read and parsed before it
62
+ * is written and may live in a dotfiles checkout. `replace` swaps the link
63
+ * itself for the new file and never touches what it pointed at — right for a
64
+ * file failproofai generates and fully owns (a plugin shim, an ownership
65
+ * record), which is written without being read, so a planted link must not
66
+ * steer the write into another file.
67
+ */
68
+ symlinks?: "follow" | "replace";
55
69
  }
56
70
 
57
- /** A symlinked config is written through to what it points at. */
71
+ /** A config that is a symlink to nothing: writing would either replace the link or create a file somewhere unknown. */
72
+ export class DanglingConfigSymlinkError extends Error {
73
+ constructor(readonly path: string, readonly target: string) {
74
+ super(
75
+ `Refusing to write ${path}: it is a symlink to ${target}, which does not exist. ` +
76
+ `Fix or remove the link, then retry — failproofai will not replace it with a regular file.`,
77
+ );
78
+ this.name = "DanglingConfigSymlinkError";
79
+ }
80
+ }
81
+
82
+ /**
83
+ * A symlinked config is written through to what it points at, so a dotfiles
84
+ * checkout keeps its link. A link whose target does not exist is refused: the
85
+ * rename would replace the link with a regular file (silently detaching the
86
+ * dotfiles), and creating the target instead would write wherever the link
87
+ * says — a path a cloned repository can choose for a project-scoped config.
88
+ */
58
89
  function resolveWriteTarget(path: string): string {
90
+ let isLink = false;
91
+ try {
92
+ isLink = lstatSync(path).isSymbolicLink();
93
+ } catch {
94
+ return path; // absent: a new file at the path as given
95
+ }
96
+ if (!isLink) return path;
97
+ try {
98
+ return realpathSync(path);
99
+ } catch {
100
+ let target = "(unreadable link)";
101
+ try {
102
+ target = readlinkSync(path);
103
+ } catch {
104
+ // keep the placeholder
105
+ }
106
+ throw new DanglingConfigSymlinkError(path, target);
107
+ }
108
+ }
109
+
110
+ function isSymlink(path: string): boolean {
59
111
  try {
60
- if (lstatSync(path).isSymbolicLink()) return realpathSync(path);
112
+ return lstatSync(path).isSymbolicLink();
61
113
  } catch {
62
- // Absent or unreadable: write to the path as given.
114
+ return false;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Keep the previous version beside the file without ever following a link that
120
+ * sits where the backup goes. `copyFileSync` onto `<name>.failproofai-backup`
121
+ * would write THROUGH a symlink planted there — for a project-scoped config
122
+ * inside a cloned repository, into any file the user can write. So the copy
123
+ * goes to a fresh, exclusively created temp file and is renamed over the backup
124
+ * path: a rename replaces a symlink, it does not follow one.
125
+ */
126
+ function writeBackup(target: string, dir: string): void {
127
+ const backup = `${target}.failproofai-backup`;
128
+ const temporary = join(dir, `.${basename(target)}.failproofai-backup-${process.pid}-${randomBytes(4).toString("hex")}.tmp`);
129
+ try {
130
+ copyFileSync(target, temporary, fsConstants.COPYFILE_EXCL);
131
+ renameSync(temporary, backup);
132
+ } catch (err) {
133
+ rmSync(temporary, { force: true });
134
+ throw err;
63
135
  }
64
- return path;
65
136
  }
66
137
 
67
138
  export function writeConfigFileAtomic(path: string, content: string, deps: AtomicWriteDeps = {}): void {
68
- const target = resolveWriteTarget(path);
139
+ const replacingLink = deps.symlinks === "replace" && isSymlink(path);
140
+ const target = deps.symlinks === "replace" ? path : resolveWriteTarget(path);
69
141
  const dir = dirname(target);
70
142
  mkdirSync(dir, { recursive: true });
71
143
 
72
144
  let mode: number | undefined;
73
145
  try {
74
- mode = statSync(target).mode & 0o777;
146
+ // A link being replaced lends nothing: its target's mode is someone else's.
147
+ mode = replacingLink ? undefined : statSync(target).mode & 0o777;
75
148
  } catch {
76
149
  mode = undefined; // a new file: the process umask decides, as writeFileSync would
77
150
  }
@@ -89,7 +162,7 @@ export function writeConfigFileAtomic(path: string, content: string, deps: Atomi
89
162
  // `open` applies the umask; the live file's own bits are what should survive.
90
163
  if (mode !== undefined) chmodSync(temporary, mode);
91
164
 
92
- if (existsSync(target)) copyFileSync(target, `${target}.failproofai-backup`);
165
+ if (deps.backup !== false && !replacingLink && existsSync(target)) writeBackup(target, dir);
93
166
 
94
167
  (deps.rename ?? renameSync)(temporary, target);
95
168
  } catch (err) {
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,70915,e=>{"use strict";var t=e.i(95187);let r=(0,t.createServerReference)("00a9163b93014ab406fd89a6249f844ab47fada4df",t.callServer,void 0,t.findSourceMapURL,"getTelemetryConfig");e.s(["getTelemetryConfig",0,r])},97917,e=>{"use strict";var t=e.i(71645),r=e.i(9969);let n=/\b[\w-]+-extension:\/\//i;function o(e){return"app"===function({stack:e,filename:t,appOrigin:r}){let o=[t,e].filter(Boolean).join("\n");return o.trim()?n.test(o)?"extension":r&&o.includes(r)?"app":"unknown":"unknown"}(e)}e.s(["GlobalErrorListeners",0,function(){return(0,t.useEffect)(()=>{let e=e=>{o({stack:e.error?.stack,filename:e.filename,appOrigin:window.location.origin})&&(0,r.captureClientEvent)("unhandled_exception",{error_message:e.message,error_name:e.error?.name,error_filename:e.filename,error_lineno:e.lineno,error_colno:e.colno})},t=e=>{let t=e.reason;o({stack:t instanceof Error?t.stack:void 0,appOrigin:window.location.origin})&&(0,r.captureClientEvent)("unhandled_rejection",{error_message:t instanceof Error?t.message:String(t),error_name:t instanceof Error?t.name:void 0})};return window.addEventListener("error",e),window.addEventListener("unhandledrejection",t),()=>{window.removeEventListener("error",e),window.removeEventListener("unhandledrejection",t)}},[]),null}],97917)},55574,e=>{"use strict";var t=e.i(43476),r=e.i(71645);let n=[],o=0,a=new Set;function i(){for(let e of a)e()}function s(e){return a.add(e),()=>a.delete(e)}function l(){return n}function u({message:e}){let[n,o]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{requestAnimationFrame(()=>o(!0));let e=setTimeout(()=>o(!1),2e3);return()=>clearTimeout(e)},[]),(0,t.jsx)("div",{className:`bg-card border border-border text-foreground text-sm px-4 py-2 rounded-lg shadow-lg transition-opacity duration-300 ${n?"opacity-100":"opacity-0"}`,children:e})}e.s(["Toaster",0,function(){let e=(0,r.useSyncExternalStore)(s,l,l);return(0,t.jsx)("div",{className:"fixed bottom-4 right-4 z-50 flex flex-col gap-2",children:e.map(e=>(0,t.jsx)(u,{message:e.message},e.id))})},"toast",0,function(e){let t=o++;n=[...n,{id:t,message:e}],i(),setTimeout(()=>{n=n.filter(e=>e.id!==t),i()},2500)}])},63780,e=>{"use strict";var t=e.i(43476),r=e.i(22016),n=e.i(18566),o=e.i(66794),a=e.i(71645),i=e.i(56420);let s={name:"git-branch",size:24,node:[["path",{d:"M15 6a9 9 0 0 0-9 9V3",key:"1cii5b"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}]]};s.node;let l=(0,i.default)(s);var u=e.i(16327);let c={name:"star",size:24,node:[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]]};c.node;let d=(0,i.default)(c),f={name:"book-open",size:24,node:[["path",{d:"M12 5v16",key:"1f6ucr"}],["path",{d:"M20.001 19A2 2 0 0022 17V5a2 2 0 00-1.999-2L16 3.002A5 5 0 0012 5a5 5 0 00-4-2H4a2 2 0 00-2 2v12a2 2 0 001.999 2H8a5 5 0 014 2 5 5 0 014-2z",key:"1fyvmf"}]]};f.node;let h=(0,i.default)(f),p={name:"message-circle",size:24,node:[["path",{d:"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",key:"1sd12s"}]]};p.node;let m=(0,i.default)(p),g={name:"messages-square",size:24,node:[["path",{d:"M16 10a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 14.286V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z",key:"1n2ejm"}],["path",{d:"M20 9a2 2 0 0 1 2 2v10.286a.71.71 0 0 1-1.212.502l-2.202-2.202A2 2 0 0 0 17.172 19H10a2 2 0 0 1-2-2v-1",key:"1qfcsi"}]]};g.node;let b=(0,i.default)(g),v={name:"message-square-warning",size:24,node:[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}],["path",{d:"M12 15h.01",key:"q59x07"}],["path",{d:"M12 7v4",key:"xawao1"}]]};v.node;let y=(0,i.default)(v);var x=e.i(67881);let w="failproofai@exosphere.host",j=[{label:"Star us on GitHub",icon:d,href:"https://github.com/failproofai/failproofai",color:"#f5c842",bg:"rgba(245,200,66,0.08)"},{label:"Documentation",icon:h,href:"https://docs.befailproof.ai/introduction",color:"#60a5fa",bg:"rgba(96,165,250,0.08)"},{label:"Join our Discord",icon:m,href:"https://discord.befailproof.ai/",color:"#5865f2",bg:"rgba(88,101,242,0.08)"},{label:"Join r/failproofai",icon:b,href:"https://www.reddit.com/r/failproofai/",color:"#ff4500",bg:"rgba(255,69,0,0.08)"},{label:"Feedback & Issues",icon:y,href:"https://github.com/FailproofAI/failproofai/issues/new/choose",color:"#34d399",bg:"rgba(52,211,153,0.08)"}],k=()=>{let[e,r]=(0,a.useState)(!1),n=(0,a.useCallback)(()=>r(!1),[]),o=(0,a.useCallback)(e=>{"Escape"===e.key&&r(!1)},[]);return(0,t.jsxs)("div",{className:"relative",onKeyDown:o,children:[e&&(0,t.jsx)("div",{className:"fixed inset-0 z-40",onClick:n,"aria-hidden":"true"}),(0,t.jsxs)(x.Button,{type:"button",variant:"ghost",size:"sm",onClick:()=>r(e=>!e),"aria-expanded":e,"aria-haspopup":"true",className:"relative z-50 flex items-center gap-1.5 text-muted-foreground hover:text-foreground",children:[(0,t.jsx)(l,{className:"h-4 w-4"}),(0,t.jsx)("span",{className:"hidden sm:inline text-xs whitespace-nowrap",children:"Reach Us"}),(0,t.jsx)(u.ChevronDown,{className:`h-3 w-3 transition-transform ${e?"rotate-180":""}`})]}),e&&(0,t.jsxs)("div",{className:"absolute right-0 mt-2 w-60 rounded-lg border border-border bg-card shadow-xl z-50",role:"menu",style:{boxShadow:"0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.04)"},children:[(0,t.jsxs)("div",{className:"px-3 py-2.5 border-b border-border",style:{background:"linear-gradient(135deg, rgba(236,72,153,0.12) 0%, rgba(139,92,246,0.08) 100%)"},children:[(0,t.jsx)("p",{className:"text-xs font-semibold",style:{color:"#e879f9",letterSpacing:"0.06em"},children:"Reach Developers"}),(0,t.jsx)("p",{className:"text-[0.65rem] text-muted-foreground mt-0.5",children:"We'd love to hear from you"})]}),(0,t.jsx)("div",{className:"py-1",children:j.map(({label:e,icon:r,href:o,color:a,bg:i})=>(0,t.jsxs)("a",{href:o,target:"_blank",rel:"noopener noreferrer",role:"menuitem",className:"flex items-center gap-2.5 px-3 py-2 text-xs transition-colors",style:{color:"var(--muted-foreground)"},onMouseEnter:e=>{e.currentTarget.style.background=i,e.currentTarget.style.color=a},onMouseLeave:e=>{e.currentTarget.style.background="",e.currentTarget.style.color=""},onClick:n,children:[(0,t.jsx)(r,{className:"h-3.5 w-3.5 flex-shrink-0",style:{color:a}}),e]},e))}),(0,t.jsx)("div",{className:"px-3 py-2 border-t border-border",style:{background:"rgba(0,0,0,0.2)"},children:(0,t.jsxs)("p",{className:"text-[0.65rem] text-muted-foreground",children:["or email"," ",(0,t.jsx)("a",{href:`mailto:${w}`,className:"transition-colors",style:{color:"#e879f9"},onMouseEnter:e=>e.currentTarget.style.opacity="0.75",onMouseLeave:e=>e.currentTarget.style.opacity="1",children:w})]})})]})]})},N={name:"refresh-cw",size:24,node:[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]};N.node;let S=(0,i.default)(N);var C=e.i(47163),E=e.i(85881);let _=[{label:"Off",value:0},{label:"5s",value:5},{label:"10s",value:10},{label:"30s",value:30}];function P({className:e}){let r=(0,n.useRouter)(),[o,i]=(0,a.useTransition)(),{intervalSec:s,setIntervalSec:l}=(0,E.useAutoRefresh)(),u=(0,a.useCallback)(()=>{i(()=>r.refresh())},[r]);(0,a.useEffect)(()=>{if(s<=0)return;let e=setInterval(u,1e3*s);return()=>clearInterval(e)},[s,u]);let c=s>0;return(0,t.jsxs)("div",{className:(0,C.cn)("inline-flex items-center rounded-lg border border-border bg-muted/50 p-0.5 gap-0.5",e),children:[(0,t.jsx)("button",{onClick:u,title:"Refresh",className:(0,C.cn)("inline-flex items-center justify-center rounded-md p-1.5 transition-colors",c?"text-primary hover:bg-primary/10":"text-muted-foreground hover:text-foreground hover:bg-muted"),children:(0,t.jsx)(S,{className:(0,C.cn)("w-3.5 h-3.5",o&&"animate-spin")})}),(0,t.jsx)("div",{className:"w-px h-4 bg-border"}),(0,t.jsx)("div",{className:"inline-flex items-center gap-0.5",role:"group","aria-label":"Auto-refresh interval",children:_.map(e=>(0,t.jsx)("button",{onClick:()=>l(e.value),"aria-pressed":s===e.value,className:(0,C.cn)("px-2 py-1 text-[11px] font-medium rounded-md transition-colors",s===e.value?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground hover:bg-muted"),children:e.label},e.value))})]})}var T=e.i(12344);let R=[{href:"/projects",label:"projects"},{href:"/policies",label:"policies"},{href:"/audit",label:"audit"}];e.s(["Navbar",0,({disabledPages:e=[]})=>{let a=(0,n.usePathname)(),{capture:i}=(0,T.usePostHog)(),s=a.startsWith("/policies")?"policies":a.startsWith("/audit")?"audit":a.startsWith("/settings")?"settings":a.startsWith("/projects")||a.startsWith("/project/")?"projects":"";return(0,t.jsxs)("header",{className:"app-header",children:[(0,t.jsx)("a",{href:"https://github.com/failproofai/failproofai",target:"_blank",rel:"noopener noreferrer",className:"h-brand",style:{flex:"none"},"aria-label":"failproof ai · GitHub",children:(0,t.jsx)("img",{src:"/logo.svg",alt:"failproof_ai",style:{height:18,display:"block",flexShrink:0}})}),(0,t.jsx)("nav",{className:"tabs",style:{border:"none",padding:0,gap:0},children:R.filter(({href:t})=>{let r=t.slice(1);return!e.includes(r)}).map(({href:e,label:n})=>{let o="/projects"===e?"/projects"===a||a.startsWith("/project/"):a.startsWith(e);return(0,t.jsx)(r.default,{href:e,className:`tab${o?" is-active":""}`,"aria-current":o?"page":void 0,onClick:()=>{"/audit"===e&&i("audit_nav_clicked",{from_path:a,is_active_tab:o})},children:n},e)})}),(0,t.jsx)("div",{style:{flex:1}}),(0,t.jsxs)("div",{className:"h-meta",children:[(0,t.jsxs)("span",{className:"h-version",children:["v","1.0.9-beta.1"]}),s&&(0,t.jsx)("span",{className:"h-brand-sep","aria-hidden":"true",children:"·"}),s&&(0,t.jsx)("span",{className:"h-brand-section",children:s})]}),(0,t.jsxs)("div",{className:"h-actions",children:[(0,t.jsx)(P,{}),(0,t.jsx)("span",{style:{width:1,height:18,background:"var(--line)",margin:"0 6px"}}),!e.includes("settings")&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.default,{href:"/settings",className:`h-icon-btn${a.startsWith("/settings")?" is-active":""}`,"aria-label":"settings","aria-current":a.startsWith("/settings")?"page":void 0,title:"settings",children:(0,t.jsx)(o.Settings,{className:"w-3.5 h-3.5",strokeWidth:1.75,"aria-hidden":"true"})}),(0,t.jsx)("span",{style:{width:1,height:18,background:"var(--line)",margin:"0 6px"}})]}),(0,t.jsx)(k,{})]})]})}],63780)},67881,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(47163);let o=r.forwardRef(({className:e,variant:r="default",size:o="default",...a},i)=>(0,t.jsx)("button",{className:(0,n.cn)("inline-flex items-center justify-center rounded-md text-sm font-medium transition-[background-color,color,box-shadow,border-color] duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:opacity-50 disabled:pointer-events-none",{"bg-primary text-primary-foreground hover:bg-primary/90 hover:shadow-[0_0_0_1px_var(--primary)]":"default"===r,"text-foreground hover:bg-muted":"ghost"===r,"border border-border bg-transparent hover:border-primary/60 hover:bg-card":"outline"===r,"h-10 py-2 px-4":"default"===o,"h-10 w-10":"icon"===o,"h-9 px-3":"sm"===o,"h-11 px-8":"lg"===o},e),ref:i,...a}));o.displayName="Button",e.s(["Button",0,o])},85881,e=>{"use strict";var t=e.i(43476),r=e.i(71645);let n=(0,r.createContext)(void 0);e.s(["AutoRefreshProvider",0,function({children:e}){let[o,a]=(0,r.useState)(0);return(0,t.jsx)(n.Provider,{value:{intervalSec:o,setIntervalSec:a},children:e})},"useAutoRefresh",0,function(){let e=(0,r.useContext)(n);if(!e)throw Error("useAutoRefresh must be used within AutoRefreshProvider");return e}])},12344,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(18566),o=e.i(70915),a=e.i(9969);let i=(0,r.createContext)(void 0);e.s(["PostHogProvider",0,function({children:e}){let s=(0,n.usePathname)(),l=(0,r.useRef)(null),u=(0,r.useRef)(!1);(0,r.useEffect)(()=>{let e=!1;return(0,o.getTelemetryConfig)().then(t=>{e||((0,a.setClientTelemetryConfig)(t),u.current=!0,(0,a.captureClientEvent)("$pageview"),l.current=window.location.pathname)}),()=>{e=!0}},[]),(0,r.useEffect)(()=>{u.current&&l.current!==s&&(l.current=s,(0,a.captureClientEvent)("$pageview"))},[s]);let c=r.default.useCallback((e,t)=>{(0,a.captureClientEvent)(e,t)},[]);return(0,t.jsx)(i.Provider,{value:{capture:c},children:e})},"usePostHog",0,function(){let e=(0,r.useContext)(i);if(void 0===e)throw Error("usePostHog must be used within a PostHogProvider");return e}])},9969,e=>{"use strict";let t=null;e.s(["captureClientEvent",0,function(e,r){if(!t||!t.enabled)return;let n=JSON.stringify({api_key:t.apiKey,event:e,distinct_id:t.distinctId,properties:{...r,$lib:"failproofai-web",failproofai_version:t.version,product:"failproofai-oss",$current_url:window.location.href,$pathname:window.location.pathname}});fetch(t.host.replace(/\/+$/,"")+"/capture/",{method:"POST",headers:{"Content-Type":"application/json"},body:n,keepalive:!0,signal:AbortSignal.timeout(5e3)}).catch(()=>{})},"setClientTelemetryConfig",0,function(e){t=e}],9969)},5014,e=>{"use strict";var t=e.i(71645);let r=(...e)=>e.filter((e,t,r)=>!!e&&""!==e.trim()&&r.indexOf(e)===t).join(" ").trim(),n={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"},o=(0,t.createContext)({}),a=(0,t.forwardRef)(({color:e,size:a,width:i,height:s,strokeWidth:l,absoluteStrokeWidth:u,nonScalingStroke:c,className:d="",children:f,iconNode:h=[],icon:p={node:h,aliases:[],size:24},...m},g)=>{let{size:b=24,strokeWidth:v=2,absoluteStrokeWidth:y=!1,nonScalingStroke:x=!1,color:w="currentColor",className:j=""}=(0,t.useContext)(o)??{},k=!!f||(e=>{for(let t in e)if(t.startsWith("aria-")||"role"===t||"title"===t)return!0;return!1})(m),[N,S,C=[]]=function(e,t={}){return function(e,t={}){let o=t.attributeNames??{},a=e=>o[e]??e,i=e.size??e.width??n.width,s=e.size??e.height??n.height,l=e.aliases?.filter(e=>"string"==typeof e&&""!==e.trim()).map(e=>`lucide-${e}`)??[],u=[...e.name?[`lucide-${e.name}`]:[],...l],c=t.className?.split(" ").filter(Boolean)??[],d=!1===t.includeDefaultClasses?r(...c):r("lucide",...u,...c),f=t.absoluteStrokeWidth?Number(t.strokeWidth??n["stroke-width"])*Number(e.size??e.width??n.width)/Number(t.size??t.width??n.width):t.strokeWidth??n["stroke-width"];return["svg",{...Object.entries(n).reduce((e,[t,r])=>(e[a(t)]=r,e),{}),..."color"in t&&t.color&&{[a("stroke")]:t.color},..."size"in t&&null!=t.size&&{[a("width")]:t.size,[a("height")]:t.size},..."width"in t&&null!=t.width&&{[a("width")]:t.width},..."height"in t&&null!=t.height&&{[a("height")]:t.height},[a("stroke-width")]:f,...d&&{[a("class")]:d},[a("viewBox")]:`0 0 ${i} ${s}`,...!1===t.hasA11yProp?{[a("aria-hidden")]:"true"}:{},..."attributes"in t&&t.attributes},e.node.map(e=>{let[r,n,o]=e,i=t.nonScalingStroke?{[a("vector-effect")]:"non-scaling-stroke",...n}:n;return o?[r,i,o]:[r,i]})]}(e,{...t,attributeNames:{...t.attributeNames,class:"className","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","stroke-linejoin":"strokeLinejoin","vector-effect":"vectorEffect"}})}(p,{color:e??w,width:i??a??b,height:s??a??b,strokeWidth:l??v,absoluteStrokeWidth:u??y,nonScalingStroke:c??x,className:r(j,d),hasA11yProp:k,attributes:m});return(0,t.createElement)(N,{ref:g,...S},[...C.map(([e,r])=>(0,t.createElement)(e,r)),...Array.isArray(f)?f:[f]])});e.s(["default",0,a],5014)},56420,e=>{"use strict";var t=e.i(71645),r=e.i(5014);e.s(["default",0,function(e,n=[],o=[]){let a,i="string"==typeof e?function(e,t,r=[]){if(null==t)throw Error("[lucide]: iconNode is required when icon name is used");return{name:e?.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),size:24,node:t,...r.length>0?{aliases:r}:{}}}(e,n,o):e,s=(0,t.forwardRef)(({className:e,...n},o)=>(0,t.createElement)(r.default,{ref:o,icon:i,className:e,...n}));return i.name&&(s.displayName=(a=(e=>{let t="",r=!1;for(let n of e){if("-"===n||"_"===n||n<=" "){r=t.length>0;continue}0===t.length?t+=n.toLowerCase():t+=r?n.toUpperCase():n,r=!1}return t})(i.name)).charAt(0).toUpperCase()+a.slice(1)),s}],56420)},16327,e=>{"use strict";var t=e.i(56420);let r={name:"chevron-down",size:24,node:[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]};r.node;let n=(0,t.default)(r);e.s(["ChevronDown",0,n],16327)},66794,e=>{"use strict";var t=e.i(56420);let r={name:"settings",size:24,node:[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]};r.node;let n=(0,t.default)(r);e.s(["Settings",0,n],66794)},95187,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={callServer:function(){return a.callServer},createServerReference:function(){return s.createServerReference},findSourceMapURL:function(){return i.findSourceMapURL}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=e.r(32120),i=e.r(92245),s=e.r(35326)},22016,(e,t,r)=>{"use strict";e.i(47167),Object.defineProperty(r,"__esModule",{value:!0});var n={default:function(){return b},useLinkStatus:function(){return y}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=e.r(90809),i=e.r(43476),s=a._(e.r(71645)),l=e.r(95057),u=e.r(8372),c=e.r(18581),d=e.r(18967),f=e.r(5550),h=e.r(88540),p=e.r(91949),m=e.r(73668),g=e.r(9396);function b(t){var r;let n,o,a,[b,y]=(0,s.useOptimistic)(p.IDLE_LINK_STATUS),x=(0,s.useRef)(null),{href:w,as:j,children:k,prefetch:N=null,passHref:S,replace:C,shallow:E,scroll:_,onClick:P,onMouseEnter:T,onTouchStart:R,legacyBehavior:O=!1,onNavigate:A,transitionTypes:M,ref:L,unstable_dynamicOnHover:z,...$}=t;n=k,O&&("string"==typeof n||"number"==typeof n)&&(n=(0,i.jsx)("a",{children:n}));let U=s.default.useContext(u.AppRouterContext),I=!1!==N,W=!1===N?"none":!0===N?"full":"auto",B="none"!==W?"auto"===W?g.FetchStrategy.PPR:g.FetchStrategy.Full:g.FetchStrategy.PPR,D="string"==typeof(r=j||w)?r:(0,l.formatUrl)(r);if(O){if(n?.$$typeof===Symbol.for("react.lazy"))throw Object.defineProperty(Error("`<Link legacyBehavior>` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link's `<a>` tag."),"__NEXT_ERROR_CODE",{value:"E863",enumerable:!1,configurable:!0});o=s.default.Children.only(n)}let F=O?o&&"object"==typeof o&&o.ref:L,H,q=s.default.useCallback(e=>(null!==U&&(x.current=(0,p.mountLinkInstance)(e,D,U,B,I,y,H)),()=>{x.current&&((0,p.unmountLinkForCurrentNavigation)(x.current),x.current=null),(0,p.unmountPrefetchableInstance)(e)}),[I,D,U,B,y,H]),K={ref:(0,c.useMergedRef)(q,F),onClick(t){O||"function"!=typeof P||P(t),O&&o.props&&"function"==typeof o.props.onClick&&o.props.onClick(t),!U||t.defaultPrevented||function(t,r,n,o,a,i,l,u="none"){if("u">typeof window){let c,{nodeName:d}=t.currentTarget;if("A"===d.toUpperCase()&&((c=t.currentTarget.getAttribute("target"))&&"_self"!==c||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.nativeEvent&&2===t.nativeEvent.which)||t.currentTarget.hasAttribute("download"))return;if(!(0,m.isLocalURL)(r)){o&&(t.preventDefault(),location.replace(r));return}if(t.preventDefault(),i){let e=!1;if(i({preventDefault:()=>{e=!0}}),e)return}let{dispatchNavigateAction:f}=e.r(99781);s.default.startTransition(()=>{f(r,o?"replace":"push",!1===a?h.ScrollBehavior.NoScroll:h.ScrollBehavior.Default,n.current,l,u)})}}(t,D,x,C,_,A,M,W)},onMouseEnter(e){O||"function"!=typeof T||T(e),O&&o.props&&"function"==typeof o.props.onMouseEnter&&o.props.onMouseEnter(e),U&&I&&(0,p.onNavigationIntent)(e.currentTarget,!0===z)},onTouchStart:function(e){O||"function"!=typeof R||R(e),O&&o.props&&"function"==typeof o.props.onTouchStart&&o.props.onTouchStart(e),U&&I&&(0,p.onNavigationIntent)(e.currentTarget,!0===z)}};return(0,d.isAbsoluteUrl)(D)?K.href=D:O&&!S&&("a"!==o.type||"href"in o.props)||(K.href=(0,f.addBasePath)(D)),a=O?s.default.cloneElement(o,K):(0,i.jsx)("a",{...$,...K,children:n}),(0,i.jsx)(v.Provider,{value:b,children:a})}let v=(0,s.createContext)(p.IDLE_LINK_STATUS),y=()=>(0,s.useContext)(v);("function"==typeof r.default||"object"==typeof r.default&&null!==r.default)&&void 0===r.default.__esModule&&(Object.defineProperty(r.default,"__esModule",{value:!0}),Object.assign(r.default,r),t.exports=r.default)},18581,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"useMergedRef",{enumerable:!0,get:function(){return o}});let n=e.r(71645);function o(e,t){let r=(0,n.useRef)(null),o=(0,n.useRef)(null);return(0,n.useCallback)(n=>{if(null===n){let e=r.current;e&&(r.current=null,e());let t=o.current;t&&(o.current=null,t())}else e&&(r.current=a(e,n)),t&&(o.current=a(t,n))},[e,t])}function a(e,t){if("function"!=typeof e)return e.current=t,()=>{e.current=null};{let r=e(t);return"function"==typeof r?r:()=>e(null)}}("function"==typeof r.default||"object"==typeof r.default&&null!==r.default)&&void 0===r.default.__esModule&&(Object.defineProperty(r.default,"__esModule",{value:!0}),Object.assign(r.default,r),t.exports=r.default)},18967,(e,t,r)=>{"use strict";e.i(47167),Object.defineProperty(r,"__esModule",{value:!0});var n={DecodeError:function(){return b},MiddlewareNotFoundError:function(){return w},MissingStaticPage:function(){return x},NormalizeError:function(){return v},PageNotFoundError:function(){return y},SP:function(){return m},ST:function(){return g},WEB_VITALS:function(){return a},execOnce:function(){return i},getDisplayName:function(){return d},getLocationOrigin:function(){return u},getURL:function(){return c},isAbsoluteUrl:function(){return l},isResSent:function(){return f},loadGetInitialProps:function(){return p},normalizeRepeatedSlashes:function(){return h},stringifyError:function(){return j}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=["CLS","FCP","FID","INP","LCP","TTFB"];function i(e){let t,r=!1;return(...n)=>(r||(r=!0,t=e(...n)),t)}let s=/^[a-zA-Z][a-zA-Z\d+\-.]*?:/,l=e=>{let t=e.charCodeAt(0);return!!(t>=65&&t<=90||t>=97&&t<=122)&&s.test(e)};function u(){let{protocol:e,hostname:t,port:r}=window.location;return`${e}//${t}${r?":"+r:""}`}function c(){let{href:e}=window.location,t=u();return e.substring(t.length)}function d(e){return"string"==typeof e?e:e.displayName||e.name||"Unknown"}function f(e){return e.finished||e.headersSent}function h(e){let t=e.split("?");return t[0].replace(/\\/g,"/").replace(/\/\/+/g,"/")+(t[1]?`?${t.slice(1).join("?")}`:"")}async function p(e,t){let r=t.res||t.ctx&&t.ctx.res;if(!e.getInitialProps)return t.ctx&&t.Component?{pageProps:await p(t.Component,t.ctx)}:{};let n=await e.getInitialProps(t);if(r&&f(r))return n;if(!n)throw Object.defineProperty(Error(`"${d(e)}.getInitialProps()" should resolve to an object. But found "${n}" instead.`),"__NEXT_ERROR_CODE",{value:"E1025",enumerable:!1,configurable:!0});return n}let m="u">typeof performance,g=m&&["mark","measure","getEntriesByName"].every(e=>"function"==typeof performance[e]);class b extends Error{}class v extends Error{}class y extends Error{constructor(e){super(),this.code="ENOENT",this.name="PageNotFoundError",this.message=`Cannot find module for page: ${e}`}}class x extends Error{constructor(e,t){super(),this.message=`Failed to load static file for page: ${e} ${t}`}}class w extends Error{constructor(){super(),this.code="ENOENT",this.message="Cannot find the middleware module"}}function j(e){return JSON.stringify({message:e.message,stack:e.stack})}},73668,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"isLocalURL",{enumerable:!0,get:function(){return a}});let n=e.r(18967),o=e.r(52817);function a(e){if(!(0,n.isAbsoluteUrl)(e))return!0;try{let t=(0,n.getLocationOrigin)(),r=new URL(e,t);return r.origin===t&&(0,o.hasBasePath)(r.pathname)}catch(e){return!1}}},98183,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={assign:function(){return l},searchParamsToUrlQuery:function(){return a},urlQueryToSearchParams:function(){return s}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});function a(e){let t={};for(let[r,n]of e.entries()){let e=t[r];void 0===e?t[r]=n:Array.isArray(e)?e.push(n):t[r]=[e,n]}return t}function i(e){return"string"==typeof e?e:("number"!=typeof e||isNaN(e))&&"boolean"!=typeof e?"":String(e)}function s(e){let t=new URLSearchParams;for(let[r,n]of Object.entries(e))if(Array.isArray(n))for(let e of n)t.append(r,i(e));else t.set(r,i(n));return t}function l(e,...t){for(let r of t){for(let t of r.keys())e.delete(t);for(let[t,n]of r.entries())e.append(t,n)}return e}},95057,(e,t,r)=>{"use strict";e.i(47167),Object.defineProperty(r,"__esModule",{value:!0});var n={formatUrl:function(){return s},formatWithValidation:function(){return u},urlObjectKeys:function(){return l}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=e.r(90809)._(e.r(98183)),i=/https?|ftp|gopher|file/;function s(e){let{auth:t,hostname:r}=e,n=e.protocol||"",o=e.pathname||"",s=e.hash||"",l=e.query||"",u=!1;t=t?encodeURIComponent(t).replace(/%3A/i,":")+"@":"",e.host?u=t+e.host:r&&(u=t+(~r.indexOf(":")?`[${r}]`:r),e.port&&(u+=":"+e.port)),l&&"object"==typeof l&&(l=String(a.urlQueryToSearchParams(l)));let c=e.search||l&&`?${l}`||"";return n&&!n.endsWith(":")&&(n+=":"),e.slashes||(!n||i.test(n))&&!1!==u?(u="//"+(u||""),o&&"/"!==o[0]&&(o="/"+o)):u||(u=""),s&&"#"!==s[0]&&(s="#"+s),c&&"?"!==c[0]&&(c="?"+c),o=o.replace(/[?#]/g,encodeURIComponent),c=c.replace("#","%23"),`${n}${u}${o}${c}${s}`}let l=["auth","hash","host","hostname","href","path","pathname","port","protocol","query","search","slashes"];function u(e){return s(e)}},18566,(e,t,r)=>{t.exports=e.r(76562)}]);