@polishd/next 0.1.0 → 0.2.1-dev.0

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 (95) hide show
  1. package/AGENTS.md +161 -46
  2. package/CHANGELOG.md +163 -0
  3. package/README.md +275 -49
  4. package/bin/doctor.mjs +374 -0
  5. package/bin/init.mjs +215 -188
  6. package/bin/polishd.mjs +85 -0
  7. package/bin/shared.mjs +114 -0
  8. package/dist/ai/actions.d.ts +13 -2
  9. package/dist/ai/actions.d.ts.map +1 -1
  10. package/dist/ai/actions.js +19 -1
  11. package/dist/ai/actions.js.map +1 -1
  12. package/dist/ai/design.d.ts +28 -0
  13. package/dist/ai/design.d.ts.map +1 -0
  14. package/dist/ai/design.js +245 -0
  15. package/dist/ai/design.js.map +1 -0
  16. package/dist/ai/guard.d.ts +44 -3
  17. package/dist/ai/guard.d.ts.map +1 -1
  18. package/dist/ai/guard.js +13 -2
  19. package/dist/ai/guard.js.map +1 -1
  20. package/dist/ai/providers.d.ts +2 -0
  21. package/dist/ai/providers.d.ts.map +1 -1
  22. package/dist/ai/providers.js +70 -0
  23. package/dist/ai/providers.js.map +1 -1
  24. package/dist/ai/settings.d.ts +15 -1
  25. package/dist/ai/settings.d.ts.map +1 -1
  26. package/dist/ai/settings.js +38 -1
  27. package/dist/ai/settings.js.map +1 -1
  28. package/dist/ai/types.d.ts +57 -0
  29. package/dist/ai/types.d.ts.map +1 -1
  30. package/dist/client/design-scan.d.ts +37 -0
  31. package/dist/client/design-scan.d.ts.map +1 -0
  32. package/dist/client/design-scan.js +319 -0
  33. package/dist/client/design-scan.js.map +1 -0
  34. package/dist/client/init.d.ts.map +1 -1
  35. package/dist/client/init.js +67 -2
  36. package/dist/client/init.js.map +1 -1
  37. package/dist/config.d.ts +57 -3
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/config.js +62 -3
  40. package/dist/config.js.map +1 -1
  41. package/dist/dashboard/design-review-card.d.ts +15 -0
  42. package/dist/dashboard/design-review-card.d.ts.map +1 -0
  43. package/dist/dashboard/design-review-card.js +82 -0
  44. package/dist/dashboard/design-review-card.js.map +1 -0
  45. package/dist/dashboard/design.d.ts +10 -0
  46. package/dist/dashboard/design.d.ts.map +1 -0
  47. package/dist/dashboard/design.js +83 -0
  48. package/dist/dashboard/design.js.map +1 -0
  49. package/dist/dashboard/index.d.ts +35 -5
  50. package/dist/dashboard/index.d.ts.map +1 -1
  51. package/dist/dashboard/index.js +176 -18
  52. package/dist/dashboard/index.js.map +1 -1
  53. package/dist/dashboard/journeys.d.ts.map +1 -1
  54. package/dist/dashboard/journeys.js +1 -0
  55. package/dist/dashboard/journeys.js.map +1 -1
  56. package/dist/dashboard/summary.d.ts.map +1 -1
  57. package/dist/dashboard/summary.js +59 -5
  58. package/dist/dashboard/summary.js.map +1 -1
  59. package/dist/dashboard/token-auth.d.ts +56 -0
  60. package/dist/dashboard/token-auth.d.ts.map +1 -0
  61. package/dist/dashboard/token-auth.js +158 -0
  62. package/dist/dashboard/token-auth.js.map +1 -0
  63. package/dist/dashboard/unlock.d.ts +2 -0
  64. package/dist/dashboard/unlock.d.ts.map +1 -0
  65. package/dist/dashboard/unlock.js +54 -0
  66. package/dist/dashboard/unlock.js.map +1 -0
  67. package/dist/dashboard.css +2740 -0
  68. package/dist/proxy.d.ts +53 -5
  69. package/dist/proxy.d.ts.map +1 -1
  70. package/dist/proxy.js +73 -3
  71. package/dist/proxy.js.map +1 -1
  72. package/dist/route.d.ts.map +1 -1
  73. package/dist/route.js +11 -3
  74. package/dist/route.js.map +1 -1
  75. package/dist/server/design.d.ts +93 -0
  76. package/dist/server/design.d.ts.map +1 -0
  77. package/dist/server/design.js +430 -0
  78. package/dist/server/design.js.map +1 -0
  79. package/dist/server/ingest.d.ts +33 -2
  80. package/dist/server/ingest.d.ts.map +1 -1
  81. package/dist/server/ingest.js +70 -8
  82. package/dist/server/ingest.js.map +1 -1
  83. package/dist/server/queries.d.ts +16 -0
  84. package/dist/server/queries.d.ts.map +1 -1
  85. package/dist/server/queries.js +80 -16
  86. package/dist/server/queries.js.map +1 -1
  87. package/dist/session.d.ts.map +1 -1
  88. package/dist/session.js +4 -2
  89. package/dist/session.js.map +1 -1
  90. package/dist/shared/types.d.ts +31 -1
  91. package/dist/shared/types.d.ts.map +1 -1
  92. package/dist/shared/types.js +1 -0
  93. package/dist/shared/types.js.map +1 -1
  94. package/docs/SETUP.md +308 -51
  95. package/package.json +14 -7
