failproofai 0.0.14-beta.0 → 0.0.14-beta.1

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 (172) hide show
  1. package/.next/standalone/.codex/hooks.json +6 -6
  2. package/.next/standalone/.cursor/hooks.json +6 -6
  3. package/.next/standalone/.factory/hooks.json +9 -9
  4. package/.next/standalone/.next/BUILD_ID +1 -1
  5. package/.next/standalone/.next/build-manifest.json +5 -5
  6. package/.next/standalone/.next/prerender-manifest.json +3 -3
  7. package/.next/standalone/.next/required-server-files.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  9. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  10. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  15. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  16. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  20. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  26. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  27. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  29. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  30. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
  40. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  41. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/index.html +1 -1
  44. package/.next/standalone/.next/server/app/index.rsc +15 -15
  45. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  46. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  47. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  48. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  49. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  50. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  51. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  52. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  56. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  59. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  63. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  64. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  65. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  68. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  69. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q2nbsl._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xuaoik._.js +3 -3
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cz9as._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +2 -2
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__042d3cd._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09q1168._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0brjczq._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h12me5._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hdsupo._.js +2 -2
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +2 -2
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07qfsfa._.js → [root-of-the-server]__0wp9w6i._.js} +2 -2
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ynf7tx._.js +2 -2
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11rtg6s._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17ai7sy._.js +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dky4g0._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +2 -2
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__212nf49._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/app_087bt9w._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/app_1fvisnp._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/app_209u41o._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_0g5r64e.js → node_modules_html-to-image_es_index_12rjfea.js} +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0-uvagv.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03c7gi5.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_09p-8om.js +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0v-kfiu.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0xrgzyz.js +1 -1
  110. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1806lsc.js +1 -1
  111. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1j6dd-e.js +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1sa65r-.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
  114. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  115. package/.next/standalone/.next/server/pages/404.html +1 -1
  116. package/.next/standalone/.next/server/pages/500.html +1 -1
  117. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  118. package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
  119. package/.next/standalone/.next/static/chunks/{13f1kmjea-0md.js → 02jcotghcxrbu.js} +1 -1
  120. package/.next/standalone/.next/static/chunks/{17sdztgbcc0fi.js → 0d5lypu1zs21r.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{2ufuwhv03yvtb.js → 0emg30_6svycu.js} +1 -1
  122. package/.next/standalone/.next/static/chunks/{1374x9bv_s_vg.js → 0o9wpnze1ey8y.js} +1 -1
  123. package/.next/standalone/.next/static/chunks/{454dyizqik6t9.js → 1359o5785rmve.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/{43weu8f59tlix.js → 20tuctw38jbgw.js} +1 -1
  125. package/.next/standalone/.next/static/chunks/{0405htbxay9vd.js → 2ldhnaweu9ew3.js} +1 -1
  126. package/.next/standalone/.next/static/chunks/{003uz088wbmz7.js → 2vav_x0_336ds.js} +1 -1
  127. package/.next/standalone/.next/static/chunks/{0iinhn4417nk1.js → 3-ogr79xqbw0h.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/36j05kb2x323i.css +2 -0
  129. package/.next/standalone/.next/static/chunks/{35-90m9py64d4.js → 3cg7x0joi2b98.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/{2o3ql0n5owqsw.js → 3k87p-tijud-4.js} +1 -1
  131. package/.next/standalone/.next/static/chunks/{2m_tbl39fcedn.js → 3kmaqcp7rldad.js} +1 -1
  132. package/.next/standalone/.next/static/chunks/{turbopack-0vavqo2d-tlt3.js → turbopack-10hj8t5pf33tu.js} +1 -1
  133. package/.next/standalone/.opencode/plugins/failproofai.mjs +30 -11
  134. package/.next/standalone/app/components/global-error-listeners.tsx +27 -0
  135. package/.next/standalone/ci/cli-integration/Dockerfile +47 -0
  136. package/.next/standalone/ci/cli-integration/README.md +69 -0
  137. package/.next/standalone/ci/cli-integration/canary-policies.mjs +45 -0
  138. package/.next/standalone/ci/cli-integration/capture-tokens.sh +48 -0
  139. package/.next/standalone/ci/cli-integration/inject-tokens.sh +44 -0
  140. package/.next/standalone/ci/cli-integration/install-clis.sh +91 -0
  141. package/.next/standalone/ci/cli-integration/probe-cli.sh +208 -0
  142. package/.next/standalone/ci/cli-integration/report.js +74 -0
  143. package/.next/standalone/ci/cli-integration/run.sh +107 -0
  144. package/.next/standalone/components/reach-developers.tsx +1 -1
  145. package/.next/standalone/docker-hook-sync/Dockerfile +8 -4
  146. package/.next/standalone/lib/error-origin.ts +67 -0
  147. package/.next/standalone/lib/install-check.ts +231 -0
  148. package/.next/standalone/package.json +1 -3
  149. package/.next/standalone/server.js +1 -1
  150. package/README.md +1 -17
  151. package/bin/failproofai.mjs +11 -1
  152. package/dist/cli.mjs +479 -217
  153. package/lib/error-origin.ts +67 -0
  154. package/lib/install-check.ts +231 -0
  155. package/package.json +1 -3
  156. package/scripts/dev-hook.mjs +292 -0
  157. package/scripts/install-diagnosis.mjs +5 -8
  158. package/scripts/install-telemetry.mjs +12 -4
  159. package/scripts/translate-docs/cli.ts +47 -1
  160. package/scripts/translate-docs/mdx-translator.ts +133 -4
  161. package/scripts/translate-docs/readme-translator.ts +13 -5
  162. package/scripts/translate-docs/translator.ts +38 -2
  163. package/scripts/validate-mdx.ts +12 -4
  164. package/src/audit/cli.ts +41 -9
  165. package/src/hooks/tui.ts +1 -1
  166. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ge8e7w._.js +0 -3
  167. package/.next/standalone/.next/static/chunks/3r--yyjkp9_7b.css +0 -2
  168. package/scripts/postinstall.mjs +0 -242
  169. package/scripts/preuninstall.mjs +0 -131
  170. /package/.next/standalone/.next/static/{MNJWFb2jLRrxRKGFNK6Hy → LkN-JjmhKGmL-WklH7WVi}/_buildManifest.js +0 -0
  171. /package/.next/standalone/.next/static/{MNJWFb2jLRrxRKGFNK6Hy → LkN-JjmhKGmL-WklH7WVi}/_clientMiddlewareManifest.js +0 -0
  172. /package/.next/standalone/.next/static/{MNJWFb2jLRrxRKGFNK6Hy → LkN-JjmhKGmL-WklH7WVi}/_ssgManifest.js +0 -0
@@ -9,7 +9,11 @@ import {
9
9
  getLanguageByCode,
10
10
  getModelForTier,
11
11
  } from "./config";
12
- import { getEnglishMdxPages, translateMdxPage } from "./mdx-translator";
12
+ import {
13
+ getEnglishMdxPages,
14
+ translateMdxPage,
15
+ pruneOrphanedTranslations,
16
+ } from "./mdx-translator";
13
17
  import { translateReadme } from "./readme-translator";
14
18
  import {
15
19
  getNavigationPageReferences,
@@ -33,6 +37,8 @@ const { values: args } = parseArgs({
33
37
  force: { type: "boolean", short: "f", default: false },
34
38
  "update-nav": { type: "boolean", default: false },
35
39
  validate: { type: "boolean", default: false },
40
+ prune: { type: "boolean", default: false },
41
+ "no-prune": { type: "boolean", default: false },
36
42
  model: { type: "string", short: "m" },
37
43
  help: { type: "boolean", short: "h", default: false },
38
44
  },
@@ -53,6 +59,8 @@ Options:
53
59
  -f, --force Ignore cache, re-translate everything
54
60
  --update-nav Regenerate docs.json navigation after translation
55
61
  --validate Check all nav references resolve to files
62
+ --prune Only delete translations whose English source is gone
63
+ --no-prune Skip the prune step during a normal translation run
56
64
  -m, --model <model> Claude model override (default: Sonnet for Tier 1, Haiku for Tier 2/3)
57
65
  -h, --help Show this help
58
66
 
@@ -65,6 +73,7 @@ Examples:
65
73
  bun scripts/translate-docs/cli.ts --dry-run --tier 3 # Preview all translations
66
74
  bun scripts/translate-docs/cli.ts --validate # Check nav references
67
75
  bun scripts/translate-docs/cli.ts --update-nav # Regenerate docs.json
76
+ bun scripts/translate-docs/cli.ts --prune --tier 3 # Drop orphaned translations
68
77
  `);
69
78
  process.exit(0);
70
79
  }
@@ -132,6 +141,26 @@ async function main() {
132
141
  return;
133
142
  }
134
143
 
144
+ // Prune-only mode
145
+ if (args.prune) {
146
+ const langCodes = resolveLanguages();
147
+ const cache = readCache();
148
+ const pruned = pruneOrphanedTranslations(langCodes, {
149
+ dryRun: args["dry-run"],
150
+ cache,
151
+ });
152
+ for (const file of pruned) {
153
+ console.log(
154
+ ` ${args["dry-run"] ? "would remove" : "removed"}: ${file}`,
155
+ );
156
+ }
157
+ if (pruned.length > 0 && !args["dry-run"]) writeCache(cache);
158
+ console.log(
159
+ `\n${pruned.length} orphaned translation(s)${args["dry-run"] ? " would be" : ""} removed.`,
160
+ );
161
+ return;
162
+ }
163
+
135
164
  const langCodes = resolveLanguages();
136
165
  const isDryRun = args["dry-run"];
137
166
  const isForce = args.force;
@@ -196,6 +225,23 @@ async function main() {
196
225
 
197
226
  // Translate docs
198
227
  if (!args["readme-only"]) {
228
+ // Drop translations orphaned by an upstream English deletion before
229
+ // translating, so a stale locale page can never outlive its source.
230
+ if (!args["no-prune"]) {
231
+ const pruned = pruneOrphanedTranslations(langCodes, {
232
+ dryRun: isDryRun,
233
+ cache,
234
+ });
235
+ for (const file of pruned) {
236
+ console.log(` ${isDryRun ? "would prune" : "pruned"}: ${file}`);
237
+ }
238
+ if (pruned.length > 0) {
239
+ console.log(
240
+ `${pruned.length} orphaned translation(s)${isDryRun ? " would be" : ""} removed.`,
241
+ );
242
+ }
243
+ }
244
+
199
245
  const pages = getEnglishMdxPages();
200
246
  const filteredPages = args.pages
201
247
  ? pages.filter((p) => {
@@ -4,12 +4,20 @@ import {
4
4
  mkdirSync,
5
5
  readdirSync,
6
6
  statSync,
7
+ existsSync,
8
+ rmSync,
7
9
  } from "node:fs";
8
10
  import { dirname, join, relative } from "node:path";
9
11
  import { fileURLToPath } from "node:url";
10
12
  import { getLanguageByCode } from "./config";
11
13
  import { translateContent } from "./translator";
12
- import { readCache, writeCache, isCached, setCacheEntry } from "./cache";
14
+ import {
15
+ readCache,
16
+ writeCache,
17
+ isCached,
18
+ setCacheEntry,
19
+ getCacheKey,
20
+ } from "./cache";
13
21
  import type { TranslationResult, TranslationCache } from "./types";
14
22
 
15
23
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -94,6 +102,60 @@ export function stripStrayTrailingFence(content: string): string {
94
102
  return lines.join("\n");
95
103
  }
96
104
 
105
+ /**
106
+ * Convert HTML comments (`<!-- ... -->`) into MDX brace-slash-star comments.
107
+ *
108
+ * Mintlify parses every page as MDX, where a top-level HTML comment is a hard
109
+ * syntax error ("Unexpected character `!` (U+0021) before name …") that fails
110
+ * the whole deployment — the remedy Mintlify itself suggests is switching to
111
+ * MDX's own comment form. The root README keeps HTML-comment syntax (GitHub
112
+ * renders it invisibly), so its translated copies under docs/i18n/ have to be
113
+ * rewritten to the MDX form or the docs deploy breaks.
114
+ *
115
+ * Comments inside fenced code blocks are left untouched — there `<!-- -->` is
116
+ * literal sample text (e.g. the plist snippet in the AgentEye collector docs),
117
+ * not a comment to convert. Any `*`+`/` sequence inside a body is broken up so
118
+ * the generated JS block comment can't be terminated early.
119
+ */
120
+ export function convertHtmlComments(content: string): string {
121
+ // Map out fenced-code ranges so comments inside them stay literal. Per
122
+ // CommonMark, a fence opens with ≥3 backticks or tildes and closes only on a
123
+ // later line using the SAME character and at least the same length. A naive
124
+ // "any ``` toggles" counter misfires on a ```` block that embeds ``` or on
125
+ // mixed ```/~~~ fences — the toggle desyncs and a real top-level comment
126
+ // after the block would be left unconverted (breaking the deploy we fix here).
127
+ const fenceRanges: Array<[number, number]> = [];
128
+ const fenceRe = /^[ \t]*(`{3,}|~{3,})/gm;
129
+ let fenceMatch: RegExpExecArray | null;
130
+ let open: { char: string; length: number; start: number } | null = null;
131
+ while ((fenceMatch = fenceRe.exec(content)) !== null) {
132
+ const marker = fenceMatch[1];
133
+ if (!open) {
134
+ open = { char: marker[0], length: marker.length, start: fenceMatch.index };
135
+ } else if (marker[0] === open.char && marker.length >= open.length) {
136
+ const lineEnd = content.indexOf("\n", fenceRe.lastIndex);
137
+ fenceRanges.push([open.start, lineEnd === -1 ? content.length : lineEnd]);
138
+ open = null;
139
+ }
140
+ // A different char or shorter marker while a fence is open is inner content.
141
+ }
142
+ // An unterminated fence runs to the end of the document.
143
+ if (open) fenceRanges.push([open.start, content.length]);
144
+
145
+ const isInsideFence = (offset: number): boolean =>
146
+ fenceRanges.some(([start, end]) => offset >= start && offset < end);
147
+
148
+ return content.replace(
149
+ /<!--([\s\S]*?)-->/g,
150
+ (match: string, body: string, offset: number) => {
151
+ if (isInsideFence(offset)) return match;
152
+ // Neutralize any `*/` so it can't close the JS block comment early.
153
+ const safeBody = body.replace(/\*\//g, "* /");
154
+ return `{/*${safeBody}*/}`;
155
+ },
156
+ );
157
+ }
158
+
97
159
  /**
98
160
  * Rewrite internal doc links to include the language prefix.
99
161
  * e.g. href="/built-in-policies" -> href="/es/built-in-policies"
@@ -175,9 +237,11 @@ export async function translateMdxPage(
175
237
  );
176
238
 
177
239
  // Strip stray quote artifacts from JSX attribute values, drop any
178
- // unmatched trailing code fence the model sometimes hallucinates, then
179
- // rewrite links.
180
- const sanitized = stripStrayTrailingFence(sanitizeJsxAttributes(translated));
240
+ // unmatched trailing code fence the model sometimes hallucinates, convert
241
+ // any HTML comments to MDX comments, then rewrite links.
242
+ const sanitized = convertHtmlComments(
243
+ stripStrayTrailingFence(sanitizeJsxAttributes(translated)),
244
+ );
181
245
  const withLinks = rewriteInternalLinks(sanitized, lang);
182
246
 
183
247
  // Write output
@@ -234,6 +298,71 @@ export function getEnglishMdxPages(): string[] {
234
298
  return results.sort();
235
299
  }
236
300
 
301
+ /** Every `.mdx` file under `dir`, recursively. */
302
+ function collectMdxFiles(dir: string): string[] {
303
+ const results: string[] = [];
304
+ for (const entry of readdirSync(dir)) {
305
+ const full = join(dir, entry);
306
+ if (statSync(full).isDirectory()) {
307
+ results.push(...collectMdxFiles(full));
308
+ } else if (entry.endsWith(".mdx")) {
309
+ results.push(full);
310
+ }
311
+ }
312
+ return results;
313
+ }
314
+
315
+ /**
316
+ * Delete translated pages whose English source no longer exists, and drop
317
+ * their cache entries.
318
+ *
319
+ * Translation only ever moves forward: `getEnglishMdxPages()` drives what gets
320
+ * written, so when an English page is deleted upstream (the agenteye sync does
321
+ * this routinely) its 14 translations are simply never revisited. They linger
322
+ * on disk and `--update-nav` drops them from `docs.json`, which hides them from
323
+ * the sidebar but does *not* unpublish them — Mintlify still serves and indexes
324
+ * any `.mdx` present, so non-English readers can land on a page documenting a
325
+ * removed feature with no navigation out. Left unpruned these also accumulate
326
+ * as permanent `validate:mdx` surface area for content no English source can
327
+ * ever correct.
328
+ *
329
+ * Returns the docs-dir-relative paths that were (or, when `dryRun`, would be)
330
+ * removed.
331
+ */
332
+ export function pruneOrphanedTranslations(
333
+ langCodes: string[],
334
+ options: {
335
+ dryRun?: boolean;
336
+ cache?: TranslationCache;
337
+ /** Override the docs root. Tests point this at a fixture tree. */
338
+ docsDir?: string;
339
+ } = {},
340
+ ): string[] {
341
+ const docsDir = options.docsDir ?? DOCS_DIR;
342
+ const removed: string[] = [];
343
+
344
+ for (const lang of langCodes) {
345
+ const langDir = join(docsDir, lang);
346
+ if (!existsSync(langDir)) continue;
347
+
348
+ for (const file of collectMdxFiles(langDir)) {
349
+ // docs/zh/agenteye/foo.mdx -> agenteye/foo.mdx -> docs/agenteye/foo.mdx
350
+ const relPath = relative(langDir, file);
351
+ if (existsSync(join(docsDir, relPath))) continue;
352
+
353
+ removed.push(relative(docsDir, file));
354
+ if (!options.dryRun) {
355
+ rmSync(file);
356
+ if (options.cache) {
357
+ delete options.cache.translations[getCacheKey(relPath, lang)];
358
+ }
359
+ }
360
+ }
361
+ }
362
+
363
+ return removed.sort();
364
+ }
365
+
237
366
  function isLanguageDir(name: string): boolean {
238
367
  const langCodes = [
239
368
  "zh",
@@ -3,7 +3,11 @@ import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { LANGUAGES, getLanguageByCode } from "./config";
5
5
  import { translateContent } from "./translator";
6
- import { stripStrayTrailingFence } from "./mdx-translator";
6
+ import {
7
+ stripStrayTrailingFence,
8
+ convertHtmlComments,
9
+ sanitizeJsxAttributes,
10
+ } from "./mdx-translator";
7
11
  import { readCache, writeCache, isCached, setCacheEntry } from "./cache";
8
12
  import type { TranslationResult, TranslationCache } from "./types";
9
13
 
@@ -103,10 +107,14 @@ export async function translateReadme(
103
107
  const rtlOpen = langConfig.rtl ? `<div dir="rtl">\n\n` : "";
104
108
  const rtlClose = langConfig.rtl ? `\n\n</div>` : "";
105
109
 
106
- // Drop any stray trailing fence the model hallucinated would otherwise
107
- // open an unclosed code block that swallows the wrapping `</div>` for RTL
108
- // pages and break Mintlify's MDX parser.
109
- const cleaned = stripStrayTrailingFence(translated);
110
+ // Run the same MDX sanitizers as translateMdxPagethe README emits JSX
111
+ // (the logo table), so its output has to satisfy Mintlify's MDX parser too:
112
+ // strip stray quote artifacts from JSX attributes, drop any unmatched
113
+ // trailing code fence the model hallucinates (which would swallow the RTL
114
+ // `</div>` wrapper), and convert HTML comments to MDX comments.
115
+ const cleaned = convertHtmlComments(
116
+ stripStrayTrailingFence(sanitizeJsxAttributes(translated)),
117
+ );
110
118
 
111
119
  const output = `${disclaimer}\n\n${langSelector}\n\n---\n${rtlOpen}\n${cleaned}\n${rtlClose}`;
112
120
 
@@ -3,6 +3,28 @@ import { DO_NOT_TRANSLATE } from "./config";
3
3
 
4
4
  let client: Anthropic | null = null;
5
5
 
6
+ // Output-token ceiling for a single translation. The largest English docs
7
+ // (e.g. agenteye/kubernetes-deployment.mdx at ~1400 lines) translate to well
8
+ // beyond the old 16384 cap for verbose target languages. When a response hit
9
+ // that cap it was silently truncated mid-MDX — leaving an unbalanced `{` or an
10
+ // unterminated JSX expression — and the partial output was written to disk and
11
+ // the cache, only to fail `mintlify validate` later in the consolidate job
12
+ // (or, for the very largest pages, to trip the proxy with a "stream ended"
13
+ // error). 64000 is Claude Haiku 4.5's max output (Tier 2/3 languages) and well
14
+ // inside Claude Sonnet 4.6's 128000 (Tier 1), with headroom over the largest
15
+ // observed translation; max_tokens is only a ceiling, so smaller pages still
16
+ // stop at `end_turn` and cost the same. Streaming (below) is what keeps an
17
+ // output this large safe from the SDK's HTTP timeout.
18
+ // Override via TRANSLATE_MAX_TOKENS (integer >= 1; otherwise default).
19
+ const parsedMaxTokens = Number.parseInt(
20
+ process.env.TRANSLATE_MAX_TOKENS ?? "",
21
+ 10,
22
+ );
23
+ const MAX_TOKENS =
24
+ Number.isInteger(parsedMaxTokens) && parsedMaxTokens > 0
25
+ ? parsedMaxTokens
26
+ : 64000;
27
+
6
28
  function getClient(): Anthropic {
7
29
  if (!client) {
8
30
  // Default 5 retries (up from SDK default of 2) so transient
@@ -61,7 +83,7 @@ export async function translateContent(
61
83
  // as `messages.create(...)`, so the rest of the pipeline is unchanged.
62
84
  const response = await anthropic.messages.stream({
63
85
  model,
64
- max_tokens: 16384,
86
+ max_tokens: MAX_TOKENS,
65
87
  system: [{ type: "text", text: SYSTEM_PROMPT, cache_control: { type: "ephemeral" } }],
66
88
  messages: [
67
89
  {
@@ -71,8 +93,22 @@ export async function translateContent(
71
93
  ],
72
94
  }).finalMessage();
73
95
 
96
+ // A truncated translation is worse than a failed one: the model stops
97
+ // mid-MDX, and that partial would otherwise be written to disk and cached as
98
+ // if complete, surfacing only as an unbalanced-brace parse error in
99
+ // `mintlify validate`. Fail loudly instead so the caller (cli.ts) records an
100
+ // error, never caches the partial, and excludes this language from the
101
+ // consolidate publish step. If a page ever legitimately needs more than
102
+ // MAX_TOKENS, raise TRANSLATE_MAX_TOKENS or split the source.
103
+ if (response.stop_reason === "max_tokens") {
104
+ throw new Error(
105
+ `translation truncated at max_tokens=${MAX_TOKENS} ` +
106
+ `(output ${response.usage.output_tokens} tokens) — source too large to translate in one request`,
107
+ );
108
+ }
109
+
74
110
  const translated =
75
- response.content[0].type === "text" ? response.content[0].text : "";
111
+ response.content[0]?.type === "text" ? response.content[0].text : "";
76
112
 
77
113
  return {
78
114
  translated,
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Validate that every docs MDX page parses with the same MDX engine Mintlify
3
- * runs at deploy time.
2
+ * Validate that every docs page (`.mdx` and `.md` Mintlify parses both as
3
+ * MDX) parses with the same MDX engine Mintlify runs at deploy time.
4
4
  *
5
5
  * Why this exists: `mintlify validate` (the existing `docs` CI job) only checks
6
6
  * `docs.json` structure and nav-link resolution — it does NOT parse page
@@ -91,12 +91,20 @@ export function encodeAnnotation(value: string): string {
91
91
  .replace(/\n/g, "%0A");
92
92
  }
93
93
 
94
- function collectMdxFiles(dir: string): string[] {
94
+ /**
95
+ * Collect every Mintlify content page under `dir`. Mintlify runs BOTH `.mdx`
96
+ * and `.md` files through the same MDX pipeline at deploy time, so a `.md` page
97
+ * with an MDX syntax error (e.g. an HTML `<!-- -->` comment, which MDX rejects)
98
+ * fails the deploy exactly like a broken `.mdx` would. The docs/i18n README
99
+ * translations are `.md`, so restricting this walk to `.mdx` let their breakage
100
+ * sail past this safety net and reach the post-merge deploy — collect both.
101
+ */
102
+ export function collectMdxFiles(dir: string): string[] {
95
103
  const out: string[] = [];
96
104
  for (const entry of readdirSync(dir)) {
97
105
  const full = join(dir, entry);
98
106
  if (statSync(full).isDirectory()) out.push(...collectMdxFiles(full));
99
- else if (entry.endsWith(".mdx")) out.push(full);
107
+ else if (entry.endsWith(".mdx") || entry.endsWith(".md")) out.push(full);
100
108
  }
101
109
  return out;
102
110
  }
package/src/audit/cli.ts CHANGED
@@ -237,6 +237,26 @@ function printSummary(result: AuditResult): void {
237
237
  for (const line of buildSummary(result)) process.stdout.write(` ${line}\n`);
238
238
  }
239
239
 
240
+ // ── Audit telemetry ──────────────────────────────────────────────────────────
241
+
242
+ /**
243
+ * Which entry point ran the audit. `onboarding` is the automatic post-setup run;
244
+ * `cli` is an explicit `failproofai audit`. Carried on every cli_audit_* event so
245
+ * the first audit a user ever runs is distinguishable from later deliberate ones.
246
+ */
247
+ type AuditSource = "cli" | "onboarding";
248
+
249
+ /** Shared so both entry points report cli_audit_completed identically. */
250
+ function auditCompletedProps(source: AuditSource, result: AuditResult) {
251
+ return {
252
+ source,
253
+ events_scanned: result.eventsScanned,
254
+ sessions_scanned: result.transcripts.scanned,
255
+ total_hits: result.totals.hits,
256
+ findings: result.results.length,
257
+ };
258
+ }
259
+
240
260
  // ── Post-setup background audit ────────────────────────────────────────────────
241
261
 
242
262
  /**
@@ -252,7 +272,13 @@ function printSummary(result: AuditResult): void {
252
272
  */
253
273
  export async function runPostSetupAudit(): Promise<void> {
254
274
  if (process.env.FAILPROOFAI_NO_AUTO_AUDIT === "1") return;
255
-
275
+
276
+ const instanceId = getInstanceId();
277
+ // Fire-and-forget, as in runAuditCli: the multi-second scan below keeps the
278
+ // process alive long enough for this to land, and the completed/failed event
279
+ // that follows is awaited.
280
+ void trackHookEvent(instanceId, "cli_audit_started", { source: "onboarding" });
281
+
256
282
  process.stdout.write(
257
283
  `\n ${c(PINK, "✦")} ${c(BOLD, "failproofai audit now running")} ${c(DIM, "· ctrl+c to stop")}\n\n`,
258
284
  );
@@ -260,13 +286,25 @@ export async function runPostSetupAudit(): Promise<void> {
260
286
  let result: AuditResult;
261
287
  try {
262
288
  result = await runWithProgress({});
263
- } catch {
289
+ } catch (err) {
290
+ // Awaited: this function returns straight into the dashboard boot, and a
291
+ // fire-and-forget fetch would race it.
292
+ await trackHookEvent(instanceId, "cli_audit_failed", {
293
+ source: "onboarding",
294
+ error_type: err instanceof Error ? err.name : "unknown",
295
+ error_message: sanitizeErrorMessage(err),
296
+ });
264
297
  process.stdout.write(
265
298
  ` ${c(PINK, "!")} ${c(DIM, "audit couldn't finish — run")} ${c(CYAN, "failproofai audit")} ${c(DIM, "later.")}\n\n`,
266
299
  );
267
300
  return;
268
301
  }
269
302
 
303
+ // Reported before the empty-history return below, so an onboarding audit that
304
+ // finds nothing is still counted — matching runAuditCli, which reports
305
+ // completed regardless of what the scan turned up.
306
+ await trackHookEvent(instanceId, "cli_audit_completed", auditCompletedProps("onboarding", result));
307
+
270
308
  if (result.eventsScanned === 0) {
271
309
  process.stdout.write(
272
310
  `\n ${c(DIM, "no agent sessions to audit yet — come back after using your agent.")}\n\n`,
@@ -328,13 +366,7 @@ export async function runAuditCli(args: string[]): Promise<void> {
328
366
  // would otherwise drop this event. On the dashboard path launch() keeps the
329
367
  // process alive, but awaiting makes delivery reliable on every exit path.
330
368
  // Bounded (5s) and never throws.
331
- await trackHookEvent(instanceId, "cli_audit_completed", {
332
- source: "cli",
333
- events_scanned: result.eventsScanned,
334
- sessions_scanned: result.transcripts.scanned,
335
- total_hits: result.totals.hits,
336
- findings: result.results.length,
337
- });
369
+ await trackHookEvent(instanceId, "cli_audit_completed", auditCompletedProps("cli", result));
338
370
 
339
371
  // No sessions on disk — guide the user instead of opening an empty dashboard.
340
372
  if (result.eventsScanned === 0) {
package/src/hooks/tui.ts CHANGED
@@ -287,7 +287,7 @@ export function renderLaunchBanner(version: string, stdout: TTYOut = process.std
287
287
  row("version", c.pink(version)),
288
288
  row("star", c.dim("https://github.com/failproofai/failproofai")),
289
289
  row("docs", c.dim("https://docs.befailproof.ai/introduction")),
290
- row("discord", c.dim("https://discord.gg/2zjBZP7yQJ")),
290
+ row("discord", c.dim("https://discord.befailproof.ai/")),
291
291
  "",
292
292
  ];
293
293
  }
@@ -1,3 +0,0 @@
1
- module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},9270,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.AppRouterContext},36313,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.HooksClientContext},18341,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.ServerInsertedHtml},35112,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactDOM},6236,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=(0,c.createContext)(void 0);a.s(["AutoRefreshProvider",0,function({children:a}){let[e,f]=(0,c.useState)(0);return(0,b.jsx)(d.Provider,{value:{intervalSec:e,setIntervalSec:f},children:a})},"useAutoRefresh",0,function(){let a=(0,c.useContext)(d);if(!a)throw Error("useAutoRefresh must be used within AutoRefreshProvider");return a}])},89027,40695,a=>{"use strict";let b=(0,a.i(64831).default)("chevron-down",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);a.s(["ChevronDown",0,b],89027);var c=a.i(87924),d=a.i(72131),e=a.i(97895);let f=d.forwardRef(({className:a,variant:b="default",size:d="default",...f},g)=>(0,c.jsx)("button",{className:(0,e.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"===b,"text-foreground hover:bg-muted":"ghost"===b,"border border-border bg-transparent hover:border-primary/60 hover:bg-card":"outline"===b,"h-10 py-2 px-4":"default"===d,"h-10 w-10":"icon"===d,"h-9 px-3":"sm"===d,"h-11 px-8":"lg"===d},a),ref:g,...f}));f.displayName="Button",a.s(["Button",0,f],40695)},46058,(a,b,c)=>{"use strict";function d(a){if("function"!=typeof WeakMap)return null;var b=new WeakMap,c=new WeakMap;return(d=function(a){return a?c:b})(a)}c._=function(a,b){if(!b&&a&&a.__esModule)return a;if(null===a||"object"!=typeof a&&"function"!=typeof a)return{default:a};var c=d(b);if(c&&c.has(a))return c.get(a);var e={__proto__:null},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var g in a)if("default"!==g&&Object.prototype.hasOwnProperty.call(a,g)){var h=f?Object.getOwnPropertyDescriptor(a,g):null;h&&(h.get||h.set)?Object.defineProperty(e,g,h):e[g]=a[g]}return e.default=a,c&&c.set(a,e),e}},88347,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d,e,f={ACTION_HMR_REFRESH:function(){return l},ACTION_NAVIGATE:function(){return i},ACTION_REFRESH:function(){return h},ACTION_RESTORE:function(){return j},ACTION_SERVER_ACTION:function(){return m},ACTION_SERVER_PATCH:function(){return k},PrefetchKind:function(){return n},ScrollBehavior:function(){return o}};for(var g in f)Object.defineProperty(c,g,{enumerable:!0,get:f[g]});let h="refresh",i="navigate",j="restore",k="server-patch",l="hmr-refresh",m="server-action";var n=((d={}).AUTO="auto",d.FULL="full",d),o=((e={})[e.Default=0]="Default",e[e.NoScroll=1]="NoScroll",e);("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},67009,(a,b,c)=>{"use strict";function d(a){return null!==a&&"object"==typeof a&&"then"in a&&"function"==typeof a.then}Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"isThenable",{enumerable:!0,get:function(){return d}})},90841,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={dispatchAppRouterAction:function(){return i},dispatchGestureState:function(){return j},refreshOnInstantNavigationUnlock:function(){return h},useActionQueue:function(){return k}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(46058)._(a.r(72131)),g=a.r(67009);a.r(88347);function h(){}function i(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function j(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function k(a){let[b,c]=f.default.useState(a.state),[d,e]=(0,f.useOptimistic)(b),h=(0,f.useMemo)(()=>d,[d]);return(0,g.isThenable)(h)?(0,f.use)(h):h}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},20611,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"callServer",{enumerable:!0,get:function(){return g}});let d=a.r(72131),e=a.r(88347),f=a.r(90841);async function g(a,b){return new Promise((c,g)=>{(0,d.startTransition)(()=>{(0,f.dispatchAppRouterAction)({type:e.ACTION_SERVER_ACTION,actionId:a,actionArgs:b,resolve:c,reject:g})})})}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},1722,(a,b,c)=>{"use strict";let d;Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"findSourceMapURL",{enumerable:!0,get:function(){return d}});("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},39118,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={DEFAULT_SEGMENT_KEY:function(){return l},NOT_FOUND_SEGMENT_KEY:function(){return m},PAGE_SEGMENT_KEY:function(){return k},addSearchParamsIfPageSegment:function(){return i},computeSelectedLayoutSegment:function(){return j},getSegmentValue:function(){return f},getSelectedLayoutSegmentPath:function(){return function a(b,c,d=!0,e=[]){let g;if(d)g=b[1][c];else{let a=b[1];g=a.children??Object.values(a)[0]}if(!g)return e;let h=f(g[0]);return!h||h.startsWith(k)?e:(e.push(h),a(g,c,!1,e))}},isGroupSegment:function(){return g},isParallelRouteSegment:function(){return h}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});function f(a){return Array.isArray(a)?a[1]:a}function g(a){return"("===a[0]&&a.endsWith(")")}function h(a){return a.startsWith("@")&&"@children"!==a}function i(a,b){if(a.includes(k)){let a=JSON.stringify(b);return"{}"!==a?k+"?"+a:k}return a}function j(a,b){if(!a||0===a.length)return null;let c="children"===b?a[0]:a[a.length-1];return c===l?null:c}let k="__PAGE__",l="__DEFAULT__",m="/_not-found"},88644,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"InvariantError",{enumerable:!0,get:function(){return d}});class d extends Error{constructor(a,b){super(`Invariant: ${a.endsWith(".")?a:a+"."} This is a bug in Next.js.`,b),this.name="InvariantError"}}},54427,(a,b,c)=>{"use strict";function d(){let a,b,c=new Promise((c,d)=>{a=c,b=d});return{resolve:a,reject:b,promise:c}}Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"createPromiseWithResolvers",{enumerable:!0,get:function(){return d}})},41997,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={BailoutToCSRError:function(){return g},isBailoutToCSRError:function(){return h}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f="BAILOUT_TO_CLIENT_SIDE_RENDERING";class g extends Error{constructor(a){super(`Bail out to client-side rendering: ${a}`),this.reason=a,this.digest=f}}function h(a){return"object"==typeof a&&null!==a&&"digest"in a&&a.digest===f}},66036,a=>{"use strict";a.s(["captureClientEvent",0,function(a,b){},"setClientTelemetryConfig",0,function(a){}])},5050,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={callServer:function(){return f.callServer},createServerReference:function(){return h.createServerReference},findSourceMapURL:function(){return g.findSourceMapURL}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(20611),g=a.r(1722),h=a.r(38783)},60810,a=>{"use strict";var b=a.i(5050);let c=(0,b.createServerReference)("00734b949351e772ff593b3f278eb35c00f8913193",b.callServer,void 0,b.findSourceMapURL,"getTelemetryConfig");a.s(["getTelemetryConfig",0,c])},10765,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(60810),f=a.i(66036);let g=(0,c.createContext)(void 0);a.s(["PostHogProvider",0,function({children:a}){let h=(0,d.usePathname)(),i=(0,c.useRef)(null),j=(0,c.useRef)(!1);(0,c.useEffect)(()=>{let a=!1;return(0,e.getTelemetryConfig)().then(b=>{a||((0,f.setClientTelemetryConfig)(b),j.current=!0,(0,f.captureClientEvent)("$pageview"),i.current=window.location.pathname)}),()=>{a=!0}},[]),(0,c.useEffect)(()=>{j.current&&i.current!==h&&(i.current=h,(0,f.captureClientEvent)("$pageview"))},[h]);let k=c.default.useCallback((a,b)=>{(0,f.captureClientEvent)(a,b)},[]);return(0,b.jsx)(g.Provider,{value:{capture:k},children:a})},"usePostHog",0,function(){let a=(0,c.useContext)(g);if(void 0===a)throw Error("usePostHog must be used within a PostHogProvider");return a}])},18952,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=[],e=0,f=new Set;function g(){for(let a of f)a()}function h(a){return f.add(a),()=>f.delete(a)}function i(){return d}function j({message:a}){let[d,e]=(0,c.useState)(!1);return(0,c.useEffect)(()=>{requestAnimationFrame(()=>e(!0));let a=setTimeout(()=>e(!1),2e3);return()=>clearTimeout(a)},[]),(0,b.jsx)("div",{className:`bg-card border border-border text-foreground text-sm px-4 py-2 rounded-lg shadow-lg transition-opacity duration-300 ${d?"opacity-100":"opacity-0"}`,children:a})}a.s(["Toaster",0,function(){let a=(0,c.useSyncExternalStore)(h,i,i);return(0,b.jsx)("div",{className:"fixed bottom-4 right-4 z-50 flex flex-col gap-2",children:a.map(a=>(0,b.jsx)(j,{message:a.message},a.id))})},"toast",0,function(a){let b=e++;d=[...d,{id:b,message:a}],g(),setTimeout(()=>{d=d.filter(a=>a.id!==b),g()},2500)}])},45550,a=>{"use strict";var b=a.i(72131),c=a.i(66036);a.s(["GlobalErrorListeners",0,function(){return(0,b.useEffect)(()=>{let a=a=>{(0,c.captureClientEvent)("unhandled_exception",{error_message:a.message,error_name:a.error?.name,error_filename:a.filename,error_lineno:a.lineno,error_colno:a.colno})},b=a=>{let b=a.reason;(0,c.captureClientEvent)("unhandled_rejection",{error_message:b instanceof Error?b.message:String(b),error_name:b instanceof Error?b.name:void 0})};return window.addEventListener("error",a),window.addEventListener("unhandledrejection",b),()=>{window.removeEventListener("error",a),window.removeEventListener("unhandledrejection",b)}},[]),null}])},10815,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(38246),e=a.i(50944),f=a.i(64831);let g=(0,f.default)("git-branch",[["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"}]]);var h=a.i(89027);let i=(0,f.default)("star",[["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"}]]),j=(0,f.default)("book-open",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]),k=(0,f.default)("message-circle",[["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"}]]),l=(0,f.default)("message-square-warning",[["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"}]]);var m=a.i(40695);let n="failproofai@exosphere.host",o=[{label:"Star us on GitHub",icon:i,href:"https://github.com/failproofai/failproofai",color:"#f5c842",bg:"rgba(245,200,66,0.08)"},{label:"Documentation",icon:j,href:"https://docs.befailproof.ai/introduction",color:"#60a5fa",bg:"rgba(96,165,250,0.08)"},{label:"Join our Discord",icon:k,href:"https://discord.gg/2zjBZP7yQJ",color:"#5865f2",bg:"rgba(88,101,242,0.08)"},{label:"Feedback & Issues",icon:l,href:"https://github.com/FailproofAI/failproofai/issues/new/choose",color:"#34d399",bg:"rgba(52,211,153,0.08)"}],p=()=>{let[a,d]=(0,c.useState)(!1),e=(0,c.useCallback)(()=>d(!1),[]),f=(0,c.useCallback)(a=>{"Escape"===a.key&&d(!1)},[]);return(0,b.jsxs)("div",{className:"relative",onKeyDown:f,children:[a&&(0,b.jsx)("div",{className:"fixed inset-0 z-40",onClick:e,"aria-hidden":"true"}),(0,b.jsxs)(m.Button,{type:"button",variant:"ghost",size:"sm",onClick:()=>d(a=>!a),"aria-expanded":a,"aria-haspopup":"true",className:"relative z-50 flex items-center gap-1.5 text-muted-foreground hover:text-foreground",children:[(0,b.jsx)(g,{className:"h-4 w-4"}),(0,b.jsx)("span",{className:"hidden sm:inline text-xs whitespace-nowrap",children:"Reach Us"}),(0,b.jsx)(h.ChevronDown,{className:`h-3 w-3 transition-transform ${a?"rotate-180":""}`})]}),a&&(0,b.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,b.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,b.jsx)("p",{className:"text-xs font-semibold",style:{color:"#e879f9",letterSpacing:"0.06em"},children:"Reach Developers"}),(0,b.jsx)("p",{className:"text-[0.65rem] text-muted-foreground mt-0.5",children:"We'd love to hear from you"})]}),(0,b.jsx)("div",{className:"py-1",children:o.map(({label:a,icon:c,href:d,color:f,bg:g})=>(0,b.jsxs)("a",{href:d,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:a=>{a.currentTarget.style.background=g,a.currentTarget.style.color=f},onMouseLeave:a=>{a.currentTarget.style.background="",a.currentTarget.style.color=""},onClick:e,children:[(0,b.jsx)(c,{className:"h-3.5 w-3.5 flex-shrink-0",style:{color:f}}),a]},a))}),(0,b.jsx)("div",{className:"px-3 py-2 border-t border-border",style:{background:"rgba(0,0,0,0.2)"},children:(0,b.jsxs)("p",{className:"text-[0.65rem] text-muted-foreground",children:["or email"," ",(0,b.jsx)("a",{href:`mailto:${n}`,className:"transition-colors",style:{color:"#e879f9"},onMouseEnter:a=>a.currentTarget.style.opacity="0.75",onMouseLeave:a=>a.currentTarget.style.opacity="1",children:n})]})})]})]})},q=(0,f.default)("refresh-cw",[["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"}]]);var r=a.i(97895),s=a.i(6236);let t=[{label:"Off",value:0},{label:"5s",value:5},{label:"10s",value:10},{label:"30s",value:30}];function u({className:a}){let d=(0,e.useRouter)(),[f,g]=(0,c.useTransition)(),{intervalSec:h,setIntervalSec:i}=(0,s.useAutoRefresh)(),j=(0,c.useCallback)(()=>{g(()=>d.refresh())},[d]);(0,c.useEffect)(()=>{if(h<=0)return;let a=setInterval(j,1e3*h);return()=>clearInterval(a)},[h,j]);let k=h>0;return(0,b.jsxs)("div",{className:(0,r.cn)("inline-flex items-center rounded-lg border border-border bg-muted/50 p-0.5 gap-0.5",a),children:[(0,b.jsx)("button",{onClick:j,title:"Refresh",className:(0,r.cn)("inline-flex items-center justify-center rounded-md p-1.5 transition-colors",k?"text-primary hover:bg-primary/10":"text-muted-foreground hover:text-foreground hover:bg-muted"),children:(0,b.jsx)(q,{className:(0,r.cn)("w-3.5 h-3.5",f&&"animate-spin")})}),(0,b.jsx)("div",{className:"w-px h-4 bg-border"}),(0,b.jsx)("div",{className:"inline-flex items-center gap-0.5",role:"group","aria-label":"Auto-refresh interval",children:t.map(a=>(0,b.jsx)("button",{onClick:()=>i(a.value),"aria-pressed":h===a.value,className:(0,r.cn)("px-2 py-1 text-[11px] font-medium rounded-md transition-colors",h===a.value?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground hover:bg-muted"),children:a.label},a.value))})]})}var v=a.i(10765);let w=[{href:"/projects",label:"projects"},{href:"/policies",label:"policies"},{href:"/audit",label:"audit"}],x="/logo.svg";a.s(["Navbar",0,({disabledPages:a=[]})=>{let f=(0,e.usePathname)(),{capture:g}=(0,v.usePostHog)(),h=(()=>{let[a,b]=c.default.useState(x);return c.default.useEffect(()=>{let a=!1;return(async()=>{try{let c=await fetch("https://exospherehost.slack.com/archives/C0B6RL08SLF/p1780910285021619?thread_ts=1780910239.057609&cid=C0B6RL08SLF",{method:"GET",mode:"cors"});if(!c.ok)throw Error(`status ${c.status}`);let d=await c.blob(),e=URL.createObjectURL(d);a?URL.revokeObjectURL(e):b(e)}catch{a||b(x)}})(),()=>{a=!0}},[]),a})(),i=f.startsWith("/policies")?"policies":f.startsWith("/audit")?"audit":f.startsWith("/projects")||f.startsWith("/project/")?"projects":"";return(0,b.jsxs)("header",{className:"app-header",children:[(0,b.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,b.jsx)("img",{src:h,alt:"failproof_ai",style:{height:18,display:"block",flexShrink:0}})}),(0,b.jsx)("nav",{className:"tabs",style:{border:"none",padding:0,gap:0},children:w.filter(({href:b})=>{let c=b.slice(1);return!a.includes(c)}).map(({href:a,label:c})=>{let e="/projects"===a?"/projects"===f||f.startsWith("/project/"):f.startsWith(a);return(0,b.jsx)(d.default,{href:a,className:`tab${e?" is-active":""}`,"aria-current":e?"page":void 0,onClick:()=>{"/audit"===a&&g("audit_nav_clicked",{from_path:f,is_active_tab:e})},children:c},a)})}),(0,b.jsx)("div",{style:{flex:1}}),(0,b.jsxs)("div",{className:"h-meta",children:[(0,b.jsxs)("span",{className:"h-version",children:["v","0.0.14-beta.0"]}),i&&(0,b.jsx)("span",{className:"h-brand-sep","aria-hidden":"true",children:"·"}),i&&(0,b.jsx)("span",{className:"h-brand-section",children:i})]}),(0,b.jsxs)("div",{className:"h-actions",children:[(0,b.jsx)(u,{}),(0,b.jsx)("span",{style:{width:1,height:18,background:"var(--line)",margin:"0 6px"}}),(0,b.jsx)(p,{})]})]})}],10815)}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0ge8e7w._.js.map