failproofai 1.0.2-beta.0 → 1.0.2-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 (125) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +14 -14
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  41. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  51. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  54. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  57. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  58. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  59. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  60. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
  61. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
  62. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
  63. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__07gm3zl._.js +14 -14
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l4748x._.js +3 -0
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/ssr/_0bwu160._.js +23 -0
  73. package/.next/standalone/.next/server/chunks/ssr/{_12l4a_k._.js → _0ns6k3a._.js} +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  80. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  81. package/.next/standalone/.next/server/pages/404.html +1 -1
  82. package/.next/standalone/.next/server/pages/500.html +1 -1
  83. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  84. package/.next/standalone/.next/server/server-reference-manifest.json +19 -19
  85. package/.next/standalone/.next/static/chunks/{35xg6retpe6rp.js → 01u1cf8js2yd6.js} +1 -1
  86. package/.next/standalone/.next/static/chunks/{2i2yt3hzjredm.js → 0izgu7nqh2zp-.js} +1 -1
  87. package/.next/standalone/.next/static/chunks/0u4-org_e7zde.js +1 -0
  88. package/.next/standalone/.next/static/chunks/{3y54nw0i7dsjl.js → 1tynnrrh711lr.js} +1 -1
  89. package/.next/standalone/.next/static/chunks/{0sa9v5mhc8861.js → 22rqvlr7p_1mv.js} +1 -1
  90. package/.next/standalone/.next/static/chunks/{2hs7ycvsav7v2.js → 2whxqyskpirbk.js} +1 -1
  91. package/.next/standalone/.next/static/chunks/31mwk8k0q3_3g.js +6 -0
  92. package/.next/standalone/.next/static/chunks/{2gn7ut4svofm2.js → 3ms6gxfm82t6s.js} +1 -1
  93. package/.next/standalone/.next/static/chunks/{0eqky-7n7dgdm.js → 3tbbs_d8xrvyp.js} +1 -1
  94. package/.next/standalone/.next/static/chunks/43nlc236oo898.js +1 -0
  95. package/.next/standalone/app/actions/pack-actions.ts +21 -11
  96. package/.next/standalone/app/policies/hooks-client.tsx +3 -4
  97. package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -1
  98. package/.next/standalone/package.json +10 -11
  99. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  100. package/.next/standalone/server.js +1 -1
  101. package/bin/failproofai.mjs +455 -316
  102. package/dist/cli.mjs +2296 -1736
  103. package/dist/worker.mjs +3 -12
  104. package/package.json +10 -11
  105. package/src/hooks/configure-wizard.ts +55 -368
  106. package/src/hooks/fp-reset.ts +10 -2
  107. package/src/hooks/handler.ts +2 -2
  108. package/src/hooks/manager.ts +14 -8
  109. package/src/hooks/pack-cli.ts +423 -43
  110. package/src/hooks/pack-failclosed.ts +1 -1
  111. package/src/hooks/pack-manifest.ts +14 -6
  112. package/src/hooks/pack-store.ts +89 -128
  113. package/src/hooks/tui.ts +126 -40
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zig5sv._.js +0 -3
  115. package/.next/standalone/.next/server/chunks/ssr/_00e9tnf._.js +0 -23
  116. package/.next/standalone/.next/static/chunks/1nuqytbta44af.js +0 -1
  117. package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +0 -6
  118. package/.next/standalone/.next/static/chunks/2aawsjld9ied_.js +0 -1
  119. package/policy-pack/SHA256SUMS +0 -2
  120. package/policy-pack/failproofai-pack.json +0 -732
  121. package/policy-pack/failproofai-pack.mjs +0 -2017
  122. package/src/hooks/policy-presets.ts +0 -137
  123. /package/.next/standalone/.next/static/{nwbyWT06Ud0XdXOrVJyvS → I5kEb9kSgYS63j4iqfVLO}/_buildManifest.js +0 -0
  124. /package/.next/standalone/.next/static/{nwbyWT06Ud0XdXOrVJyvS → I5kEb9kSgYS63j4iqfVLO}/_clientMiddlewareManifest.js +0 -0
  125. /package/.next/standalone/.next/static/{nwbyWT06Ud0XdXOrVJyvS → I5kEb9kSgYS63j4iqfVLO}/_ssgManifest.js +0 -0
@@ -2,7 +2,7 @@
2
2
  * Reads the installed policy packs a machine has on disk.
3
3
  *
4
4
  * A pack is the delivery unit for policies that did not ship compiled into this
5
- * build: `failproofai pack add` writes the artifact and records it here, and the
5
+ * build: `failproofai policies add` writes the artifact and records it here, and the
6
6
  * loader imports it through the same path custom policies already use.
7
7
  *
8
8
  * ## Why this is not `cloud-managed-policies.ts`
@@ -24,11 +24,19 @@
24
24
  * ## Fail-open, and the condition that makes it sound
25
25
  *
26
26
  * An unreadable manifest, a bad digest or a corrupt artifact yields zero packs
