failproofai 0.0.6-beta.0 → 0.0.6-beta.2

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 (191) hide show
  1. package/.next/standalone/.failproofai/policies/review-policies.mjs +113 -0
  2. package/.next/standalone/.next/BUILD_ID +1 -1
  3. package/.next/standalone/.next/build-manifest.json +5 -5
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  13. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  22. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  23. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  24. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  25. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  26. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  28. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/.next/standalone/.next/server/app/index.html +1 -1
  30. package/.next/standalone/.next/server/app/index.rsc +15 -15
  31. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  33. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  34. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  35. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  36. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  41. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  42. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  45. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  51. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g72weg._.js +1 -1
  58. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  59. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0a.nuas._.js → [root-of-the-server]__05akje6._.js} +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  61. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  62. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  63. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  64. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0.~fd7s._.js → [root-of-the-server]__0i5kvry._.js} +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0okos0k._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +6 -6
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
  72. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  73. package/.next/standalone/.next/server/pages/404.html +2 -2
  74. package/.next/standalone/.next/server/pages/500.html +1 -1
  75. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  77. package/.next/standalone/.next/static/chunks/{0teq8wdh3po1n.js → 00j0rr7rh8ef8.js} +1 -1
  78. package/.next/standalone/.next/static/chunks/{0maq.q1t.ri85.js → 05j1px0r8yzh6.js} +2 -2
  79. package/.next/standalone/.next/static/chunks/0badv41uxa56..js +4 -0
  80. package/.next/standalone/.next/static/chunks/{0hplx-8c-4vpv.js → 0ijk_kek9_wyx.js} +1 -1
  81. package/.next/standalone/.next/static/chunks/{0uc0um_uz51m_.js → 0npb~873.wvg3.js} +1 -1
  82. package/.next/standalone/.next/static/chunks/{0hctoh28rg838.js → 0xpl.oscrakvx.js} +1 -1
  83. package/.next/standalone/.next/static/chunks/{0.z51twd.0l5z.js → 1052sguyd-.ka.js} +1 -1
  84. package/.next/standalone/.next/static/chunks/{09e7drilkf1sn.js → 12simlrcfk3g2.js} +1 -1
  85. package/.next/standalone/.next/static/chunks/{0ul6fk-z.6k-0.js → 14cl9poem30dq.js} +1 -1
  86. package/.next/standalone/.next/static/chunks/{turbopack-0r26pc8h0y_-e.js → turbopack-0o7k.hakttp4k.js} +1 -1
  87. package/.next/standalone/CHANGELOG.md +19 -0
  88. package/.next/standalone/README.md +2 -2
  89. package/.next/standalone/bun.lock +43 -85
  90. package/.next/standalone/dist/cli.mjs +91 -4
  91. package/.next/standalone/docs/ar/built-in-policies.mdx +124 -87
  92. package/.next/standalone/docs/ar/custom-policies.mdx +72 -72
  93. package/.next/standalone/docs/ar/examples.mdx +86 -33
  94. package/.next/standalone/docs/ar/getting-started.mdx +82 -29
  95. package/.next/standalone/docs/built-in-policies.mdx +38 -1
  96. package/.next/standalone/docs/custom-policies.mdx +1 -1
  97. package/.next/standalone/docs/de/built-in-policies.mdx +93 -56
  98. package/.next/standalone/docs/de/custom-policies.mdx +56 -56
  99. package/.next/standalone/docs/de/examples.mdx +72 -18
  100. package/.next/standalone/docs/de/getting-started.mdx +72 -20
  101. package/.next/standalone/docs/es/built-in-policies.mdx +115 -78
  102. package/.next/standalone/docs/es/custom-policies.mdx +55 -55
  103. package/.next/standalone/docs/es/examples.mdx +73 -19
  104. package/.next/standalone/docs/es/getting-started.mdx +72 -20
  105. package/.next/standalone/docs/examples.mdx +54 -0
  106. package/.next/standalone/docs/fr/built-in-policies.mdx +83 -46
  107. package/.next/standalone/docs/fr/custom-policies.mdx +51 -51
  108. package/.next/standalone/docs/fr/examples.mdx +78 -24
  109. package/.next/standalone/docs/fr/getting-started.mdx +65 -13
  110. package/.next/standalone/docs/getting-started.mdx +52 -0
  111. package/.next/standalone/docs/he/built-in-policies.mdx +156 -117
  112. package/.next/standalone/docs/he/custom-policies.mdx +75 -75
  113. package/.next/standalone/docs/he/examples.mdx +87 -33
  114. package/.next/standalone/docs/he/getting-started.mdx +84 -33
  115. package/.next/standalone/docs/hi/built-in-policies.mdx +101 -60
  116. package/.next/standalone/docs/hi/custom-policies.mdx +71 -70
  117. package/.next/standalone/docs/hi/examples.mdx +90 -36
  118. package/.next/standalone/docs/hi/getting-started.mdx +80 -27
  119. package/.next/standalone/docs/i18n/README.ar.md +69 -69
  120. package/.next/standalone/docs/i18n/README.de.md +46 -46
  121. package/.next/standalone/docs/i18n/README.es.md +42 -42
  122. package/.next/standalone/docs/i18n/README.fr.md +39 -39
  123. package/.next/standalone/docs/i18n/README.he.md +83 -83
  124. package/.next/standalone/docs/i18n/README.hi.md +69 -69
  125. package/.next/standalone/docs/i18n/README.it.md +72 -72
  126. package/.next/standalone/docs/i18n/README.ja.md +71 -71
  127. package/.next/standalone/docs/i18n/README.ko.md +52 -52
  128. package/.next/standalone/docs/i18n/README.pt-br.md +44 -44
  129. package/.next/standalone/docs/i18n/README.ru.md +66 -66
  130. package/.next/standalone/docs/i18n/README.tr.md +82 -83
  131. package/.next/standalone/docs/i18n/README.vi.md +70 -71
  132. package/.next/standalone/docs/i18n/README.zh.md +51 -51
  133. package/.next/standalone/docs/it/built-in-policies.mdx +118 -81
  134. package/.next/standalone/docs/it/custom-policies.mdx +69 -69
  135. package/.next/standalone/docs/it/examples.mdx +93 -39
  136. package/.next/standalone/docs/it/getting-started.mdx +73 -21
  137. package/.next/standalone/docs/ja/built-in-policies.mdx +98 -61
  138. package/.next/standalone/docs/ja/custom-policies.mdx +71 -71
  139. package/.next/standalone/docs/ja/examples.mdx +76 -22
  140. package/.next/standalone/docs/ja/getting-started.mdx +65 -13
  141. package/.next/standalone/docs/ko/built-in-policies.mdx +137 -100
  142. package/.next/standalone/docs/ko/custom-policies.mdx +67 -67
  143. package/.next/standalone/docs/ko/examples.mdx +87 -33
  144. package/.next/standalone/docs/ko/getting-started.mdx +61 -9
  145. package/.next/standalone/docs/pt-br/built-in-policies.mdx +94 -57
  146. package/.next/standalone/docs/pt-br/custom-policies.mdx +56 -56
  147. package/.next/standalone/docs/pt-br/examples.mdx +78 -24
  148. package/.next/standalone/docs/pt-br/getting-started.mdx +64 -12
  149. package/.next/standalone/docs/ru/built-in-policies.mdx +142 -105
  150. package/.next/standalone/docs/ru/custom-policies.mdx +82 -81
  151. package/.next/standalone/docs/ru/examples.mdx +77 -22
  152. package/.next/standalone/docs/ru/getting-started.mdx +74 -22
  153. package/.next/standalone/docs/tr/built-in-policies.mdx +104 -67
  154. package/.next/standalone/docs/tr/custom-policies.mdx +59 -60
  155. package/.next/standalone/docs/tr/examples.mdx +97 -42
  156. package/.next/standalone/docs/tr/getting-started.mdx +75 -23
  157. package/.next/standalone/docs/vi/built-in-policies.mdx +110 -72
  158. package/.next/standalone/docs/vi/custom-policies.mdx +68 -68
  159. package/.next/standalone/docs/vi/examples.mdx +93 -38
  160. package/.next/standalone/docs/vi/getting-started.mdx +74 -22
  161. package/.next/standalone/docs/zh/built-in-policies.mdx +132 -95
  162. package/.next/standalone/docs/zh/custom-policies.mdx +49 -49
  163. package/.next/standalone/docs/zh/examples.mdx +90 -36
  164. package/.next/standalone/docs/zh/getting-started.mdx +73 -21
  165. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  166. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  167. package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +7 -7
  168. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  169. package/.next/standalone/node_modules/next/dist/server/config-schema.js +10 -2
  170. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  171. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  172. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  173. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  174. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  175. package/.next/standalone/node_modules/next/dist/server/render.js +27 -20
  176. package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
  177. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  178. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  179. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  180. package/.next/standalone/node_modules/next/package.json +15 -15
  181. package/.next/standalone/package.json +2 -2
  182. package/.next/standalone/server.js +1 -1
  183. package/.next/standalone/src/hooks/builtin-policies.ts +106 -1
  184. package/README.md +2 -2
  185. package/dist/cli.mjs +91 -4
  186. package/package.json +2 -2
  187. package/src/hooks/builtin-policies.ts +106 -1
  188. package/.next/standalone/.next/static/chunks/0w9lwqy0-v1dk.js +0 -4
  189. /package/.next/standalone/.next/static/{8mygPGI5bzrtWK36ZYO59 → A9pNTZdoYJTVyPAYwQMx5}/_buildManifest.js +0 -0
  190. /package/.next/standalone/.next/static/{8mygPGI5bzrtWK36ZYO59 → A9pNTZdoYJTVyPAYwQMx5}/_clientMiddlewareManifest.js +0 -0
  191. /package/.next/standalone/.next/static/{8mygPGI5bzrtWK36ZYO59 → A9pNTZdoYJTVyPAYwQMx5}/_ssgManifest.js +0 -0
