failproofai 1.0.9-beta.2 → 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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +4 -4
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +1 -1
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ox4w55._.js → [root-of-the-server]__1ec94jt._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0n6zrjv._.js → _0xq-p5o._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1pa3k5k._.js → _1g7s7di._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
- package/.next/standalone/.next/static/chunks/{42-l25bbfo0ec.js → 03madt33xbsx2.js} +1 -1
- package/.next/standalone/.next/static/chunks/0w8_n30wmnorq.js +1 -0
- package/.next/standalone/.next/static/chunks/{2b59i-n9l-4of.js → 0zlixskj11-yh.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0h--izcpk__m9.js → 1-n1o5wh4wfy6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{30z-240_lrczt.js → 1t6tmwe_1myeo.js} +1 -1
- package/.next/standalone/.next/static/chunks/28z6u4u7hdrnd.js +1 -0
- package/.next/standalone/.next/static/chunks/{28cmd5molgwa3.js → 2dj6xq9mueqb6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1srecm9k-z_i1.js → 2lczelmvvc2yg.js} +1 -1
- package/.next/standalone/.next/static/chunks/3fbsuyflx-2qi.js +1 -0
- package/.next/standalone/.next/static/chunks/3jffngwvgxm5q.js +6 -0
- package/.next/standalone/package.json +9 -9
- package/.next/standalone/sdk/typescript/CHANGELOG.md +39 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +3 -3
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +16 -113
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +3 -1
- package/.next/standalone/server.js +1 -1
- package/dist/cli.mjs +230 -115
- package/dist/worker.mjs +1 -1
- package/package.json +9 -9
- package/src/hooks/daemon-service.ts +14 -1
- package/src/hooks/integrations.ts +108 -26
- package/src/hooks/safe-config-write.ts +80 -7
- package/.next/standalone/.next/static/chunks/2k5vhij_w1g82.js +0 -1
- package/.next/standalone/.next/static/chunks/2o1fy-waqn1he.js +0 -6
- package/.next/standalone/.next/static/chunks/38gpf5tb_rd0m.js +0 -1
- package/.next/standalone/.next/static/chunks/3nyf50dub1vuk.js +0 -1
- /package/.next/standalone/.next/static/{D1BjwOkHNPetPo47DhV4_ → Q2PyL8ZdGGdvVnn-3FrL2}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{D1BjwOkHNPetPo47DhV4_ → Q2PyL8ZdGGdvVnn-3FrL2}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{D1BjwOkHNPetPo47DhV4_ → Q2PyL8ZdGGdvVnn-3FrL2}/_ssgManifest.js +0 -0
|
@@ -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
|
-
*
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
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
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
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 {
|
|
1529
1534
|
try {
|
|
1530
|
-
const
|
|
1531
|
-
return
|
|
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;
|
|
1573
|
+
try {
|
|
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 (!
|
|
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)
|
|
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
|
|
@@ -1851,6 +1910,9 @@ export async function migrateHermesProfiles(opts: {
|
|
|
1851
1910
|
const results: HermesProfileMigration[] = [];
|
|
1852
1911
|
let daemonOk: boolean | undefined;
|
|
1853
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 {
|
|
1854
1916
|
if (!existsSync(profile.home)) continue;
|
|
1855
1917
|
const settingsPath = resolve(profile.home, "config.yaml");
|
|
1856
1918
|
const pluginPath = hermesPluginPathForSettings(settingsPath);
|
|
@@ -1888,6 +1950,15 @@ export async function migrateHermesProfiles(opts: {
|
|
|
1888
1950
|
continue;
|
|
1889
1951
|
}
|
|
1890
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
|
+
}
|
|
1891
1962
|
results.push({ ...base, status: "current", detail: "already linked", legacyShellHooksRemain: false });
|
|
1892
1963
|
continue;
|
|
1893
1964
|
}
|
|
@@ -1902,19 +1973,6 @@ export async function migrateHermesProfiles(opts: {
|
|
|
1902
1973
|
});
|
|
1903
1974
|
continue;
|
|
1904
1975
|
}
|
|
1905
|
-
if (existsSync(settingsPath)) {
|
|
1906
|
-
const errors = parseDocument(readFileSync(settingsPath, "utf8")).errors;
|
|
1907
|
-
if (errors.length > 0) {
|
|
1908
|
-
results.push({
|
|
1909
|
-
...base,
|
|
1910
|
-
status: "failed",
|
|
1911
|
-
detail: `${settingsPath} does not parse as YAML; left untouched`,
|
|
1912
|
-
legacyShellHooksRemain: legacy,
|
|
1913
|
-
});
|
|
1914
|
-
continue;
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
1976
|
if (daemonOk === undefined) daemonOk = await opts.daemonSupportsPolicyEvaluation();
|
|
1919
1977
|
if (!daemonOk) {
|
|
1920
1978
|
results.push({
|
|
@@ -1935,6 +1993,7 @@ export async function migrateHermesProfiles(opts: {
|
|
|
1935
1993
|
const doc = readYamlDoc(settingsPath);
|
|
1936
1994
|
enableHermesPluginInDoc(doc);
|
|
1937
1995
|
writeYamlDoc(settingsPath, doc);
|
|
1996
|
+
const reenabledOnly = !legacy && plugin.kind === "link" && plugin.current && mode === "unchanged";
|
|
1938
1997
|
const from = legacy
|
|
1939
1998
|
? "shell hooks"
|
|
1940
1999
|
: plugin.kind === "copy"
|
|
@@ -1943,7 +2002,12 @@ export async function migrateHermesProfiles(opts: {
|
|
|
1943
2002
|
? "old plugin link"
|
|
1944
2003
|
: "enabled but missing plugin";
|
|
1945
2004
|
const to = mode === "copied" ? "plugin copy (symlink not possible here)" : "linked plugin";
|
|
1946
|
-
|
|
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 });
|
|
1947
2011
|
} catch (err) {
|
|
1948
2012
|
results.push({
|
|
1949
2013
|
...base,
|
|
@@ -1952,6 +2016,15 @@ export async function migrateHermesProfiles(opts: {
|
|
|
1952
2016
|
legacyShellHooksRemain: hermesConfigState(settingsPath).legacyShellHookPresent,
|
|
1953
2017
|
});
|
|
1954
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
|
+
}
|
|
1955
2028
|
}
|
|
1956
2029
|
return results;
|
|
1957
2030
|
}
|
|
@@ -1974,6 +2047,8 @@ export interface HermesProfileHealth {
|
|
|
1974
2047
|
cronUnchecked: boolean;
|
|
1975
2048
|
/** config.yaml exists but does not parse; failproofai will not touch it. */
|
|
1976
2049
|
configUnreadable: boolean;
|
|
2050
|
+
/** Another plugin (not provably FailproofAI's) occupies plugins/failproofai. */
|
|
2051
|
+
pluginForeign: boolean;
|
|
1977
2052
|
healthy: boolean;
|
|
1978
2053
|
}
|
|
1979
2054
|
|
|
@@ -1996,6 +2071,7 @@ export function hermesProfileHealth(): HermesProfileHealth[] {
|
|
|
1996
2071
|
legacyShellHookPresent: config.legacyShellHookPresent,
|
|
1997
2072
|
cronUnchecked: config.legacyShellHookPresent && !pluginWorks,
|
|
1998
2073
|
configUnreadable: config.unreadable === true,
|
|
2074
|
+
pluginForeign: plugin.kind === "foreign",
|
|
1999
2075
|
healthy: pluginWorks && !config.legacyShellHookPresent && config.unreadable !== true,
|
|
2000
2076
|
};
|
|
2001
2077
|
});
|
|
@@ -2007,6 +2083,12 @@ export function hermesProfileStatusRows(): Array<[string, string]> {
|
|
|
2007
2083
|
.filter((profile) => existsSync(profile.home))
|
|
2008
2084
|
.map((profile) => {
|
|
2009
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
|
+
}
|
|
2010
2092
|
if (profile.configUnreadable) {
|
|
2011
2093
|
return [label, `UNHEALTHY — ${profile.settingsPath} does not parse; failproofai leaves it untouched until it is fixed`];
|
|
2012
2094
|
}
|
|
@@ -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
|
|
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
|
-
|
|
112
|
+
return lstatSync(path).isSymbolicLink();
|
|
61
113
|
} catch {
|
|
62
|
-
|
|
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
|
|
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
|
-
|
|
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))
|
|
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,13644,e=>{"use strict";var t=e.i(95187);let r=(0,t.createServerReference)("00b0b1e41b15389782e3c2352a31388b82d5d66fc6",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.2"]}),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(13644),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)}]);
|