27
- * and a recorded error — it does not deny. That is only defensible **while the
28
- * builtin policies still ship compiled into the package and keep enforcing
29
- * underneath**. The day builtins become a fetched pack, this exact behaviour
30
- * becomes "zero enforcement on a machine reporting healthy", and this comment is
31
- * the reason that must be revisited rather than inherited.
27
+ * and a recorded error — this READER does not deny.
28
+ *
29
+ * That used to be defensible because the builtin policies shipped compiled in
30
+ * and kept enforcing underneath. They no longer do: the builtins ARE a pack now,
31
+ * so a silent zero here would be zero enforcement at exit 0 on a machine that
32
+ * reports healthy — exactly what the comment that stood here warned about.
33
+ *
34
+ * What makes it sound now is that the denying moved rather than disappeared:
35
+ * `pack-failclosed.ts` reads these same `errors` and refuses the events the
36
+ * missing policies declared. So this stays a pure reader that reports what it
37
+ * found, and the layer above decides what a failure means. Do not add a throw
38
+ * here — per-pack isolation is the reason one bad third-party pack cannot
39
+ * switch off every other pack on the machine.
32
40
  */
33
41
  import { createHash } from "node:crypto";
34
42
  import { existsSync, readFileSync } from "node:fs";
@@ -18,7 +18,9 @@
18
18
  * Asset URLs are CONSTRUCTED from an owner, repo and concrete tag. When the
19
19
  * user omits a tag, one `releases/latest` redirect resolves it before any asset
20
20
  * is fetched or written. There is no API lookup or rate-limit dependency, and
21
- * the installed record always names the pinned result.
21
+ * the installed record always names the pinned result — which has to AGREE with
22
+ * the version that pack's manifest declares, or nothing is installed at all
23
+ * (`packTagMatchesVersion`).
22
24
  *
23
25
  * ## Never on the hook path
24
26
  *