@@ -1,7 +1,13 @@
1
- import { type SaveAISettingsInput } from "./settings";
2
- import type { PolishdAISettingsPublic, PolishdLossItem, CreateIssueResult, GenerateProfileResult, GenerateSummaryResult, VerifyGithubResult } from "./types";
1
+ import { type ListModelsInput, type SaveAISettingsInput } from "./settings";
2
+ import type { PolishdAISettingsPublic, PolishdLossItem, CreateIssueResult, GenerateDesignReviewResult, GenerateProfileResult, GenerateSummaryResult, ListModelsResult, VerifyGithubResult } from "./types";
3
3
  /** Generate or refresh the narrative. `force` re-asks the model even if data is unchanged. */
4
4
  export declare function generateSummaryAction(force?: boolean): Promise<GenerateSummaryResult>;
5
+ /**
6
+ * Generate or refresh the aesthetic design review (the Design tab). Uses the
7
+ * same configured provider/model as the summary. `force` re-asks the model
8
+ * even when the design metrics haven't changed.
9
+ */
10
+ export declare function generateDesignReviewAction(force?: boolean): Promise<GenerateDesignReviewResult>;
5
11
  /** Persist provider/model/key/instructions/context; returns the no-secret view. */
6
12
  export declare function saveAISettingsAction(input: SaveAISettingsInput): Promise<PolishdAISettingsPublic>;
7
13
  /**
@@ -9,6 +15,11 @@ export declare function saveAISettingsAction(input: SaveAISettingsInput): Promis
9
15
  * step. Passes current analytics so known component names steer the scan.
10
16
  */
11
17
  export declare function generateProfileAction(): Promise<GenerateProfileResult>;
18
+ /**
19
+ * List the models available to the given (or already-stored) key, so the
20
+ * dashboard can render a dropdown instead of a free-text model id.
21
+ */
22
+ export declare function listModelsAction(input: ListModelsInput): Promise<ListModelsResult>;
12
23
  /**
13
24
  * Check the saved GitHub repo + token live against the API — called by the
14
25
  * onboarding step right after saving, so a bad token fails at setup.
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,8FAA8F;AAC9F,wBAAsB,qBAAqB,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAGzF;AAED,mFAAmF;AACnF,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAGlC;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAI5E;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAGtE;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC,GAC7D,OAAO,CAAC,iBAAiB,CAAC,CAG5B"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAqBA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,8FAA8F;AAC9F,wBAAsB,qBAAqB,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAGzF;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,UAAQ,GACZ,OAAO,CAAC,0BAA0B,CAAC,CAGrC;AAED,mFAAmF;AACnF,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAGlC;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAI5E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGxF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAGtE;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC,GAC7D,OAAO,CAAC,iBAAiB,CAAC,CAG5B"}
@@ -13,17 +13,27 @@
13
13
  * re-runs that same callback against the caller's cookies on every call.
14
14
  */
15
15
  import { requirePolishdAuth } from "./guard";
16
+ import { generateDesignReview } from "./design";
16
17
  import { verifyGithubConnection } from "./github";
17
18
  import { createIssueFromLoss } from "./issues";
18
19
  import { generateProjectProfile } from "./profile";
19
20
  import { loadPolishdDashboardData } from "../server/queries";
20
- import { saveAISettings } from "./settings";
21
+ import { listModelsForProvider, saveAISettings, } from "./settings";
21
22
  import { generateSummary } from "./summary";
22
23
  /** Generate or refresh the narrative. `force` re-asks the model even if data is unchanged. */