@@ -72,7 +72,7 @@ async function fetchPkgInfo(pkg) {
72
72
  });
73
73
  }
74
74
  const data = await res.json();
75
- const versionData = data.versions["16.2.3"];
75
+ const versionData = data.versions["16.2.4"];
76
76
  return {
77
77
  os: versionData.os,
78
78
  cpu: versionData.cpu,
@@ -100,7 +100,7 @@ async function patchIncorrectLockfile(dir) {
100
100
  const expectedSwcPkgs = Object.keys(_packagejson.optionalDependencies || {}).filter((pkg)=>pkg.startsWith('@next/swc-'));
101
101
  const patchDependency = (pkg, pkgData)=>{
102
102
  lockfileParsed.dependencies[pkg] = {
103
- version: "16.2.3",
103
+ version: "16.2.4",
104
104
  resolved: pkgData.tarball,
105
105
  integrity: pkgData.integrity,
106
106
  optional: true
@@ -108,7 +108,7 @@ async function patchIncorrectLockfile(dir) {
108
108
  };
109
109
  const patchPackage = (pkg, pkgData)=>{
110
110
  lockfileParsed.packages[pkg] = {
111
- version: "16.2.3",
111
+ version: "16.2.4",
112
112
  resolved: pkgData.tarball,
113
113
  integrity: pkgData.integrity,
114
114
  cpu: pkgData.cpu,
@@ -507,8 +507,16 @@ const configSchema = _zod.z.lazy(()=>_zod.z.strictObject({
507
507
  useLightningcss: _zod.z.boolean().optional()
508
508
  })
509
509
  ]),
510
- define: _zod.z.record(_zod.z.string(), _zod.z.string()).optional(),
511
- defineServer: _zod.z.record(_zod.z.string(), _zod.z.string()).optional(),
510
+ define: _zod.z.record(_zod.z.string(), _zod.z.union([
511
+ _zod.z.string(),
512
+ _zod.z.number(),
513
+ _zod.z.boolean()
514
+ ])).optional(),
515
+ defineServer: _zod.z.record(_zod.z.string(), _zod.z.union([
516
+ _zod.z.string(),
517
+ _zod.z.number(),
518
+ _zod.z.boolean()
519
+ ])).optional(),
512
520
  runAfterProductionCompile: _zod.z.function().returns(_zod.z.promise(_zod.z.void())).optional()
513
521
  }).optional(),
514
522
  compress: _zod.z.boolean().optional(),
@@ -1106,7 +1106,7 @@ async function applyModifyConfig(config, phase, silent) {
1106
1106
  }
1107
1107
  config = await adapterMod.modifyConfig(config, {
1108
1108
  phase,
1109
- nextVersion: "16.2.3"
1109
+ nextVersion: "16.2.4"
1110
1110
  });
1111
1111
  }
1112
1112
  }
@@ -240,7 +240,7 @@ async function createHotReloaderTurbopack(opts, serverFields, distDir, resetFetc
240
240
  }
241
241
  const hasRewrites = opts.fsChecker.rewrites.afterFiles.length > 0 || opts.fsChecker.rewrites.beforeFiles.length > 0 || opts.fsChecker.rewrites.fallback.length > 0;
242
242
  const hotReloaderSpan = (0, _trace.trace)('hot-reloader', undefined, {
243
- version: "16.2.3"
243
+ version: "16.2.4"
244
244
  });
245
245
  // Ensure the hotReloaderSpan is flushed immediately as it's the parentSpan for all processing
246
246
  // of the current `next dev` invocation.
@@ -294,7 +294,7 @@ async function createHotReloaderTurbopack(opts, serverFields, distDir, resetFetc
294
294
  writeRoutesHashesManifest: false,
295
295
  currentNodeJsVersion,
296
296
  isPersistentCachingEnabled: (0, _utils2.isFileSystemCacheEnabledForDev)(opts.nextConfig),
297
- nextVersion: "16.2.3",
297
+ nextVersion: "16.2.4",
298
298
  serverHmr: serverFastRefresh
299
299
  }, {
300
300
  memoryLimit: (_opts_nextConfig_experimental = opts.nextConfig.experimental) == null ? void 0 : _opts_nextConfig_experimental.turbopackMemoryLimit,
@@ -234,7 +234,7 @@ class HotReloaderWebpack {
234
234
  this.previewProps = previewProps;
235
235
  this.rewrites = rewrites;
236
236
  this.hotReloaderSpan = (0, _trace.trace)('hot-reloader', undefined, {
237
- version: "16.2.3"
237
+ version: "16.2.4"
238
238
  });
239
239
  // Ensure the hotReloaderSpan is flushed immediately as it's the parentSpan for all processing
240
240
  // of the current `next dev` invocation.
@@ -85,7 +85,7 @@ function logStartInfo({ networkUrl, appUrl, envInfo, logBundler }) {
85
85
  if (parts.length > 0) {
86
86
  versionSuffix = ` (${parts.join(', ')})`;
87
87
  }
88
- _log.bootstrap(`${(0, _picocolors.bold)((0, _picocolors.purple)(`${_log.prefixes.ready} Next.js ${"16.2.3"}`))}${versionSuffix}`);
88
+ _log.bootstrap(`${(0, _picocolors.bold)((0, _picocolors.purple)(`${_log.prefixes.ready} Next.js ${"16.2.4"}`))}${versionSuffix}`);
89
89
  if (appUrl) {
90
90
  _log.bootstrap(`- Local: ${appUrl}`);
91
91
  }
@@ -178,7 +178,7 @@ async function getRequestHandlers({ dir, port, isDev, onDevServerCleanup, server
178
178
  async function startServer(serverOptions) {
179
179
  const { dir, isDev, hostname, minimalMode, allowRetry, keepAliveTimeout, selfSignedCertificate, serverFastRefresh } = serverOptions;
180
180
  let { port } = serverOptions;
181
- process.title = `next-server (v${"16.2.3"})`;
181
+ process.title = `next-server (v${"16.2.4"})`;
182
182
  let handlersReady = ()=>{};
183
183
  let handlersError = ()=>{};
184
184
  let handlersPromise = new Promise((resolve, reject)=>{
@@ -204,29 +204,35 @@ function serializeError(dev, err) {
204
204
  statusCode: 500
205
205
  };
206
206
  }
207
+ function getSafariCacheBusterQueryString(req) {
208
+ if (process.env.__NEXT_DEV_SERVER) {
209
+ const userAgent = (req.headers['user-agent'] || '').toLowerCase();
210
+ if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
211
+ return `?ts=${Date.now()}`;
212
+ }
213
+ }
214
+ return '';
215
+ }
207
216
  async function renderToHTMLImpl(req, res, pathname, query, renderOpts, extra, sharedContext, renderContext) {
208
217
  // Adds support for reading `cookies` in `getServerSideProps` when SSR.
209
218
  (0, _apiutils.setLazyProp)({
210
219
  req: req
211
220
  }, 'cookies', (0, _getcookieparser.getCookieParser)(req.headers));
212
- let baseAssetQueryString = process.env.__NEXT_DEV_SERVER && renderOpts.assetQueryString || '';
213
- if (process.env.__NEXT_DEV_SERVER && !baseAssetQueryString) {
214
- const userAgent = (req.headers['user-agent'] || '').toLowerCase();
215
- if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
216
- // In dev we invalidate the cache by appending a timestamp to the resource URL.
217
- // This is a workaround to fix https://github.com/vercel/next.js/issues/5860
218
- // TODO: remove this workaround when https://bugs.webkit.org/show_bug.cgi?id=187726 is fixed.
219
- // Note: The workaround breaks breakpoints on reload since the script url always changes,
220
- // so we only apply it to Safari.
221
- baseAssetQueryString = `?ts=${Date.now()}`;
222
- }
223
- }
224
- const mutableAssetQueryString = baseAssetQueryString + (sharedContext.deploymentId ? `${baseAssetQueryString ? '&' : '?'}dpl=${sharedContext.deploymentId}` : '');
225
- const assetQueryString = baseAssetQueryString + (sharedContext.clientAssetToken ? `${baseAssetQueryString ? '&' : '?'}dpl=${sharedContext.clientAssetToken}` : '');
226
- const metadata = {
227
- assetQueryString,
228
- mutableAssetQueryString
229
- };
221
+ // cssCacheBuster is a workaround for a Safari bug
222
+ // (https://bugs.webkit.org/show_bug.cgi?id=187726) where preloaded CSS
223
+ // resources are cached and not re-fetched on HMR. It must only be applied
224
+ // to CSS and font assets — not to script tags — because the Turbopack
225
+ // runtime infers ASSET_SUFFIX from the executing script's query string and
226
+ // leaks it onto all static asset URLs (including images), causing
227
+ // next/image validation errors.
228
+ // See https://github.com/vercel/next.js/issues/92118.
229
+ const cssCacheBuster = getSafariCacheBusterQueryString(req);
230
+ const mutableAssetQueryString = sharedContext.deploymentId ? `?dpl=${sharedContext.deploymentId}` : '';
231
+ const assetQueryString = sharedContext.clientAssetToken ? `?dpl=${sharedContext.clientAssetToken}` : '';
232
+ // cssAssetQueryString is assetQueryString with the cacheBuster prepended.
233
+ // Use this for CSS and font URLs; use assetQueryString for script URLs.
234
+ const cssAssetQueryString = cssCacheBuster + (sharedContext.clientAssetToken ? `${cssCacheBuster ? '&' : '?'}dpl=${sharedContext.clientAssetToken}` : '');
235
+ const metadata = {};
230
236
  // don't modify original query object
231
237
  query = Object.assign({}, query);
232
238
  const { err, pageConfig = {}, buildManifest, reactLoadableManifest, ErrorDebug, getStaticProps, getStaticPaths, getServerSideProps, isNextDataRequest, params, previewProps, basePath, images, runtime: globalRuntime, isExperimentalCompile, expireTime } = renderOpts;
@@ -1080,8 +1086,9 @@ async function renderToHTMLImpl(req, res, pathname, query, renderOpts, extra, sh
1080
1086
  // Only enabled in production as development mode has features relying on HMR (style injection for example)
1081
1087
  unstable_runtimeJS: process.env.NODE_ENV === 'production' ? pageConfig.unstable_runtimeJS : undefined,
1082
1088
  unstable_JsPreload: pageConfig.unstable_JsPreload,
1083
- assetQueryString: assetQueryString || '',
1084
- mutableAssetQueryString: mutableAssetQueryString || '',
1089
+ assetQueryString,
1090
+ cssAssetQueryString,
1091
+ mutableAssetQueryString,
1085
1092
  scriptLoader,
1086
1093
  locale,
1087
1094
  disableOptimizedLoading,
@@ -21,7 +21,7 @@ _export(exports, {
21
21
  }
22
22
  });
23
23
  function isStableBuild() {
24
- return !"16.2.3"?.includes('canary') && !process.env.__NEXT_TEST_MODE && !process.env.NEXT_PRIVATE_LOCAL_DEV;
24
+ return !"16.2.4"?.includes('canary') && !process.env.__NEXT_TEST_MODE && !process.env.NEXT_PRIVATE_LOCAL_DEV;
25
25
  }
26
26
  class CanaryOnlyConfigError extends Error {
27
27
  constructor(arg){
@@ -81,7 +81,7 @@ function getAnonymousMeta() {
81
81
  isWsl: _iswsl.default,
82
82
  isCI: _ciinfo.isCI,
83
83
  ciName: _ciinfo.isCI && _ciinfo.name || null,
84
- nextVersion: "16.2.3"
84
+ nextVersion: "16.2.4"
85
85
  };
86
86
  return traits;
87
87
  }
@@ -38,7 +38,7 @@ async function eventSwcLoadFailure(event) {
38
38
  telemetry.record({
39
39
  eventName: EVENT_PLUGIN_PRESENT,
40
40
  payload: {
41
- nextVersion: "16.2.3",
41
+ nextVersion: "16.2.4",
42
42
  glibcVersion,
43
43
  installedSwcPackages,
44
44
  arch: process.arch,
@@ -12,12 +12,12 @@ const EVENT_VERSION = 'NEXT_CLI_SESSION_STARTED';
12
12
  function eventCliSession(nextConfig, event) {
13
13
  var _nextConfig_experimental_staleTimes, _nextConfig_experimental_staleTimes1, _nextConfig_reactCompiler, _nextConfig_reactCompiler1;
14
14
  // This should be an invariant, if it fails our build tooling is broken.
15
- if (typeof "16.2.3" !== 'string') {
15
+ if (typeof "16.2.4" !== 'string') {
16
16
  return [];
17
17
  }
18
18
  const { images, i18n } = nextConfig || {};
19
19
  const payload = {
20
- nextVersion: "16.2.3",
20
+ nextVersion: "16.2.4",
21
21
  nodeVersion: process.version,
22
22
  cliCommand: event.cliCommand,
23
23
  isSrcDir: event.isSrcDir,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next",
3
- "version": "16.2.3",
3
+ "version": "16.2.4",
4
4
  "description": "The React Framework",
5
5
  "main": "./dist/server/next.js",
6
6
  "license": "MIT",
@@ -97,7 +97,7 @@
97
97
  ]
98
98
  },
99
99
  "dependencies": {
100
- "@next/env": "16.2.3",
100
+ "@next/env": "16.2.4",
101
101
  "@swc/helpers": "0.5.15",
102
102
  "baseline-browser-mapping": "^2.9.19",
103
103
  "caniuse-lite": "^1.0.30001579",
@@ -128,14 +128,14 @@
128
128
  },
129
129
  "optionalDependencies": {
130
130
  "sharp": "^0.34.5",
131
- "@next/swc-darwin-arm64": "16.2.3",
132
- "@next/swc-darwin-x64": "16.2.3",
133
- "@next/swc-linux-arm64-gnu": "16.2.3",
134
- "@next/swc-linux-arm64-musl": "16.2.3",
135
- "@next/swc-linux-x64-gnu": "16.2.3",
136
- "@next/swc-linux-x64-musl": "16.2.3",
137
- "@next/swc-win32-arm64-msvc": "16.2.3",
138
- "@next/swc-win32-x64-msvc": "16.2.3"
131
+ "@next/swc-darwin-arm64": "16.2.4",
132
+ "@next/swc-darwin-x64": "16.2.4",
133
+ "@next/swc-linux-arm64-gnu": "16.2.4",
134
+ "@next/swc-linux-arm64-musl": "16.2.4",
135
+ "@next/swc-linux-x64-gnu": "16.2.4",
136
+ "@next/swc-linux-x64-musl": "16.2.4",
137
+ "@next/swc-win32-arm64-msvc": "16.2.4",
138
+ "@next/swc-win32-x64-msvc": "16.2.4"
139
139
  },
140
140
  "devDependencies": {
141
141
  "@babel/core": "7.26.10",
@@ -169,11 +169,11 @@
169
169
  "@modelcontextprotocol/sdk": "1.18.1",
170
170
  "@mswjs/interceptors": "0.23.0",
171
171
  "@napi-rs/triples": "1.2.0",
172
- "@next/font": "16.2.3",
173
- "@next/polyfill-module": "16.2.3",
174
- "@next/polyfill-nomodule": "16.2.3",
175
- "@next/react-refresh-utils": "16.2.3",
176
- "@next/swc": "16.2.3",
172
+ "@next/font": "16.2.4",
173
+ "@next/polyfill-module": "16.2.4",
174
+ "@next/polyfill-nomodule": "16.2.4",
175
+ "@next/react-refresh-utils": "16.2.4",
176
+ "@next/swc": "16.2.4",
177
177
  "@opentelemetry/api": "1.6.0",
178
178
  "@playwright/test": "1.58.2",
179
179
  "@rspack/core": "1.6.7",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "0.0.6-beta.0",
3
+ "version": "0.0.6-beta.2",
4
4
  "description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK",
5
5
  "bin": {
6
6
  "failproofai": "./dist/cli.mjs"
@@ -90,7 +90,7 @@
90
90
  "tailwind-merge": "^3.4.0",
91
91
  "tailwindcss": "^4.1.18",
92
92
  "typescript": "^6.0.2",
93
- "@anthropic-ai/sdk": "^0.39.0",
93
+ "@anthropic-ai/sdk": "^0.90.0",
94
94
  "vitest": "^4.0.18"
95
95
  },
96
96
  "dependencies": {
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
9
9
  const hostname = process.env.HOSTNAME || '0.0.0.0'
10
10
 
11
11
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
12
- const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.6-beta.0"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"distDirRoot":".next"}
12
+ const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.6-beta.2"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"distDirRoot":".next"}
13
13
 
14
14
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
15
15
 
@@ -138,6 +138,20 @@ const BUN_GLOBAL_RE = /\bbun\s+(?:install|add)\b(?=.*(?:\s-g\b|--global\b))/;
138
138
  const CARGO_INSTALL_RE = /\bcargo\s+install\b/;
139
139
  const PIP_SYSTEM_RE = /\bpip(?:3)?\s+install\b(?=.*(?:--user\b|--break-system-packages\b))/;
140
140
 
141
+ // preferPackageManager — maps manager name → detection patterns
142
+ const PKG_MANAGER_DETECTORS: Record<string, RegExp[]> = {
143
+ pip: [/\bpip\b/, /\bpip3\b/, /\bpython3?\s+-m\s+pip\b/],
144
+ npm: [/\bnpm\b/, /\bnpx\b/],
145
+ yarn: [/\byarn\b/],
146
+ pnpm: [/\bpnpm\b/, /\bpnpx\b/],
147
+ bun: [/\bbun\b/, /\bbunx\b/],
148
+ uv: [/\buv\b/],
149
+ poetry: [/\bpoetry\b/],
150
+ pipenv: [/\bpipenv\b/],
151
+ conda: [/\bconda\b/],
152
+ cargo: [/\bcargo\b/],
153
+ };
154
+
141
155
  // warnBackgroundProcess
142
156
  const NOHUP_RE = /\bnohup\s+\S/;
143
157
  const SCREEN_DETACH_RE = /\bscreen\s+-[A-Za-z]*d[A-Za-z]*\b/;
@@ -857,6 +871,73 @@ function warnGlobalPackageInstall(ctx: PolicyContext): PolicyResult {
857
871
  return allow();
858
872
  }
859
873
 
874
+ // Split a compound shell command into independent segments.
875
+ const SEGMENT_SPLIT_RE = /\s*(?:&&|\|\||\||;)\s*/;
876
+
877
+ function preferPackageManager(ctx: PolicyContext): PolicyResult {
878
+ if (ctx.toolName !== "Bash") return allow();
879
+ const cmd = getCommand(ctx);
880
+ if (!cmd) return allow();
881
+
882
+ const allowed = (ctx.params?.allowed ?? []) as string[];
883
+ if (allowed.length === 0) return allow();
884
+
885
+ const allowedSet = new Set(allowed.map((a) => a.toLowerCase()));
886
+ const blocked = (ctx.params?.blocked ?? []) as string[];
887
+ const allowedList = allowed.join(", ");
888
+
889
+ // Evaluate each shell segment independently so that
890
+ // "uv --version && pip install flask" correctly denies the pip segment.
891
+ const segments = cmd.split(SEGMENT_SPLIT_RE);
892
+
893
+ for (const segment of segments) {
894
+ const trimmed = segment.trim();
895
+ if (!trimmed) continue;
896
+
897
+ // Check if this segment uses an allowed manager — if so, skip it.
898
+ let segmentAllowed = false;
899
+ for (const manager of allowedSet) {
900
+ const patterns = PKG_MANAGER_DETECTORS[manager];
901
+ if (!patterns) continue;
902
+ for (const pattern of patterns) {
903
+ if (pattern.test(trimmed)) { segmentAllowed = true; break; }
904
+ }
905
+ if (segmentAllowed) break;
906
+ }
907
+ if (segmentAllowed) continue;
908
+
909
+ // Check if this segment uses a non-allowed builtin manager.
910
+ for (const [manager, patterns] of Object.entries(PKG_MANAGER_DETECTORS)) {
911
+ if (allowedSet.has(manager)) continue;
912
+ for (const pattern of patterns) {
913
+ if (pattern.test(trimmed)) {
914
+ return deny(
915
+ `"${manager}" is not an allowed package manager. ` +
916
+ `Allowed package managers for this project: ${allowedList}. ` +
917
+ `Rewrite this command using an allowed package manager.`,
918
+ );
919
+ }
920
+ }
921
+ }
922
+
923
+ // Check user-specified blocked managers.
924
+ for (const name of blocked) {
925
+ const lower = name.toLowerCase();
926
+ if (allowedSet.has(lower)) continue;
927
+ const re = new RegExp(`\\b${lower.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`);
928
+ if (re.test(trimmed)) {
929
+ return deny(
930
+ `"${lower}" is not an allowed package manager. ` +
931
+ `Allowed package managers for this project: ${allowedList}. ` +
932
+ `Rewrite this command using an allowed package manager.`,
933
+ );
934
+ }
935
+ }
936
+ }
937
+
938
+ return allow();
939
+ }
940
+
860
941
  function warnBackgroundProcess(ctx: PolicyContext): PolicyResult {
861
942
  if (ctx.toolName !== "Bash") return allow();
862
943
  const cmd = getCommand(ctx);
@@ -1148,7 +1229,11 @@ function requireCiGreenBeforeStop(ctx: PolicyContext): PolicyResult {
1148
1229
  if (allChecks.length === 0) return allow(`No CI runs found for branch "${branch}".`);
1149
1230
 
1150
1231
  const failing = allChecks.filter(
1151
- (r) => r.status === "completed" && r.conclusion !== "success" && r.conclusion !== "skipped",
1232
+ (r) =>
1233
+ r.status === "completed" &&
1234
+ r.conclusion !== "success" &&
1235
+ r.conclusion !== "skipped" &&
1236
+ r.conclusion !== "cancelled",
1152
1237
  );
1153
1238
  if (failing.length > 0) {
1154
1239
  const names = failing.map((r) => `"${r.name}"`).join(", ");
@@ -1409,6 +1494,26 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1409
1494
  defaultEnabled: false,
1410
1495
  category: "Packages & System",
1411
1496
  },
1497
+ {
1498
+ name: "prefer-package-manager",
1499
+ description: "Blocks non-preferred package managers and tells Claude to use an allowed one (e.g., uv instead of pip)",
1500
+ fn: preferPackageManager,
1501
+ match: { events: ["PreToolUse"], toolNames: ["Bash"] },
1502
+ defaultEnabled: false,
1503
+ category: "Packages & System",
1504
+ params: {
1505
+ allowed: {
1506
+ type: "string[]",
1507
+ description: "Allowed package manager names (e.g. ['uv', 'bun']). Any detected manager not in this list is blocked.",
1508
+ default: [],
1509
+ },
1510
+ blocked: {
1511
+ type: "string[]",
1512
+ description: "Additional manager names to block beyond the built-in list (e.g. ['pdm', 'pipx']).",
1513
+ default: [],
1514
+ },
1515
+ } satisfies PolicyParamsSchema,
1516
+ },
1412
1517
  {
1413
1518
  name: "warn-large-file-write",
1414
1519
  description: "Warn before writing files larger than 1MB (configurable via thresholdKb param)",
package/README.md CHANGED
@@ -222,7 +222,7 @@ Custom hooks support transitive local imports, async/await, and access to `proce
222
222
 
223
223
  ### Convention-based policies
224
224
 
225
- Drop `*policies.{js,mjs,ts}` files into `.failproofai/policies/` and they're automatically loaded — no `--custom` flag or config changes needed. Works like git hooks: drop a file, it just works.
225
+ Drop `*policies.{js,mjs,ts}` files into `.failproofai/policies/` and they're automatically loaded — no flags or config changes needed. Commit the directory to git and every team member gets the same quality standards automatically.
226
226
 
227
227
  ```text
228
228
  # Project level — committed to git, shared with the team
@@ -233,7 +233,7 @@ Drop `*policies.{js,mjs,ts}` files into `.failproofai/policies/` and they're aut
233
233
  ~/.failproofai/policies/my-policies.mjs
234
234
  ```
235
235
 
236
- Both levels load (union). Files are loaded alphabetically within each directory. Prefix with `01-`, `02-`, etc. to control order. See [examples/convention-policies/](examples/convention-policies/) for ready-to-use examples.
236
+ Both levels load (union). Files are loaded alphabetically within each directory. Prefix with `01-`, `02-`, etc. to control order. As your team discovers new failure modes, add a policy and push — everyone gets the update on their next pull. See [examples/convention-policies/](examples/convention-policies/) for ready-to-use examples.
237
237
 
238
238
  ---
239
239