@@ -157,6 +159,14 @@ function validated(owner: string, repo: string, tag: string | null): PackSpec {
157
159
  * unauthenticated rate limit, and stays pointed at whatever
158
160
  * `FAILPROOFAI_PACK_BASE_URL` names — which is how a mirror, and the tests,
159
161
  * work at all.
162
+ *
163
+ * The price of that, and it is a real one: the redirect is issued only for a
164
+ * PUBLISHED, non-prerelease release. A repository whose newest release is a
165
+ * prerelease or a draft therefore either redirects to an OLDER stable tag —
166
+ * pinning something the publisher has already superseded — or issues no
167
+ * redirect at all. Only the second is detectable from here, so the error names
168
+ * the prerelease case explicitly; the first is why naming a tag is the answer
169
+ * whenever a publisher's newest release is not their newest stable one.
160
170
  */
161
171
  export async function resolveLatestTag(spec: PackSpec): Promise<string> {
162
172
  const url = `${baseUrl()}/${spec.owner}/${spec.repo}/releases/latest`;
@@ -168,7 +178,9 @@ export async function resolveLatestTag(spec: PackSpec): Promise<string> {
168
178
  if (!location) {
169
179
  throw new Error(
170
180
  `could not resolve the newest release of ${spec.owner}/${spec.repo} ` +
171
- `(GET ${url} returned ${response.status} with no redirect). Name a tag explicitly.`,
181
+ `(GET ${url} returned ${response.status} with no redirect). That redirect is issued only ` +
182
+ `for a published, non-prerelease release, so either the repository has no releases at all ` +
183
+ `or every release it has is a prerelease or a draft. Name a tag explicitly.`,
172
184
  );
173
185
  }
174
186
  const match = location.match(/\/releases\/tag\/(.+)$/);
@@ -193,6 +205,33 @@ export function packAssetUrl(spec: PinnedPackSpec, asset: string): string {
193
205
  return `${baseUrl()}/${spec.owner}/${spec.repo}/releases/download/${spec.tag}/${asset}`;
194
206
  }
195
207
 
208
+ /**
209
+ * Does a release tag describe the version the pack's own manifest declares?
210
+ *
211
+ * These are two independently-typed strings that everything downstream treats as
212
+ * one fact: the TAG builds every asset URL and is what `installed.json` records
213
+ * as the source, while the VERSION is read out of the manifest and is what
214
+ * `pack list` prints and `pack:<id>@<version>:<name>` keys are built from. Left
215
+ * uncompared, a pack tagged `v2` whose manifest still said `1.0.0` installed
216
+ * cleanly and recorded a version no release of that repository answers to.
217
+ *
218
+ * A leading `v` is accepted because both spellings are in live use for the same
219
+ * release — `pack build` tells publishers to tag `<version>` while this repo's
220
+ * own releases are tagged `v<version>` — and refusing that would break packs
221
+ * that are perfectly coherent.
222
+ *
223
+ * Compared on the tag's LAST `/`-delimited segment, so the monorepo shape
224
+ * `parsePackSpec` deliberately supports (`release/2.1`) still installs:
225
+ * `PACK_VERSION_RE` forbids `/`, so such a tag could never equal a version and a
226
+ * whole-string comparison would make the shape uninstallable rather than merely
227
+ * unusual. Everything else is a genuine disagreement — the release was tagged
228
+ * without rebuilding the manifest, or the wrong tag was typed.
229
+ */
230
+ export function packTagMatchesVersion(tag: string, version: string): boolean {
231
+ const tail = tag.slice(tag.lastIndexOf("/") + 1);
232
+ return tail === version || tail === `v${version}`;
233
+ }
234
+
196
235
  async function fetchBytes(url: string): Promise<Buffer> {
197
236
  const response = await fetch(url, {
198
237
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
@@ -277,6 +316,16 @@ interface FetchedPack {
277
316
  * and has to resolve it the same way — `core` worked in the terminal and failed
278
317
  * in the browser for exactly as long as this list sat in `pack-cli.ts`.
279
318
  */
319
+ /**
320
+ * Where our own policies actually live.
321
+ *
322
+ * They are a GitHub release like anybody else's, and the package carries no
323
+ * copy of them. That is the point: a pack that ships inside the binary is a
324
+ * policy set we chose for you and put on your disk before you asked, and it
325
+ * gives our own policies a delivery path nobody else's pack can use. One lane,
326
+ * the same for everyone — ours are just the pack whose short name we spell.
327
+ */
328
+ export const CORE_SOURCE = "FailproofAI/policies";
280
329
  export const CORE_ALIASES = new Set(["core", "failproofai", "official"]);
281
330
 
282
331
  export interface PackAddOptions {
@@ -307,18 +356,12 @@ export async function addPackFromSource(
307
356
  source: string,
308
357
  opts: PackAddOptions = {},
309
358
  ): Promise<AddedPack> {
310
- if (CORE_ALIASES.has(source.trim().toLowerCase())) {
311
- const result = installBundledPack(opts);
312
- if (!result.installed) throw new Error(result.reason ?? "could not install");
313
- return {
314
- id: result.id!,
315
- version: result.version!,
316
- enabled: result.enabled ?? result.available ?? [],
317
- available: result.available ?? [],
318
- bundled: true,
319
- };
320
- }
321
- const result = await addPack(source, opts);
359
+ // `core` is a spelling of CORE_SOURCE, not a second delivery path. Resolved
360
+ // HERE rather than in the CLI so the dashboard and the CLI cannot disagree
361
+ // about what the short name means — they did once, and a name the CLI could
362
+ // resolve failed in the browser.
363
+ const resolved = CORE_ALIASES.has(source.trim().toLowerCase()) ? CORE_SOURCE : source;
364
+ const result = await addPack(resolved, opts);
322
365
  return {
323
366
  id: result.id,
324
367
  version: result.version,
@@ -607,6 +650,27 @@ export async function addPack(
607
650
  : { ...parsed, tag: await resolveLatestTag(parsed) };
608
651
  const resolvedFromLatest = parsed.tag === null;
609
652
  const fetched = await fetchPack(spec);
653
+ // Checked here, before a byte is written and before the artifact is imported,
654
+ // so a refusal leaves the machine exactly as it was — and on the RESOLVED tag
655
+ // as well as a typed one, because a tagless add pins whatever
656
+ // `releases/latest` pointed at and lands the same incoherent pair in
657
+ // `installed.json` with nobody having typed it. Deliberately NOT in
658
+ // `fetchPackPreview`: looking at a pack has to stay possible precisely so a
659
+ // publisher can SEE the two values disagree.
660
+ if (!packTagMatchesVersion(spec.tag, fetched.version)) {
661
+ const fromTag = spec.tag.slice(spec.tag.lastIndexOf("/") + 1).replace(/^v/, "");
662
+ const fix =
663
+ `re-tag the release ${fetched.version} (a leading v is fine), or rebuild the pack with ` +
664
+ `--version ${fromTag}`;
665
+ throw new Error(
666
+ `${fetched.id} was not installed: release tag ${spec.tag} does not match the version its ` +
667
+ `manifest declares (${fetched.version}). ` +
668
+ (resolvedFromLatest
669
+ ? `That is the newest release of ${spec.owner}/${spec.repo}, so the release and the pack ` +
670
+ `disagree at the source — ask the publisher to ${fix}.`
671
+ : `Name the tag whose manifest says ${fetched.version}, or fix the pack: ${fix}.`),
672
+ );
673
+ }
610
674
  const available = fetched.policies.map((p) => p.name);
611
675
 
612
676
  const prior = priorRecordFor(fetched.id, fetched.artifactDigest);
@@ -686,25 +750,21 @@ export async function addPack(
686
750
  }
687
751
 
688
752
  /**
689
- * Install the pack that ships inside the npm package, from disk.
753
+ * The vendored pack directory, when a working tree happens to have one.
690
754
  *
691
- * This is what makes removing the builtins from the bundle survivable. The
692
- * tarball carries `policy-pack/` — the builtins as a real, digest-verified pack —
693
- * so a machine that has just installed failproofai already HAS them and setup
694
- * can enable them with no network at all. Without this, a fresh install with no
695
- * connectivity would be a machine enforcing nothing.
755
+ * The published package does NOT carry `policy-pack/` and there is no install
756
+ * path through here. Our policies are fetched from their GitHub release like
757
+ * anybody else's — a pack that ships inside the binary is a policy set chosen
758
+ * for the user and written to their disk before they asked, and it gave our own
759
+ * policies a delivery route no third-party pack could use.
760
+ *
761
+ * The one remaining caller is `audit/replay.ts`, which prefers the pack's own
762
+ * functions when a dev tree has run `build:pack` and falls back to the compiled
763
+ * implementations when it returns null. Both produce identical text, so the two
764
+ * paths score the same; the fallback is the normal case now.
696
765
  *
697
766
  * Anchored at `FAILPROOFAI_PACKAGE_ROOT` for the reason `npmPlatformBinaryPath`
698
767
  * documents: `import.meta.url` does not survive the CJS bundle.
699
- *
700
- * The bytes are COPIED into `packsDir()` rather than loaded where they lie. A
701
- * `sudo npm i -g` package directory is root-owned, and the loader writes its
702
- * rewritten module tree BESIDE the source it loads — so loading in place gives a
703
- * non-root hook EACCES, the pack never loads, and the hook exits 0. Copying is
704
- * what avoids that, and it is the same trap CHANGELOG #694 fixed for the shim.
705
- *
706
- * Idempotent, and never throws: a package without the directory returns null,
707
- * which is a normal state for a dev checkout that has not run `build:pack`.
708
768
  */
709
769
  export function bundledPackDir(): string | null {
710
770
  const root = process.env.FAILPROOFAI_PACKAGE_ROOT;
@@ -713,105 +773,6 @@ export function bundledPackDir(): string | null {
713
773
  return existsSync(resolve(dir, PACK_MANIFEST_ASSET)) ? dir : null;
714
774
  }
715
775
 
716
- export interface BundledPackResult {
717
- installed: boolean;
718
- id?: string;
719
- version?: string;
720
- enabled?: string[];
721
- available?: string[];
722
- /** Ids this install absorbed — the same pack, previously under another name. */
723
- replaced?: string[];
724
- reason?: string;
725
- }
726
-
727
- export function installBundledPack(opts?: { only?: string[]; categories?: string[]; all?: boolean }): BundledPackResult {
728
- const dir = bundledPackDir();
729
- if (!dir) return { installed: false, reason: "this build ships no bundled pack" };
730
-
731
- try {
732
- const checksums = readFileSync(resolve(dir, PACK_CHECKSUMS_ASSET), "utf8");
733
- const manifestBytes = readFileSync(resolve(dir, PACK_MANIFEST_ASSET));
734
- const artifact = readFileSync(resolve(dir, PACK_ENTRY_ASSET));
735
-
736
- // Verified even though it never crossed a network. The digest is what the
737
- // hook path re-checks before every import, so it has to describe the bytes
738
- // actually installed — and a tarball can be corrupted on disk like anything
739
- // else.
740
- const manifestDigest = digestFor(checksums, PACK_MANIFEST_ASSET);
741
- const entryDigest = digestFor(checksums, PACK_ENTRY_ASSET);
742
- const artifactDigest = sha256(artifact);
743
- if (!manifestDigest || sha256(manifestBytes) !== manifestDigest) {
744
- return { installed: false, reason: `${PACK_MANIFEST_ASSET} failed integrity verification` };
745
- }
746
- if (!entryDigest || artifactDigest !== entryDigest) {
747
- return { installed: false, reason: `${PACK_ENTRY_ASSET} failed integrity verification` };
748
- }
749
-
750
- const parsed = JSON.parse(manifestBytes.toString("utf8")) as {
751
- id?: unknown; version?: unknown; policies?: unknown; effect?: unknown;
752
- };
753
- if (!Array.isArray(parsed.policies)) {
754
- return { installed: false, reason: "bundled pack manifest is malformed" };
755
- }
756
- const identity = parsePackIdentity(parsed);
757
- // Same rules the loader applies, so a bundled pack that could never load
758
- // fails the install rather than looking fine until the next tool call.
759
- const policies = parsed.policies.map((pol, i) => parsePackPolicy(identity.id, pol, i));
760
-
761
- const root = packsRoot();
762
- const artifactRel = `artifacts/${artifactDigest}.mjs`;
763
- const artifactAbs = resolve(root, artifactRel);
764
- if (!existsSync(artifactAbs)) writeAtomic(artifactAbs, artifact);
765
-
766
- const prior = priorRecordFor(identity.id, artifactDigest);
767
- const available = policies.map((pol) => pol.name);
768
- const { enabled } = resolveSelection(
769
- policies,
770
- opts,
771
- prior?.enabled ? prior.enabled.filter((n) => available.includes(n)) : prior?.enabled,
772
- Boolean(prior),
773
- );
774
-
775
- const absorbed = upsertInstalled({
776
- id: identity.id,
777
- version: identity.version,
778
- // Recorded as `bundled:` rather than a github: source, because it did not
779
- // come from one — and `pack add` on this id would otherwise look like a
780
- // re-fetch of something that was never fetched.
781
- source: `bundled:${identity.id}@${identity.version}`,
782
- entry: artifactRel,
783
- sha256: artifactDigest,
784
- policies,
785
- ...(parsed.effect !== undefined ? { effect: identity.effect } : {}),
786
- ...(enabled ? { enabled } : {}),
787
- });
788
-
789
- return {
790
- installed: true,
791
- id: identity.id,
792
- version: identity.version,
793
- enabled: enabled ?? available,
794
- available,
795
- ...(absorbed.length > 0 ? { replaced: absorbed } : {}),
796
- };
797
- } catch (err) {
798
- return { installed: false, reason: errText(err) };
799
- }
800
- }
801
-
802
- /** Remove a pack from the activation pointer. Returns false if it was not installed. */
803
- /**
804
- * Turn ONE policy of an installed pack on or off.
805
- *
806
- * The selection in `installed.json` is the lever, not a `disabledCustomPolicies`
807
- * entry: those are keyed by `pack:<id>@<version>:<name>`, so an upgrade stops
808
- * matching them and silently switches back on everything the user had turned
809
- * off. The selection is version-stable and is carried forward by `pack add`.
810
- *
811
- * Enabling also clears any matching disabled key, or a policy switched off from
812
- * the dashboard could not be switched back on from the CLI — the two mechanisms
813
- * would disagree and the more obscure one would win.
814
- */
815
776
  export function setPackPolicyEnabled(
816
777
  packId: string,
817
778
  name: string,
package/src/hooks/tui.ts CHANGED
@@ -14,8 +14,8 @@
14
14
  * repaint) and, on resolve, collapses that region to a one-line summary that
15
15
  * stays on screen — so the next prompt simply appends below, building the log.
16
16
  * No external dependencies. Honors NO_COLOR and non-TTY (returns the default
17
- * without drawing), and uses 24-bit color where COLORTERM advertises it,
18
- * falling back to the nearest basic ANSI hue otherwise.
17
+ * without drawing), and paints at the deepest tier the terminal admits to —
18
+ * 24-bit, the xterm-256 cube, or the 16 basic ANSI hues.
19
19
  */
20
20
  import * as readline from "node:readline";
21
21
 
@@ -116,13 +116,32 @@ const FLOWER = "❋";
116
116
  // re-deriving their own copies.
117
117
  interface Hue {
118
118
  rgb: [number, number, number];
119
+ /**
120
+ * xterm-256 index for the middle tier, verified as the nearest cube entry by
121
+ * Euclidean distance rather than eyeballed.
122
+ *
123
+ * Optional because `dim` has no honest answer: its `basic` is SGR 2, an
124
+ * ATTRIBUTE that steps down whatever foreground the user's theme is already
125
+ * using, and the cube's nearest grey (243, #767676) is a fixed colour that
126
+ * fights every theme that is not ours. So dim keeps the attribute at all
127
+ * three tiers and this stays undefined.
128
+ */
129
+ c256?: number;
119
130
  basic: string;
120
131
  }
132
+ /**
133
+ * TWO accent hues and no third — the brand system states that as a rule, and
134
+ * this table used to break it: `pink` was #ff2e88, a hot pink that appears in
135
+ * no brand token, sitting beside `logoPink` #e4587d which was the real one. The
136
+ * mark and the prompts were therefore two different pinks, and neither surface
137
+ * could be recoloured without the other drifting. There is now one pink.
138
+ * Everything past the two accents is a state — amber for warn, an attribute for
139
+ * dim — never identity.
140
+ */
121
141
  const HUES = {
122
- guide: { rgb: [102, 209, 181], basic: "36" }, // teal — the policy flower / step spine
123
- pink: { rgb: [255, 46, 136], basic: "95" }, // hot pink — selection, enabled, the brand
124
- logoPink: { rgb: [228, 88, 124], basic: "95" }, // the softer artwork pink of the logomark
125
- warn: { rgb: [227, 179, 65], basic: "33" },
142
+ guide: { rgb: [102, 209, 181], c256: 79, basic: "36" }, // #66d1b5 mint — the policy flower / step spine
143
+ pink: { rgb: [228, 88, 125], c256: 168, basic: "95" }, // #e4587d — selection, enabled, the mark, the brand
144
+ warn: { rgb: [227, 179, 65], c256: 179, basic: "33" },
126
145
  dim: { rgb: [107, 118, 132], basic: "2" },
127
146
  } satisfies Record<string, Hue>;
128
147
 
@@ -137,32 +156,68 @@ export function colorsEnabled(out: TTYOut): boolean {
137
156
  * blue that appear nowhere in the brand — so `audit` looked like a different
138
157
  * product from `config`. Routing it here
139
158
  * keeps HUES the single source of truth: change a hue once and every surface
140
- * follows. Emits truecolor where the terminal advertises it, basic ANSI
141
- * otherwise; the caller still decides *whether* to colour at all.
159
+ * follows. Paints at the deepest tier the terminal admits to; the caller still
160
+ * decides *whether* to colour at all.
142
161
  */
143
162
  export function brandAnsi(role: keyof typeof HUES): string {
144
- const h = HUES[role];
145
- const code = truecolorEnabled() ? `38;2;${h.rgb.join(";")}` : h.basic;
146
- return `${ESC}[${code}m`;
163
+ return `${ESC}[${fg(HUES[role], colorTier())}m`;
147
164
  }
148
165
 
149
166
  export const ANSI_RESET = `${ESC}[0m`;
150
167
  export const ANSI_BOLD = `${ESC}[1m`;
151
168
  export const ANSI_DIM = `${ESC}[2m`;
152
- function truecolorEnabled(): boolean {
153
- return /truecolor|24bit/i.test(process.env.COLORTERM || "");
154
- }
155
169
 
156
- /** Brand painter: role-named color functions, truecolor where advertised,
157
- * basic-ANSI fallback otherwise, identity when `on` is false. */
170
+ /** How much colour this terminal will actually render. */
171
+ type ColorTier = "truecolor" | "ansi256" | "basic";
172
+
173
+ /**
174
+ * Three tiers, because the two-way gate skipped the one most terminals are in.
175
+ *
176
+ * COLORTERM-or-nothing sent every terminal that renders 256 colours but does
177
+ * not advertise 24-bit — tmux and screen, ssh into a stock xterm, most CI
178
+ * runners — all the way down to the 16 basic hues, where the brand pink lands
179
+ * on generic bright magenta and the mint on generic cyan. TERM naming its own
180
+ * depth is the signal those terminals do set, and it costs one regex.
181
+ *
182
+ * Deliberately no `FORCE_COLOR` / `-256color`-less allowlist: over-claiming a
183
+ * depth prints raw escape bytes into the user's scrollback, which is worse than
184
+ * an approximate hue. Under-claiming only costs fidelity.
185
+ */
186
+ function colorTier(): ColorTier {
187
+ if (/truecolor|24bit/i.test(process.env.COLORTERM || "")) return "truecolor";
188
+ if (/256color/i.test(process.env.TERM || "")) return "ansi256";
189
+ return "basic";
190
+ }
191
+
192
+ /** SGR foreground parameters for a hue at a tier. The ONE place a hue turns
193
+ * into bytes, so a new tier is added here and nowhere else. */
194
+ function fg(h: Hue, tier: ColorTier): string {
195
+ if (tier === "truecolor") return `38;2;${h.rgb[0]};${h.rgb[1]};${h.rgb[2]}`;
196
+ if (tier === "ansi256" && h.c256 !== undefined) return `38;5;${h.c256}`;
197
+ return h.basic;
198
+ }
199
+
200
+ /** The same as a background — only the logomark needs one, for a half-block
201
+ * cell whose two pixels are different hues. The current grid has no such cell
202
+ * (the flower and the cross never share a column), so this is here for the
203
+ * next grid edit, which the rules above LOGO_GRID actively invite. Never
204
+ * called at the basic tier: the mark draws monochrome there rather than
205
+ * approximate two brand hues with ANSI 5 and 6. */
206
+ function bg(h: Hue, tier: ColorTier): string {
207
+ return tier === "ansi256" && h.c256 !== undefined
208
+ ? `48;5;${h.c256}`
209
+ : `48;2;${h.rgb[0]};${h.rgb[1]};${h.rgb[2]}`;
210
+ }
211
+
212
+ /** Brand painter: role-named color functions at the terminal's best tier,
213
+ * identity when `on` is false. */
158
214
  export function paint(on: boolean) {
159
- const tc = on && truecolorEnabled();
215
+ const tier: ColorTier = on ? colorTier() : "basic";
160
216
  const mk =
161
217
  (h: Hue, bold = false) =>
162
218
  (s: string): string => {
163
219
  if (!on) return s;
164
- const code = tc ? `38;2;${h.rgb[0]};${h.rgb[1]};${h.rgb[2]}` : h.basic;
165
- return `${ESC}[${bold ? "1;" : ""}${code}m${s}${ESC}[0m`;
220
+ return `${ESC}[${bold ? "1;" : ""}${fg(h, tier)}m${s}${ESC}[0m`;
166
221
  };
167
222
  return {
168
223
  bold: (s: string) => (on ? `${ESC}[1m${s}${ESC}[0m` : s),
@@ -170,7 +225,11 @@ export function paint(on: boolean) {
170
225
  guide: mk(HUES.guide),
171
226
  pink: mk(HUES.pink),
172
227
  pinkBold: mk(HUES.pink, true),
173
- softPink: mk(HUES.logoPink),
228
+ // An ALIAS of `pink`, not a hue. The logomark's softer artwork tint
229
+ // collapsed into the one brand pink, so this name survives only for its
230
+ // single caller — install-prompt.ts's "beta" pill — and should be renamed
231
+ // to `pink` there, at which point it is deleted.
232
+ softPink: mk(HUES.pink),
174
233
  warn: mk(HUES.warn),
175
234
  };
176
235
  }
@@ -224,37 +283,40 @@ const LOGO_GRID = [
224
283
  "..ppppppppppp",
225
284
  "..ppppppppppp",
226
285
  ];
227
- // Derived from the shared HUES table so a palette tweak needs one edit.
228
- const LOGO_TEAL: [number, number, number] = HUES.guide.rgb;
229
- const LOGO_PINK: [number, number, number] = HUES.logoPink.rgb;
230
-
231
- /** Render the logomark as half-block art. When `colorize` is false (no truecolor
232
- * / NO_COLOR) the shape still prints, just monochrome. */
233
- function renderLogo(colorize: boolean): string[] {
286
+ // Derived from the shared HUES table so a palette tweak needs one edit. The
287
+ // mark is painted from the SAME two accents as the prompts — it used to carry
288
+ // its own pink, which is how the two drifted apart.
289
+ const LOGO_TEAL: Hue = HUES.guide;
290
+ const LOGO_PINK: Hue = HUES.pink;
291
+
292
+ /** Render the logomark as half-block art. At the `basic` tier (16 colours, or
293
+ * NO_COLOR) the shape still prints, just monochrome — approximating two brand
294
+ * hues with generic magenta and cyan reads as a different mark, and the shape
295
+ * alone already carries it. */
296
+ function renderLogo(tier: ColorTier): string[] {
234
297
  const pad = ".".repeat(LOGO_GRID[0]?.length ?? 0);
235
- const rgb = (ch: string): [number, number, number] | null =>
236
- ch === "t" ? LOGO_TEAL : ch === "p" ? LOGO_PINK : null;
298
+ const hue = (ch: string): Hue | null => (ch === "t" ? LOGO_TEAL : ch === "p" ? LOGO_PINK : null);
237
299
  const lines: string[] = [];
238
300
  for (let r = 0; r < LOGO_GRID.length; r += 2) {
239
301
  const top = LOGO_GRID[r];
240
302
  const bot = LOGO_GRID[r + 1] ?? pad;
241
303
  let line = "";
242
304
  for (let x = 0; x < top.length; x++) {
243
- const t = rgb(top[x]);
244
- const b = rgb(bot[x]);
305
+ const t = hue(top[x]);
306
+ const b = hue(bot[x]);
245
307
  if (!t && !b) {
246
308
  line += " ";
247
- } else if (!colorize) {
309
+ } else if (tier === "basic") {
248
310
  line += t && b ? "█" : t ? "▀" : "▄";
249
311
  } else if (t && b) {
250
312
  line +=
251
313
  t === b
252
- ? `${ESC}[38;2;${t.join(";")}m█${ESC}[0m`
253
- : `${ESC}[38;2;${t.join(";")};48;2;${b.join(";")}m▀${ESC}[0m`;
314
+ ? `${ESC}[${fg(t, tier)}m█${ESC}[0m`
315
+ : `${ESC}[${fg(t, tier)};${bg(b, tier)}m▀${ESC}[0m`;
254
316
  } else if (t) {
255
- line += `${ESC}[38;2;${t.join(";")}m▀${ESC}[0m`;
317
+ line += `${ESC}[${fg(t, tier)}m▀${ESC}[0m`;
256
318
  } else {
257
- line += `${ESC}[38;2;${b!.join(";")}m▄${ESC}[0m`;
319
+ line += `${ESC}[${fg(b!, tier)}m▄${ESC}[0m`;
258
320
  }
259
321
  }
260
322
  lines.push(line);
@@ -320,8 +382,10 @@ export function renderBrandLogo(stdout: TTYOut = process.stdout): string[] {
320
382
  if (cols < LOGO_MIN_COLS) {
321
383
  return [`${c.guide(FLOWER)} fa${c.pink("il")}proof ai ${c.dim("· " + TAGLINE)}`];
322
384
  }
323
- const tc = colorsEnabled(stdout) && truecolorEnabled();
324
- const lines = renderLogo(tc).map((l) => ` ${l}`);
385
+ // NO_COLOR / non-TTY forces `basic`, which renderLogo draws monochrome — so
386
+ // the mark never emits an escape byte on a stream that asked for none.
387
+ const tier: ColorTier = colorsEnabled(stdout) ? colorTier() : "basic";
388
+ const lines = renderLogo(tier).map((l) => ` ${l}`);
325
389
  lines.push("");
326
390
  lines.push(` fa${c.pink("il")}proof ai`);
327
391
  lines.push(` ${c.dim(TAGLINE)}`);
@@ -445,6 +509,24 @@ function nameWidth(labels: string[]): number {
445
509
  return Math.min(24, Math.max(6, ...labels.map((l) => l.length)));
446
510
  }
447
511
 
512
+ /**
513
+ * The hint budget for one row, after a label that outgrew its column.
514
+ *
515
+ * `nameWidth` caps the name column at 24 so that one long name cannot squeeze
516
+ * every description on screen — but `padEnd` pads, it does not TRUNCATE, so a
517
+ * longer name renders at its true width while the description was sized against
518
+ * the cap. The row then overruns the terminal by the difference and the
519
+ * description is cut by the terminal instead of by `ellipsize`, with no `…` to
520
+ * show it happened.
521
+ *
522
+ * Names are deliberately not truncated: a policy name is the thing you type
523
+ * next, and half of one is useless. The description gives up the space, because
524
+ * it is prose and shortening prose costs nothing.
525
+ */
526
+ function hintBudget(label: string, nameCol: number, budget: number): number {
527
+ return Math.max(6, budget - Math.max(0, label.length - nameCol));
528
+ }
529
+
448
530
  type DisplayRow = { kind: "header"; text: string } | { kind: "item"; index: number };
449
531
 
450
532
  /** Flatten choices into section-header + item display rows. */
@@ -651,7 +733,9 @@ export function selectOne<T>(opts: SelectOneOptions<T>): Promise<T | Back | null
651
733
  const dot = active ? c.pink(RADIO_ON) : c.dim(RADIO_OFF);
652
734
  const rawLabel = choice.label.padEnd(nameCol);
653
735
  const label = active ? c.pinkBold(rawLabel) : rawLabel;
654
- const hint = choice.hint ? ` ${c.dim(ellipsize(choice.hint, budget))}` : "";
736
+ const hint = choice.hint
737
+ ? ` ${c.dim(ellipsize(choice.hint, hintBudget(choice.label, nameCol, budget)))}`
738
+ : "";
655
739
  return `${dot} ${label}${hint}`;
656
740
  },
657
741
  allowBack: opts.allowBack,
@@ -709,7 +793,9 @@ export function multiSelect<T>(opts: MultiSelectOptions<T>): Promise<T[] | null
709
793
  : c.dim(CHECK_OFF);
710
794
  const rawLabel = choice.label.padEnd(nameCol);
711
795
  const label = active ? c.pinkBold(rawLabel) : checked[index] ? rawLabel : c.dim(rawLabel);
712
- const hint = choice.hint ? ` ${c.dim(ellipsize(choice.hint, budget))}` : "";
796
+ const hint = choice.hint
797
+ ? ` ${c.dim(ellipsize(choice.hint, hintBudget(choice.label, nameCol, budget)))}`
798
+ : "";
713
799
  return `${caret} ${box} ${label}${hint}`;
714
800
  },
715
801
  warnLine: () => (warn ? c.warn(`Select at least ${minSelected}.`) : null),
@@ -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"))},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"))},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"))},59043,(a,b,c)=>{b.exports=a.x("next/dist/server/runtime-reacts.external.js",()=>require("next/dist/server/runtime-reacts.external.js"))},77580,a=>{"use strict";var b=a.i(5050);let c=(0,b.createServerReference)("00b801c035726aaa9d297e34f35258369a37177149",b.callServer,void 0,b.findSourceMapURL,"getTelemetryConfig");a.s(["getTelemetryConfig",0,c])},3171,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(77580),e=a.i(66036);a.s(["default",0,function({error:a,reset:f}){return(0,c.useEffect)(()=>{(0,d.getTelemetryConfig)().then(b=>{(0,e.setClientTelemetryConfig)(b),(0,e.captureClientEvent)("client_error",{error_message:a.message,error_name:a.name,error_digest:a.digest,boundary:"global"})}).catch(()=>{})},[a]),(0,b.jsx)("html",{children:(0,b.jsx)("body",{children:(0,b.jsx)("main",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#031035",color:"#f8fafc",fontFamily:"system-ui, sans-serif"},children:(0,b.jsxs)("div",{style:{textAlign:"center",padding:"2rem",border:"1px solid rgba(239,68,68,0.4)",borderRadius:"0.5rem",maxWidth:"500px"},children:[(0,b.jsx)("h2",{style:{color:"#ef4444",marginBottom:"0.5rem",fontSize:"1.25rem"},children:"Something went wrong"}),(0,b.jsx)("p",{style:{color:"#94a3b8",marginBottom:"1.5rem"},children:a.message||"An unexpected error occurred."}),(0,b.jsx)("button",{onClick:f,style:{padding:"0.5rem 1.25rem",background:"#3b82f6",color:"white",border:"none",borderRadius:"0.375rem",cursor:"pointer",fontSize:"0.875rem"},children:"Try again"})]})})})})}])},66036,a=>{"use strict";a.s(["captureClientEvent",0,function(a,b){},"setClientTelemetryConfig",0,function(a){}])},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}},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)},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)},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)},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)},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},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},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React},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}})}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0zig5sv._.js.map
@@ -1,23 +0,0 @@
1
- module.exports=[77580,a=>{"use strict";var b=a.i(5050);let c=(0,b.createServerReference)("00b801c035726aaa9d297e34f35258369a37177149",b.callServer,void 0,b.findSourceMapURL,"getTelemetryConfig");a.s(["getTelemetryConfig",0,c])},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)}])},10765,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(77580),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}])},66036,a=>{"use strict";a.s(["captureClientEvent",0,function(a,b){},"setClientTelemetryConfig",0,function(a){}])},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}},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)},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)},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)},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)},14827,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={createLinkPrefetchPartialError:function(){return g},createUnrenderedSegmentError:function(){return f}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});function f(a,b){let c=`Route "${a}": Could not validate that a segment in your UI has instant navigation.`;if(b.length>0){let a=1===b.length?"Dropped segment":"Dropped segments";c+=`
2
-
3
- This segment was dropped from rendering. Issues that would prevent instant navigation will go undetected.
4
-
5
- ${a}:
6
- ${b.map(a=>` ${a}`).join("\n")}
7
-
8
- Ways to fix this:
9
- - [render] Render the dropped segment
10
- - [ignore] Set \`export const instant = false\` to opt the dropped segment out of instant-navigation validation
11
-
12
- Learn more: https://nextjs.org/docs/messages/instant-unrendered-segment`}return Object.defineProperty(Error(c),"__NEXT_ERROR_CODE",{value:"E1286",enumerable:!1,configurable:!0})}function g(a){return Object.defineProperty(Error(`Next.js encountered dynamic data during prefetching for "${a}".
13
-
14
- This will lead to slower, more expensive prefetches.
15
-
16
- Ways to fix this:
17
- - [upgrade] Opt into Partial Prefetching by exporting \`const prefetch = 'partial'\` from the page or layout, or by setting \`partialPrefetching: true\` in next.config to opt the whole app in
18
- - [disable] Remove \`prefetch={true}\` from the <Link> to use the default prefetch
19
- - [ignore] Set \`export const instant = false\` to opt the route out of instant-navigation validation
20
-
21
- Learn more: https://nextjs.org/docs/messages/instant-link-prefetch-partial`),"__NEXT_ERROR_CODE",{value:"E1435",enumerable:!1,configurable:!0})}},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),Object.defineProperty(this,"__NEXT_ERROR_CODE",{value:"E1179",enumerable:!1,configurable:!0}),this.name="InvariantError"}}},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}})},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}},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}})},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"}];
22
-
23
- //# sourceMappingURL=_00e9tnf._.js.map