23
24
  export async function generateSummaryAction(force = false) {
24
25
  await requirePolishdAuth();
25
26
  return generateSummary({ force });
26
27
  }
28
+ /**
29
+ * Generate or refresh the aesthetic design review (the Design tab). Uses the
30
+ * same configured provider/model as the summary. `force` re-asks the model
31
+ * even when the design metrics haven't changed.
32
+ */
33
+ export async function generateDesignReviewAction(force = false) {
34
+ await requirePolishdAuth();
35
+ return generateDesignReview({ force });
36
+ }
27
37
  /** Persist provider/model/key/instructions/context; returns the no-secret view. */
28
38
  export async function saveAISettingsAction(input) {
29
39
  await requirePolishdAuth();
@@ -38,6 +48,14 @@ export async function generateProfileAction() {
38
48
  const data = await loadPolishdDashboardData();
39
49
  return generateProjectProfile(data);
40
50
  }
51
+ /**
52
+ * List the models available to the given (or already-stored) key, so the
53
+ * dashboard can render a dropdown instead of a free-text model id.
54
+ */
55
+ export async function listModelsAction(input) {
56
+ await requirePolishdAuth();
57
+ return listModelsForProvider(input);
58
+ }
41
59
  /**
42
60
  * Check the saved GitHub repo + token live against the API — called by the
43
61
  * onboarding step right after saving, so a bad token fails at setup.
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAA4B,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAU5C,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAK,GAAG,KAAK;IACvD,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAA0B;IAE1B,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC9C,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAA8D;IAE9D,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,cAAc,GAGf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAY5C,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAK,GAAG,KAAK;IACvD,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,KAAK,GAAG,KAAK;IAEb,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,oBAAoB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAA0B;IAE1B,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC9C,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAsB;IAC3D,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAA8D;IAE9D,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type PolishdDesignData } from "../server/design";
2
+ import type { GenerateDesignReviewResult, PolishdDesignReview } from "./types";
3
+ /** The last generated review, or null. Read-only — never calls a model. */
4
+ export declare function loadDesignReview(): Promise<PolishdDesignReview | null>;
5
+ /**
6
+ * Render the aggregated design data as a terse, model-readable brief.
7
+ * Sections are omitted when empty so the prompt only carries real signal.
8
+ */
9
+ export declare function buildDesignDigest(data: PolishdDesignData, context?: string): string;
10
+ /**
11
+ * Generate (or reuse) the design review.
12
+ *
13
+ * @param force When false (default), a review whose fingerprint matches the
14
+ * current metrics is returned as-is — no model call. When true,
15
+ * always re-asks the model.
16
+ */
17
+ export declare function generateDesignReview(opts?: {
18
+ force?: boolean;
19
+ }): Promise<GenerateDesignReviewResult>;
20
+ /**
21
+ * For the Design tab's first render: the cached review plus whether the live
22
+ * metrics have drifted from it. Only reads the store; never calls a model.
23
+ */
24
+ export declare function loadDesignReviewState(preloaded?: PolishdDesignData): Promise<{
25
+ review: PolishdDesignReview | null;
26
+ stale: boolean;
27
+ }>;
28
+ //# sourceMappingURL=design.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/ai/design.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIzE,OAAO,KAAK,EACV,0BAA0B,EAE1B,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAIjB,2EAA2E;AAC3E,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAQ5E;AAsBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAmEnF;AAgED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,0BAA0B,CAAC,CAgErC;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAClF,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC,CASD"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Polishd — AI design review orchestration (server only).
3
+ *
4
+ * The Design tab's second layer. The first layer is deterministic
5
+ * (server/design.ts): measured typography, palette, radii, spacing, and
6
+ * rule-based flags. This module renders those metrics as a compact digest and
7
+ * asks the owner's configured model — the same provider, model, and key the
8
+ * analytics summary uses — for an aesthetic read: how coherent the design is,
9
+ * what works, and what specifically breaks the system.
10
+ *
11
+ * Token thrift mirrors summary.ts: the model sees aggregated tokens (a few
12
+ * hundred tokens for the whole site), never raw scans; the digest is
13
+ * fingerprinted and the review cached, so reopening the tab is free and a
14
+ * regenerate with unchanged metrics returns the cached text without a call.
15
+ */
16
+ import { getMeta, setMeta } from "../server/store";
17
+ import { getDesignData } from "../server/design";
18
+ import { fingerprintDigest } from "./digest";
19
+ import { callModel } from "./providers";
20
+ import { resolveSettings } from "./settings";
21
+ const DESIGN_REVIEW_KEY = "ai_design_review";
22
+ /** The last generated review, or null. Read-only — never calls a model. */
23
+ export async function loadDesignReview() {
24
+ const raw = await getMeta(DESIGN_REVIEW_KEY);
25
+ if (!raw)
26
+ return null;
27
+ try {
28
+ return JSON.parse(raw);
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ const SYSTEM_PROMPT = "You are a senior brand and product designer reviewing a shipped website. " +
35
+ "You receive design tokens reverse-engineered from the rendered pages — the " +
36
+ "typography, color palette, corner radii and spacing actually in use, plus " +
37
+ "deterministic findings from rule-based checks. You never see screenshots; " +
38
+ "judge coherence from the system the numbers describe.\n\n" +
39
+ "Respond with ONLY a JSON object (no markdown fences, no preamble):\n" +
40
+ '{ "assessment": string, "strengths": string[], "issues": [{ "issue": string, "evidence": string, "suggestion": string }] }\n\n' +
41
+ "assessment: one tight paragraph (3-5 sentences) on how coherent and " +
42
+ "tasteful the design system reads — does it feel like one deliberate brand, " +
43
+ "or an accumulation of one-off decisions? Name the strongest and weakest " +
44
+ "aspects. If the data covers too few pages to be confident, say so.\n" +
45
+ "strengths: 2-4 things the design gets right (a disciplined palette, a " +
46
+ "clear type hierarchy, consistent radii…).\n" +
47
+ "issues: 0-5 specific aesthetic problems, worst first. Each issue must be " +
48
+ "concrete, evidence must be an exact token copied verbatim from the metrics " +
49
+ "(a hex color, a px value, a page path), and suggestion must be an " +
50
+ "actionable fix (e.g. 'collapse 15px and 17px into the 16px body size'). " +
51
+ "Never invent an issue: if the system is genuinely coherent, return fewer.";
52
+ /**
53
+ * Render the aggregated design data as a terse, model-readable brief.
54
+ * Sections are omitted when empty so the prompt only carries real signal.
55
+ */
56
+ export function buildDesignDigest(data, context) {
57
+ const lines = [];
58
+ if (context && context.trim())
59
+ lines.push(`SITE: ${context.trim()}`);
60
+ lines.push(`SCANNED: ${data.pages.length} pages (${data.pages
61
+ .slice(0, 10)
62
+ .map((p) => p.path)
63
+ .join(", ")}${data.pages.length > 10 ? ", …" : ""}).`);
64
+ if (data.families.length) {
65
+ lines.push("FONT FAMILIES: " + data.families.map((f) => `${f.family} (${f.count} uses)`).join(", "));
66
+ }
67
+ if (data.fonts.length) {
68
+ lines.push("TYPE STYLES (family size/weight — uses, tags):");
69
+ for (const f of data.fonts.slice(0, 20)) {
70
+ lines.push(` - ${f.family} ${f.sizePx}px/${f.weight}: ${f.count} uses, ${f.pages.length} pages` +
71
+ `${f.tags.length ? ` (${f.tags.join(",")})` : ""}${f.outlier ? " [one-off]" : ""}`);
72
+ }
73
+ }
74
+ if (data.colors.length) {
75
+ lines.push("PALETTE (share of all color usage):");
76
+ for (const c of data.colors.slice(0, 20)) {
77
+ const roles = Object.entries(c.roles)
78
+ .filter(([, n]) => n > 0)
79
+ .map(([r]) => r)
80
+ .join("/");
81
+ lines.push(` - ${c.hex}: ${c.pct}% (${roles})${c.outlier ? " [one-off]" : ""}`);
82
+ }
83
+ }
84
+ const failing = data.contrast.filter((p) => !p.passes);
85
+ if (failing.length) {
86
+ lines.push("CONTRAST FAILURES (WCAG AA):");
87
+ for (const p of failing.slice(0, 6)) {
88
+ lines.push(` - ${p.fg} on ${p.bg}: ${p.ratio}:1 at ${p.minSizePx}px (needs ${p.required}:1)`);
89
+ }
90
+ }
91
+ if (data.radii.length) {
92
+ lines.push("CORNER RADII: " + data.radii.map((r) => `${r.value} ×${r.count}${r.outlier ? " [one-off]" : ""}`).join(", "));
93
+ }
94
+ if (data.spacing.length) {
95
+ lines.push("PADDING VALUES (px ×uses): " +
96
+ data.spacing
97
+ .slice(0, 18)
98
+ .map((s) => `${s.px} ×${s.count}${s.offGrid ? "*" : ""}`)
99
+ .join(", ") +
100
+ " (* = off the 4px grid)");
101
+ }
102
+ if (data.flags.length) {
103
+ lines.push("RULE-BASED FINDINGS:");
104
+ for (const f of data.flags)
105
+ lines.push(` - [${f.section}] ${f.message}`);
106
+ }
107
+ return lines.join("\n");
108
+ }
109
+ /** Parse the model's JSON, tolerating fences/prose; fall back to plain text. */
110
+ function parseStructured(text) {
111
+ let t = text.trim();
112
+ const fence = t.match(/```(?:json)?\s*([\s\S]*?)```/);
113
+ if (fence)
114
+ t = fence[1].trim();
115
+ const start = t.indexOf("{");
116
+ const end = t.lastIndexOf("}");
117
+ if (start >= 0 && end > start) {
118
+ try {
119
+ const obj = JSON.parse(t.slice(start, end + 1));
120
+ const assessment = typeof obj.assessment === "string" ? obj.assessment.trim() : "";
121
+ if (assessment) {
122
+ const strengths = Array.isArray(obj.strengths)
123
+ ? obj.strengths.filter((s) => typeof s === "string" && s.trim().length > 0).slice(0, 4)
124
+ : [];
125
+ const issues = Array.isArray(obj.issues) ? obj.issues.slice(0, 8) : [];
126
+ return { assessment, strengths, issues };
127
+ }
128
+ }
129
+ catch {
130
+ /* fall through */
131
+ }
132
+ }
133
+ return { assessment: text.trim(), strengths: [], issues: [] };
134
+ }
135
+ /**
136
+ * Hold issues to their evidence bar: the citation must literally appear in
137
+ * the digest we sent, so the model can't critique a color that isn't there.
138
+ */
139
+ function verifyIssues(raw, digest) {
140
+ const hay = digest.toLowerCase();
141
+ const out = [];
142
+ for (const r of raw) {
143
+ if (typeof r.issue !== "string" || !r.issue.trim())
144
+ continue;
145
+ const evidence = typeof r.evidence === "string" ? r.evidence.trim() : "";
146
+ if (!evidence)
147
+ continue;
148
+ const tokens = evidence
149
+ .toLowerCase()
150
+ .split(/[^\w#/.-]+/)
151
+ .filter((t) => t.length >= 3);
152
+ if (!tokens.length || !tokens.some((t) => hay.includes(t)))
153
+ continue;
154
+ out.push({
155
+ issue: r.issue.trim(),
156
+ evidence,
157
+ suggestion: typeof r.suggestion === "string" && r.suggestion.trim() ? r.suggestion.trim() : undefined,
158
+ });
159
+ if (out.length >= 5)
160
+ break;
161
+ }
162
+ return out;
163
+ }
164
+ /**
165
+ * Generate (or reuse) the design review.
166
+ *
167
+ * @param force When false (default), a review whose fingerprint matches the
168
+ * current metrics is returned as-is — no model call. When true,
169
+ * always re-asks the model.
170
+ */
171
+ export async function generateDesignReview(opts = {}) {
172
+ const { settings } = await resolveSettings();
173
+ if (!settings.apiKey) {
174
+ return { ok: false, error: "no-key", message: "No API key configured." };
175
+ }
176
+ const data = await getDesignData();
177
+ if (!data.ready || data.pages.length === 0) {
178
+ return {
179
+ ok: false,
180
+ error: "no-data",
181
+ message: "No pages scanned yet — browse the site, then refresh.",
182
+ };
183
+ }
184
+ const digest = buildDesignDigest(data, settings.context);
185
+ const fingerprint = fingerprintDigest(digest);
186
+ if (!opts.force) {
187
+ const cached = await loadDesignReview();
188
+ if (cached && cached.fingerprint === fingerprint) {
189
+ return { ok: true, review: cached, regenerated: false };
190
+ }
191
+ }
192
+ const system = settings.instructions
193
+ ? `${SYSTEM_PROMPT}\n\nAdditional instructions from the site owner: ${settings.instructions}`
194
+ : SYSTEM_PROMPT;
195
+ let reply;
196
+ try {
197
+ reply = await callModel(settings, system, digest);
198
+ }
199
+ catch (err) {
200
+ return {
201
+ ok: false,
202
+ error: "provider-error",
203
+ message: err instanceof Error ? err.message : "The model request failed.",
204
+ };
205
+ }
206
+ if (!reply.text) {
207
+ return { ok: false, error: "provider-error", message: "The model returned an empty response." };
208
+ }
209
+ if (reply.truncated) {
210
+ return {
211
+ ok: false,
212
+ error: "provider-error",
213
+ message: "The model's response was cut off at the output limit, twice. Try a model that reasons less, or regenerate.",
214
+ };
215
+ }
216
+ const parsed = parseStructured(reply.text);
217
+ const review = {
218
+ text: parsed.assessment,
219
+ strengths: parsed.strengths,
220
+ issues: verifyIssues(parsed.issues, digest),
221
+ provider: settings.provider,
222
+ model: settings.model,
223
+ generatedAt: Date.now(),
224
+ fingerprint,
225
+ usage: reply.usage,
226
+ };
227
+ await setMeta(DESIGN_REVIEW_KEY, JSON.stringify(review));
228
+ return { ok: true, review, regenerated: true };
229
+ }
230
+ /**
231
+ * For the Design tab's first render: the cached review plus whether the live
232
+ * metrics have drifted from it. Only reads the store; never calls a model.
233
+ */
234
+ export async function loadDesignReviewState(preloaded) {
235
+ const [review, data] = await Promise.all([
236
+ loadDesignReview(),
237
+ preloaded ? Promise.resolve(preloaded) : getDesignData(),
238
+ ]);
239
+ if (!data.ready || data.pages.length === 0)
240
+ return { review, stale: false };
241
+ const { settings } = await resolveSettings();
242
+ const fingerprint = fingerprintDigest(buildDesignDigest(data, settings.context));
243
+ return { review, stale: review !== null && review.fingerprint !== fingerprint };
244
+ }
245
+ //# sourceMappingURL=design.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/ai/design.ts"],"names":[],"mappings":"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"}
@@ -13,17 +13,58 @@
13
13
  * about the decision is trusted from the client.
14
14
  *
15
15
  * Fails closed: an action reached before any dashboard page has registered a
16
- * policy is denied.
16
+ * policy is denied. That includes an app which deletes `app/polishd/page.tsx`
17
+ * while keeping the package installed — the actions remain routable but now
18
+ * always deny, which is the right outcome and a confusing one to debug, so it
19
+ * is called out in the docs.
17
20
  */
21
+ import { cookies, headers } from "next/headers";
22
+ /**
23
+ * What an `authenticate` callback is handed.
24
+ *
25
+ * Without this a callback has to reach for `cookies()`/`headers()` itself,
26
+ * which couples it to Next's request-scoped storage and makes it awkward to
27
+ * unit test — you can only exercise it inside a request. Taking the request
28
+ * state as an argument instead makes the callback an ordinary function of its
29
+ * inputs, so a test can pass whatever it likes.
30
+ *
31
+ * Resolved once per check and shared between the page render and the action
32
+ * guard, so both see exactly the same request.
33
+ */
34
+ export interface PolishdAuthContext {
35
+ cookies: Awaited<ReturnType<typeof cookies>>;
36
+ headers: Awaited<ReturnType<typeof headers>>;
37
+ }
38
+ /**
39
+ * A host's access check. The context argument is optional in practice — a
40
+ * zero-argument callback is assignable here and keeps working unchanged.
41
+ */
42
+ export type PolishdAuthenticate = (ctx: PolishdAuthContext) => boolean | Promise<boolean>;
43
+ /** Build the context handed to `authenticate`. */
44
+ export declare function polishdAuthContext(): Promise<PolishdAuthContext>;
18
45
  export type PolishdAuthPolicy =
19
- /** `createPolishdPage()` with no `authenticate` — deliberately public. */
46
+ /** Deliberately public: dev, or an explicit `POLISHD_DASHBOARD_PUBLIC=true`. */
20
47
  {
21
48
  mode: "open";
22
49
  }
23
50
  /** `createPolishdPage({ authenticate })` — re-checked per action call. */
24
51
  | {
25
52
  mode: "guarded";
26
- authenticate: () => boolean | Promise<boolean>;
53
+ authenticate: PolishdAuthenticate;
54
+ }
55
+ /**
56
+ * Production with no access decision made by the host at all. Denied like a
57
+ * failed check rather than waved through.
58
+ *
59
+ * This mode has to exist at the *policy* level, not just as a screen the page
60
+ * renders. The actions are independently addressable and re-check the policy
61
+ * themselves, so a page that renders a lockout while still registering
62
+ * `open` would leave every action — including the AI settings write, which
63
+ * redirects the model base URL and spends the owner's key — wide open behind
64
+ * a locked-looking door.
65
+ */
66
+ | {
67
+ mode: "setup-required";
27
68
  };
28
69
  /** Record the dashboard's access policy. Called by `createPolishdPage()`. */
29
70
  export declare function registerPolishdAuth(next: PolishdAuthPolicy): void;
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/ai/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,iBAAiB;AAC3B,0EAA0E;AACxE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,0EAA0E;GACxE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC;AAIxE,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAEjE;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;;CAKlD;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBxD"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/ai/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,kBAAkB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1F,kDAAkD;AAClD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAGtE;AAED,MAAM,MAAM,iBAAiB;AAC3B,gFAAgF;AAC9E;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,0EAA0E;GACxE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,mBAAmB,CAAA;CAAE;AACxD;;;;;;;;;;GAUG;GACD;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAI/B,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAEjE;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;;CAKlD;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBxD"}
package/dist/ai/guard.js CHANGED
@@ -13,8 +13,17 @@
13
13
  * about the decision is trusted from the client.
14
14
  *
15
15
  * Fails closed: an action reached before any dashboard page has registered a
16
- * policy is denied.
16
+ * policy is denied. That includes an app which deletes `app/polishd/page.tsx`
17
+ * while keeping the package installed — the actions remain routable but now
18
+ * always deny, which is the right outcome and a confusing one to debug, so it
19
+ * is called out in the docs.
17
20
  */
21
+ import { cookies, headers } from "next/headers";
22
+ /** Build the context handed to `authenticate`. */
23
+ export async function polishdAuthContext() {
24
+ const [c, h] = await Promise.all([cookies(), headers()]);
25
+ return { cookies: c, headers: h };
26
+ }
18
27
  let policy = null;
19
28
  /** Record the dashboard's access policy. Called by `createPolishdPage()`. */
20
29
  export function registerPolishdAuth(next) {
@@ -41,11 +50,13 @@ export async function requirePolishdAuth() {
41
50
  // dashboard produces.
42
51
  if (!policy)
43
52
  throw new PolishdUnauthorizedError();
53
+ if (policy.mode === "setup-required")
54
+ throw new PolishdUnauthorizedError();
44
55
  if (policy.mode === "open")
45
56
  return;
46
57
  let ok = false;
47
58
  try {
48
- ok = await policy.authenticate();
59
+ ok = await policy.authenticate(await polishdAuthContext());
49
60
  }
50
61
  catch (err) {
51
62
  console.warn("[polishd] authenticate() threw during an action call, denying:", err instanceof Error ? err.message : err);
@@ -1 +1 @@
1
- {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/ai/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,IAAI,MAAM,GAA6B,IAAI,CAAC;AAE5C,6EAA6E;AAC7E,MAAM,UAAU,mBAAmB,CAAC,IAAuB;IACzD,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD;QACE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,0EAA0E;IAC1E,6EAA6E;IAC7E,sBAAsB;IACtB,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO;IAEnC,IAAI,EAAE,GAAG,KAAK,CAAC;IACf,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,gEAAgE,EAChE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;QACF,EAAE,GAAG,KAAK,CAAC;IACb,CAAC;IACD,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/ai/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAyBhD,kDAAkD;AAClD,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACzD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AACpC,CAAC;AAoBD,IAAI,MAAM,GAA6B,IAAI,CAAC;AAE5C,6EAA6E;AAC7E,MAAM,UAAU,mBAAmB,CAAC,IAAuB;IACzD,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD;QACE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,0EAA0E;IAC1E,6EAA6E;IAC7E,sBAAsB;IACtB,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB;QAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;IAC3E,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO;IAEnC,IAAI,EAAE,GAAG,KAAK,CAAC;IACf,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,kBAAkB,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,gEAAgE,EAChE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;QACF,EAAE,GAAG,KAAK,CAAC;IACb,CAAC;IACD,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;AAChD,CAAC"}
@@ -26,6 +26,8 @@ export interface CallOptions {
26
26
  /** Output token cap for this call. */
27
27
  maxTokens?: number;
28
28
  }
29
+ /** List model ids available to `settings.apiKey` for its provider. Throws `ProviderError` on failure. */
30
+ export declare function listModels(settings: PolishdAISettings): Promise<string[]>;
29
31
  /**
30
32
  * Dispatch to the configured provider. Throws on transport / API errors with a
31
33
  * message safe to surface (no key material), which the caller turns into a
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED,yEAAyE;AACzE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAM3D,CAAC;AAWF,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsKD;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,iBAAiB,EAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,CAQrB"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED,yEAAyE;AACzE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAM3D,CAAC;AAWF,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwND,yGAAyG;AACzG,wBAAsB,UAAU,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAY/E;AAqBD;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,iBAAiB,EAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,CAQrB"}
@@ -44,6 +44,26 @@ async function postJson(url, headers, body) {
44
44
  function num(v) {
45
45
  return typeof v === "number" && Number.isFinite(v) ? v : undefined;
46
46
  }
47
+ async function getJson(url, headers) {
48
+ let res;
49
+ try {
50
+ res = await fetch(url, { method: "GET", headers });
51
+ }
52
+ catch (err) {
53
+ throw new ProviderError(`network error contacting model provider: ${err instanceof Error ? err.message : String(err)}`);
54
+ }
55
+ const raw = await res.text();
56
+ if (!res.ok) {
57
+ const detail = raw.slice(0, 300).replace(/\s+/g, " ").trim();
58
+ throw new ProviderError(`provider returned ${res.status}: ${detail}`);
59
+ }
60
+ try {
61
+ return JSON.parse(raw);
62
+ }
63
+ catch {
64
+ throw new ProviderError("provider returned a non-JSON response");
65
+ }
66
+ }
47
67
  // ── Anthropic Messages API ───────────────────────────────────────────────────
48
68
  async function callAnthropic(s, system, user, maxTokens) {
49
69
  const data = (await postJson("https://api.anthropic.com/v1/messages", { "x-api-key": s.apiKey, "anthropic-version": "2023-06-01" }, {
@@ -108,6 +128,56 @@ async function callGoogle(s, system, user, maxTokens) {
108
128
  },
109
129
  };
110
130
  }
131
+ // ── Model listing ─────────────────────────────────────────────────────────────
132
+ // Lets the dashboard offer a dropdown instead of a free-text model id, using
133
+ // whichever key the owner already entered. Best-effort: any provider that
134
+ // doesn't support (or rejects) this call still works fine as a text field.
135
+ async function listAnthropicModels(s) {
136
+ const data = (await getJson("https://api.anthropic.com/v1/models?limit=1000", {
137
+ "x-api-key": s.apiKey,
138
+ "anthropic-version": "2023-06-01",
139
+ }));
140
+ return (data.data ?? [])
141
+ .map((m) => m.id)
142
+ .filter((id) => !!id)
143
+ .sort();
144
+ }
145
+ async function listOpenAIModels(s) {
146
+ const base = s.baseUrl?.replace(/\/$/, "") || "https://api.openai.com/v1";
147
+ const data = (await getJson(`${base}/models`, {
148
+ authorization: `Bearer ${s.apiKey}`,
149
+ }));
150
+ const ids = (data.data ?? []).map((m) => m.id).filter((id) => !!id);
151
+ // The endpoint also lists embeddings/whisper/tts/moderation models — this
152
+ // package only ever sends chat completions, so prefer chat-shaped ids when
153
+ // we can tell the difference. Falls back to the full list otherwise (e.g.
154
+ // OpenAI-compatible proxies whose ids don't follow this convention).
155
+ const chatLike = ids.filter((id) => /^(gpt-|o[1-9]|chatgpt)/i.test(id) &&
156
+ !/embedding|whisper|tts|audio|moderation|dall-e/i.test(id));
157
+ return (chatLike.length > 0 ? chatLike : ids).sort();
158
+ }
159
+ async function listGoogleModels(s) {
160
+ const data = (await getJson(`https://generativelanguage.googleapis.com/v1beta/models?pageSize=1000&key=${encodeURIComponent(s.apiKey)}`, {}));
161
+ return (data.models ?? [])
162
+ .filter((m) => m.supportedGenerationMethods?.includes("generateContent"))
163
+ .map((m) => (m.name ?? "").replace(/^models\//, ""))
164
+ .filter(Boolean)
165
+ .sort();
166
+ }
167
+ /** List model ids available to `settings.apiKey` for its provider. Throws `ProviderError` on failure. */
168
+ export async function listModels(settings) {
169
+ switch (settings.provider) {
170
+ case "anthropic":
171
+ return listAnthropicModels(settings);
172
+ case "openai":
173
+ case "openai-compatible":
174
+ return listOpenAIModels(settings);
175
+ case "google":
176
+ return listGoogleModels(settings);
177
+ default:
178
+ throw new ProviderError(`unknown provider: ${settings.provider}`);
179
+ }
180
+ }
111
181
  function dispatch(settings, system, user, maxTokens) {
112
182
  switch (settings.provider) {
113
183
  case "anthropic":
@@ -1 +1 @@
1
- {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"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"}