@polishd/next 0.1.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.
- package/AGENTS.md +262 -0
- package/DATABASE.md +147 -0
- package/LICENSE +21 -0
- package/README.md +310 -0
- package/bin/init.mjs +224 -0
- package/dist/ai/actions.d.ts +23 -0
- package/dist/ai/actions.d.ts.map +1 -0
- package/dist/ai/actions.js +58 -0
- package/dist/ai/actions.js.map +1 -0
- package/dist/ai/digest.d.ts +9 -0
- package/dist/ai/digest.d.ts.map +1 -0
- package/dist/ai/digest.js +108 -0
- package/dist/ai/digest.js.map +1 -0
- package/dist/ai/github.d.ts +51 -0
- package/dist/ai/github.d.ts.map +1 -0
- package/dist/ai/github.js +175 -0
- package/dist/ai/github.js.map +1 -0
- package/dist/ai/guard.d.ts +43 -0
- package/dist/ai/guard.d.ts.map +1 -0
- package/dist/ai/guard.js +57 -0
- package/dist/ai/guard.js.map +1 -0
- package/dist/ai/issues.d.ts +21 -0
- package/dist/ai/issues.d.ts.map +1 -0
- package/dist/ai/issues.js +291 -0
- package/dist/ai/issues.js.map +1 -0
- package/dist/ai/profile.d.ts +26 -0
- package/dist/ai/profile.d.ts.map +1 -0
- package/dist/ai/profile.js +160 -0
- package/dist/ai/profile.js.map +1 -0
- package/dist/ai/providers.d.ts +40 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +142 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/ai/scan.d.ts +38 -0
- package/dist/ai/scan.d.ts.map +1 -0
- package/dist/ai/scan.js +274 -0
- package/dist/ai/scan.js.map +1 -0
- package/dist/ai/settings.d.ts +31 -0
- package/dist/ai/settings.d.ts.map +1 -0
- package/dist/ai/settings.js +182 -0
- package/dist/ai/settings.js.map +1 -0
- package/dist/ai/summary.d.ts +26 -0
- package/dist/ai/summary.d.ts.map +1 -0
- package/dist/ai/summary.js +260 -0
- package/dist/ai/summary.js.map +1 -0
- package/dist/ai/types.d.ts +188 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +13 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/client/init.d.ts +14 -0
- package/dist/client/init.d.ts.map +1 -0
- package/dist/client/init.js +274 -0
- package/dist/client/init.js.map +1 -0
- package/dist/client/monitor.d.ts +23 -0
- package/dist/client/monitor.d.ts.map +1 -0
- package/dist/client/monitor.js +176 -0
- package/dist/client/monitor.js.map +1 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +10 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +26 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/elements.d.ts +6 -0
- package/dist/dashboard/elements.d.ts.map +1 -0
- package/dist/dashboard/elements.js +35 -0
- package/dist/dashboard/elements.js.map +1 -0
- package/dist/dashboard/features.d.ts +6 -0
- package/dist/dashboard/features.d.ts.map +1 -0
- package/dist/dashboard/features.js +28 -0
- package/dist/dashboard/features.js.map +1 -0
- package/dist/dashboard/index.d.ts +54 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +140 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/journeys.d.ts +5 -0
- package/dist/dashboard/journeys.d.ts.map +1 -0
- package/dist/dashboard/journeys.js +158 -0
- package/dist/dashboard/journeys.js.map +1 -0
- package/dist/dashboard/pages.d.ts +5 -0
- package/dist/dashboard/pages.d.ts.map +1 -0
- package/dist/dashboard/pages.js +104 -0
- package/dist/dashboard/pages.js.map +1 -0
- package/dist/dashboard/summary.d.ts +13 -0
- package/dist/dashboard/summary.d.ts.map +1 -0
- package/dist/dashboard/summary.js +333 -0
- package/dist/dashboard/summary.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +40 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +29 -0
- package/dist/proxy.js.map +1 -0
- package/dist/route.d.ts +24 -0
- package/dist/route.d.ts.map +1 -0
- package/dist/route.js +37 -0
- package/dist/route.js.map +1 -0
- package/dist/server/ingest.d.ts +14 -0
- package/dist/server/ingest.d.ts.map +1 -0
- package/dist/server/ingest.js +73 -0
- package/dist/server/ingest.js.map +1 -0
- package/dist/server/queries.d.ts +245 -0
- package/dist/server/queries.d.ts.map +1 -0
- package/dist/server/queries.js +547 -0
- package/dist/server/queries.js.map +1 -0
- package/dist/server/store.d.ts +29 -0
- package/dist/server/store.d.ts.map +1 -0
- package/dist/server/store.js +359 -0
- package/dist/server/store.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +15 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +16 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +29 -0
- package/dist/session.js.map +1 -0
- package/dist/shared/types.d.ts +56 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +27 -0
- package/dist/shared/types.js.map +1 -0
- package/docs/SETUP.md +315 -0
- package/package.json +92 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polishd — AI settings resolution (server only).
|
|
3
|
+
*
|
|
4
|
+
* One place that decides "which model, with which key, and what the owner told
|
|
5
|
+
* us about the site". Saved dashboard settings win over `POLISHD_AI_*` env
|
|
6
|
+
* defaults. Lives in its own module so both the summary and the project-profile
|
|
7
|
+
* orchestrators can share it without importing each other.
|
|
8
|
+
*
|
|
9
|
+
* The API key never leaves the server: `getAISettingsPublic` maps it to a
|
|
10
|
+
* boolean before anything reaches the client.
|
|
11
|
+
*/
|
|
12
|
+
import { getMeta, setMeta } from "../server/store";
|
|
13
|
+
import { DEFAULT_MODEL } from "./providers";
|
|
14
|
+
const SETTINGS_KEY = "ai_settings";
|
|
15
|
+
const VALID_PROVIDERS = [
|
|
16
|
+
"anthropic",
|
|
17
|
+
"openai",
|
|
18
|
+
"openai-compatible",
|
|
19
|
+
"google",
|
|
20
|
+
];
|
|
21
|
+
function coerceProvider(v) {
|
|
22
|
+
return typeof v === "string" && VALID_PROVIDERS.includes(v)
|
|
23
|
+
? v
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
const VALID_CADENCES = ["manual", "daily", "weekly"];
|
|
27
|
+
function coerceCadence(v) {
|
|
28
|
+
return typeof v === "string" && VALID_CADENCES.includes(v)
|
|
29
|
+
? v
|
|
30
|
+
: undefined;
|
|
31
|
+
}
|
|
32
|
+
async function readSaved() {
|
|
33
|
+
const raw = await getMeta(SETTINGS_KEY);
|
|
34
|
+
if (!raw)
|
|
35
|
+
return {};
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(raw);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Non-secret env defaults — handy for CI / shared deploys.
|
|
45
|
+
*
|
|
46
|
+
* Each key is read as `POLISHD_*` first, then the pre-rename `BUFFD_*` name, so
|
|
47
|
+
* deployments configured before the rename keep working without anyone having
|
|
48
|
+
* to touch their host's environment settings.
|
|
49
|
+
*/
|
|
50
|
+
function envSettings() {
|
|
51
|
+
const e = process.env;
|
|
52
|
+
/** POLISHD_<name>, falling back to the legacy BUFFD_<name>. */
|
|
53
|
+
const read = (name) => e[`POLISHD_${name}`] || e[`BUFFD_${name}`];
|
|
54
|
+
const out = {};
|
|
55
|
+
const provider = coerceProvider(read("AI_PROVIDER"));
|
|
56
|
+
if (provider)
|
|
57
|
+
out.provider = provider;
|
|
58
|
+
const cadence = coerceCadence(read("AI_REFRESH_CADENCE"));
|
|
59
|
+
if (cadence)
|
|
60
|
+
out.refreshCadence = cadence;
|
|
61
|
+
const model = read("AI_MODEL");
|
|
62
|
+
if (model)
|
|
63
|
+
out.model = model;
|
|
64
|
+
const apiKey = read("AI_API_KEY");
|
|
65
|
+
if (apiKey)
|
|
66
|
+
out.apiKey = apiKey;
|
|
67
|
+
const baseUrl = read("AI_BASE_URL");
|
|
68
|
+
if (baseUrl)
|
|
69
|
+
out.baseUrl = baseUrl;
|
|
70
|
+
const instructions = read("AI_INSTRUCTIONS");
|
|
71
|
+
if (instructions)
|
|
72
|
+
out.instructions = instructions;
|
|
73
|
+
const context = read("AI_CONTEXT");
|
|
74
|
+
if (context)
|
|
75
|
+
out.context = context;
|
|
76
|
+
const audience = read("AI_AUDIENCE");
|
|
77
|
+
if (audience)
|
|
78
|
+
out.audience = audience;
|
|
79
|
+
const ideology = read("AI_IDEOLOGY");
|
|
80
|
+
if (ideology)
|
|
81
|
+
out.ideology = ideology;
|
|
82
|
+
const sourceDirs = read("AI_SOURCE_DIRS");
|
|
83
|
+
if (sourceDirs)
|
|
84
|
+
out.sourceDirs = sourceDirs;
|
|
85
|
+
const githubRepo = read("GITHUB_REPO");
|
|
86
|
+
if (githubRepo)
|
|
87
|
+
out.githubRepo = githubRepo;
|
|
88
|
+
const githubToken = read("GITHUB_TOKEN");
|
|
89
|
+
if (githubToken)
|
|
90
|
+
out.githubToken = githubToken;
|
|
91
|
+
const autoIssues = read("GITHUB_AUTO_ISSUES");
|
|
92
|
+
if (autoIssues)
|
|
93
|
+
out.githubAutoIssues = /^(1|true|yes)$/i.test(autoIssues);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Effective settings = saved (dashboard) over env defaults. Returns the full
|
|
98
|
+
* settings (with key) for server use, plus whether the *provider config* came
|
|
99
|
+
* purely from env (so the UI can show it as a read-only default).
|
|
100
|
+
*/
|
|
101
|
+
export async function resolveSettings() {
|
|
102
|
+
const env = envSettings();
|
|
103
|
+
const saved = await readSaved();
|
|
104
|
+
const merged = { ...env, ...saved };
|
|
105
|
+
const provider = merged.provider ?? "anthropic";
|
|
106
|
+
return {
|
|
107
|
+
settings: {
|
|
108
|
+
provider,
|
|
109
|
+
model: merged.model || DEFAULT_MODEL[provider],
|
|
110
|
+
apiKey: merged.apiKey ?? "",
|
|
111
|
+
baseUrl: merged.baseUrl,
|
|
112
|
+
instructions: merged.instructions,
|
|
113
|
+
context: merged.context,
|
|
114
|
+
audience: merged.audience,
|
|
115
|
+
ideology: merged.ideology,
|
|
116
|
+
sourceDirs: merged.sourceDirs,
|
|
117
|
+
refreshCadence: merged.refreshCadence ?? "manual",
|
|
118
|
+
githubRepo: merged.githubRepo,
|
|
119
|
+
githubToken: merged.githubToken,
|
|
120
|
+
githubAutoIssues: merged.githubAutoIssues ?? false,
|
|
121
|
+
},
|
|
122
|
+
fromEnv: Object.keys(saved).length === 0 && Object.keys(env).length > 0,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Public (no-secret) settings for the dashboard. */
|
|
126
|
+
export async function getAISettingsPublic() {
|
|
127
|
+
const { settings, fromEnv } = await resolveSettings();
|
|
128
|
+
return {
|
|
129
|
+
provider: settings.provider,
|
|
130
|
+
model: settings.model,
|
|
131
|
+
hasApiKey: settings.apiKey.length > 0,
|
|
132
|
+
baseUrl: settings.baseUrl,
|
|
133
|
+
instructions: settings.instructions,
|
|
134
|
+
context: settings.context,
|
|
135
|
+
audience: settings.audience,
|
|
136
|
+
ideology: settings.ideology,
|
|
137
|
+
sourceDirs: settings.sourceDirs,
|
|
138
|
+
refreshCadence: settings.refreshCadence,
|
|
139
|
+
githubRepo: settings.githubRepo,
|
|
140
|
+
hasGithubToken: (settings.githubToken ?? "").length > 0,
|
|
141
|
+
githubAutoIssues: settings.githubAutoIssues,
|
|
142
|
+
fromEnv,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** Persist owner settings. Returns the refreshed public view. */
|
|
146
|
+
export async function saveAISettings(input) {
|
|
147
|
+
const prev = await readSaved();
|
|
148
|
+
const next = { ...prev };
|
|
149
|
+
const provider = coerceProvider(input.provider);
|
|
150
|
+
if (provider)
|
|
151
|
+
next.provider = provider;
|
|
152
|
+
if (input.model !== undefined)
|
|
153
|
+
next.model = input.model.trim();
|
|
154
|
+
// Empty apiKey = "keep what's stored"; a non-empty value replaces it.
|
|
155
|
+
if (input.apiKey)
|
|
156
|
+
next.apiKey = input.apiKey.trim();
|
|
157
|
+
if (input.baseUrl !== undefined)
|
|
158
|
+
next.baseUrl = input.baseUrl.trim() || undefined;
|
|
159
|
+
if (input.instructions !== undefined)
|
|
160
|
+
next.instructions = input.instructions.trim() || undefined;
|
|
161
|
+
if (input.context !== undefined)
|
|
162
|
+
next.context = input.context.trim() || undefined;
|
|
163
|
+
if (input.audience !== undefined)
|
|
164
|
+
next.audience = input.audience.trim() || undefined;
|
|
165
|
+
if (input.ideology !== undefined)
|
|
166
|
+
next.ideology = input.ideology.trim() || undefined;
|
|
167
|
+
if (input.sourceDirs !== undefined)
|
|
168
|
+
next.sourceDirs = input.sourceDirs.trim() || undefined;
|
|
169
|
+
const cadence = coerceCadence(input.refreshCadence);
|
|
170
|
+
if (cadence)
|
|
171
|
+
next.refreshCadence = cadence;
|
|
172
|
+
if (input.githubRepo !== undefined)
|
|
173
|
+
next.githubRepo = input.githubRepo.trim() || undefined;
|
|
174
|
+
// Like apiKey: blank keeps the stored token, a value replaces it.
|
|
175
|
+
if (input.githubToken)
|
|
176
|
+
next.githubToken = input.githubToken.trim();
|
|
177
|
+
if (input.githubAutoIssues !== undefined)
|
|
178
|
+
next.githubAutoIssues = input.githubAutoIssues === true;
|
|
179
|
+
await setMeta(SETTINGS_KEY, JSON.stringify(next));
|
|
180
|
+
return getAISettingsPublic();
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/ai/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type PolishdDashboardData } from "../server/queries";
|
|
2
|
+
import type { PolishdSummary, GenerateSummaryResult } from "./types";
|
|
3
|
+
export { getAISettingsPublic, saveAISettings, type SaveAISettingsInput, } from "./settings";
|
|
4
|
+
/** The last generated summary, or null. Read-only — never calls a model. */
|
|
5
|
+
export declare function loadSummary(): Promise<PolishdSummary | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Generate (or reuse) the narrative summary.
|
|
8
|
+
*
|
|
9
|
+
* @param force When false (default), a summary whose fingerprint matches the
|
|
10
|
+
* current data is returned as-is — no model call, no tokens spent.
|
|
11
|
+
* When true, always re-asks the model.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateSummary(opts?: {
|
|
14
|
+
force?: boolean;
|
|
15
|
+
}): Promise<GenerateSummaryResult>;
|
|
16
|
+
/**
|
|
17
|
+
* For the dashboard's first render: the cached summary plus whether the live
|
|
18
|
+
* data has drifted from it (so the UI can show a "new data — regenerate" hint).
|
|
19
|
+
* Computing this only reads the store; it never calls a model.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadSummaryState(preloaded?: PolishdDashboardData): Promise<{
|
|
22
|
+
summary: PolishdSummary | null;
|
|
23
|
+
stale: boolean;
|
|
24
|
+
currentFingerprint: string | null;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/ai/summary.ts"],"names":[],"mappings":"AAmBA,OAAO,EAA4B,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAOxF,OAAO,KAAK,EAGV,cAAc,EACd,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,YAAY,CAAC;AAIpB,4EAA4E;AAC5E,wBAAsB,WAAW,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQlE;AA2ID;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,qBAAqB,CAAC,CAgFhC;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,CAAC,EAAE,oBAAoB,GAC/B,OAAO,CAAC;IACT,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC,CAAC,CAuBD"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polishd — AI summary orchestration (server only).
|
|
3
|
+
*
|
|
4
|
+
* Ties the pieces together: resolve the owner's model settings, build a compact
|
|
5
|
+
* digest of the analytics, fold in the cached project profile, and — only when
|
|
6
|
+
* needed — ask the model for a one-paragraph story of how the site is used.
|
|
7
|
+
*
|
|
8
|
+
* Token thrift, in order of impact:
|
|
9
|
+
* 1. We send a pre-aggregated digest, never raw events.
|
|
10
|
+
* 2. Code understanding comes from the cached project profile (see
|
|
11
|
+
* profile.ts), generated once — the summary call never re-reads source.
|
|
12
|
+
* Only when analytics mention a component the profile doesn't cover do we
|
|
13
|
+
* do a tiny targeted read of the files naming it.
|
|
14
|
+
* 3. We fingerprint the inputs (digest + profile) and cache the summary. A
|
|
15
|
+
* regenerate with no new data returns the cached text for free
|
|
16
|
+
* (`regenerated: false`).
|
|
17
|
+
* 4. The system prompt is tight and the output is capped to a paragraph.
|
|
18
|
+
*/
|
|
19
|
+
import { getMeta, setMeta } from "../server/store";
|
|
20
|
+
import { loadPolishdDashboardData } from "../server/queries";
|
|
21
|
+
import { buildDigest, fingerprintDigest } from "./digest";
|
|
22
|
+
import { attachGithubIssues } from "./issues";
|
|
23
|
+
import { callModel } from "./providers";
|
|
24
|
+
import { coverageGaps, loadProjectProfile } from "./profile";
|
|
25
|
+
import { collectTargeted, findInSource } from "./scan";
|
|
26
|
+
import { resolveSettings } from "./settings";
|
|
27
|
+
// Settings live in ./settings; re-exported here so existing imports keep working.
|
|
28
|
+
export { getAISettingsPublic, saveAISettings, } from "./settings";
|
|
29
|
+
const SUMMARY_KEY = "ai_summary";
|
|
30
|
+
/** The last generated summary, or null. Read-only — never calls a model. */
|
|
31
|
+
export async function loadSummary() {
|
|
32
|
+
const raw = await getMeta(SUMMARY_KEY);
|
|
33
|
+
if (!raw)
|
|
34
|
+
return null;
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const SYSTEM_PROMPT = "You are a product analyst embedded in a website's analytics dashboard. " +
|
|
43
|
+
"You receive a compact digest of real user-behavior signals (clicks, rage " +
|
|
44
|
+
"clicks, dead clicks, scroll depth, errors, per-page and per-element stats), " +
|
|
45
|
+
"usually preceded by a project profile describing the site's purpose, pages, " +
|
|
46
|
+
"and components — treat the profile as authoritative context for what every " +
|
|
47
|
+
"identifier means.\n\n" +
|
|
48
|
+
"Respond with ONLY a JSON object (no markdown fences, no preamble):\n" +
|
|
49
|
+
'{ "story": string, "wins": string[], "losses": [{ "issue": string, "evidence": string }] }\n\n' +
|
|
50
|
+
"story: a single tight paragraph (3-5 sentences) telling the site owner how " +
|
|
51
|
+
"people are actually using their site — what's working best and what's " +
|
|
52
|
+
"frustrating or broken. Name specific pages and elements, in the site's own " +
|
|
53
|
+
"terms from the profile. Lead with the strongest finding. If the data is too " +
|
|
54
|
+
"sparse to be confident, say so plainly.\n" +
|
|
55
|
+
"wins: 2-4 things that are working. These may be general observations.\n" +
|
|
56
|
+
"losses: 0-4 real, specific problems visible in the data — a broken or " +
|
|
57
|
+
"frustrating element, an underperforming page, a recurring error. Each issue " +
|
|
58
|
+
"must be concrete (what is wrong, where, and what the numbers show), and " +
|
|
59
|
+
"evidence must be the exact page path, CSS selector, or component name " +
|
|
60
|
+
"copied verbatim from the digest that demonstrates it. Never invent a loss: " +
|
|
61
|
+
"if the data shows no real problems, return an empty array.";
|
|
62
|
+
/**
|
|
63
|
+
* Parse the model's JSON reply, tolerating stray fences or prose around it.
|
|
64
|
+
* Falls back to treating the whole text as the story so a model that ignores
|
|
65
|
+
* the format still produces a usable card.
|
|
66
|
+
*/
|
|
67
|
+
function parseStructured(text) {
|
|
68
|
+
let t = text.trim();
|
|
69
|
+
const fence = t.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
70
|
+
if (fence)
|
|
71
|
+
t = fence[1].trim();
|
|
72
|
+
const start = t.indexOf("{");
|
|
73
|
+
const end = t.lastIndexOf("}");
|
|
74
|
+
if (start >= 0 && end > start) {
|
|
75
|
+
try {
|
|
76
|
+
const obj = JSON.parse(t.slice(start, end + 1));
|
|
77
|
+
const story = typeof obj.story === "string" ? obj.story.trim() : "";
|
|
78
|
+
if (story) {
|
|
79
|
+
const wins = Array.isArray(obj.wins)
|
|
80
|
+
? obj.wins.filter((w) => typeof w === "string" && w.trim().length > 0).slice(0, 4)
|
|
81
|
+
: [];
|
|
82
|
+
const losses = Array.isArray(obj.losses) ? obj.losses.slice(0, 6) : [];
|
|
83
|
+
return { story, wins, losses };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
/* fall through to plain-text handling */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { story: text.trim(), wins: [], losses: [] };
|
|
91
|
+
}
|
|
92
|
+
/** Tokens specific enough to ground a citation (drop generic words). */
|
|
93
|
+
function citationTokens(s) {
|
|
94
|
+
return s
|
|
95
|
+
.toLowerCase()
|
|
96
|
+
.split(/[^\w/-]+/)
|
|
97
|
+
.filter((t) => t.length >= 4 && !/^(button|input|click|clicks|page|pages|http|https|with|from|that)$/.test(t));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Hold losses to their evidence bar. A loss survives only if its citation
|
|
101
|
+
* actually appears in the prompt we sent (so it can't be invented), and is
|
|
102
|
+
* then matched to a source file when the codebase is on disk.
|
|
103
|
+
*/
|
|
104
|
+
function verifyLosses(raw, promptText, sourceDirs) {
|
|
105
|
+
const hay = promptText.toLowerCase();
|
|
106
|
+
const out = [];
|
|
107
|
+
for (const l of raw) {
|
|
108
|
+
if (typeof l.issue !== "string" || !l.issue.trim())
|
|
109
|
+
continue;
|
|
110
|
+
const evidence = typeof l.evidence === "string" ? l.evidence.trim() : "";
|
|
111
|
+
if (!evidence)
|
|
112
|
+
continue; // no citation, no loss
|
|
113
|
+
const tokens = citationTokens(evidence);
|
|
114
|
+
if (!tokens.length || !tokens.some((t) => hay.includes(t)))
|
|
115
|
+
continue; // not in the data we sent
|
|
116
|
+
const location = findInSource(tokens, sourceDirs);
|
|
117
|
+
out.push({
|
|
118
|
+
issue: l.issue.trim(),
|
|
119
|
+
evidence,
|
|
120
|
+
location: location ?? undefined,
|
|
121
|
+
verified: location !== null,
|
|
122
|
+
});
|
|
123
|
+
if (out.length >= 4)
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The exact user message for a summary call, plus its cache fingerprint.
|
|
130
|
+
* Fingerprint covers the digest AND the profile, so a re-scan (new profile)
|
|
131
|
+
* marks the cached summary stale too.
|
|
132
|
+
*/
|
|
133
|
+
function composePrompt(data, profile, context, sourceDirs) {
|
|
134
|
+
const digest = buildDigest(data, context);
|
|
135
|
+
const sections = [];
|
|
136
|
+
if (profile) {
|
|
137
|
+
sections.push(`PROJECT PROFILE (authoritative — what this site and its components are):\n${profile.text}`);
|
|
138
|
+
// The "only touch source again when something isn't covered" path: a tiny
|
|
139
|
+
// targeted read for identifiers the profile doesn't know about.
|
|
140
|
+
const gaps = coverageGaps(data, profile);
|
|
141
|
+
if (gaps.length) {
|
|
142
|
+
const excerpts = collectTargeted(gaps, sourceDirs);
|
|
143
|
+
if (excerpts.length) {
|
|
144
|
+
sections.push("NEW COMPONENTS NOT IN THE PROFILE (source excerpts):\n" +
|
|
145
|
+
excerpts.map((f) => `--- ${f.path} ---\n${f.content}`).join("\n\n"));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
sections.push(`COMPONENTS NOT COVERED BY THE PROFILE (no source found): ${gaps.join(", ")}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
sections.push(digest);
|
|
153
|
+
const user = sections.join("\n\n");
|
|
154
|
+
return {
|
|
155
|
+
user,
|
|
156
|
+
fingerprint: fingerprintDigest(profile ? `${digest}\nPROFILE:${profile.fingerprint}` : digest),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Generate (or reuse) the narrative summary.
|
|
161
|
+
*
|
|
162
|
+
* @param force When false (default), a summary whose fingerprint matches the
|
|
163
|
+
* current data is returned as-is — no model call, no tokens spent.
|
|
164
|
+
* When true, always re-asks the model.
|
|
165
|
+
*/
|
|
166
|
+
export async function generateSummary(opts = {}) {
|
|
167
|
+
const { settings } = await resolveSettings();
|
|
168
|
+
if (!settings.apiKey) {
|
|
169
|
+
return { ok: false, error: "no-key", message: "No API key configured." };
|
|
170
|
+
}
|
|
171
|
+
const data = await loadPolishdDashboardData();
|
|
172
|
+
if (!data.overview.ready || data.overview.totalEvents === 0) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
error: "no-data",
|
|
176
|
+
message: "No analytics captured yet — browse the site, then generate.",
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const profile = await loadProjectProfile();
|
|
180
|
+
const { user, fingerprint } = composePrompt(data, profile, settings.context, settings.sourceDirs);
|
|
181
|
+
if (!opts.force) {
|
|
182
|
+
const cached = await loadSummary();
|
|
183
|
+
if (cached && cached.fingerprint === fingerprint) {
|
|
184
|
+
return { ok: true, summary: cached, regenerated: false };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const system = settings.instructions
|
|
188
|
+
? `${SYSTEM_PROMPT}\n\nAdditional instructions from the site owner: ${settings.instructions}`
|
|
189
|
+
: SYSTEM_PROMPT;
|
|
190
|
+
let reply;
|
|
191
|
+
try {
|
|
192
|
+
reply = await callModel(settings, system, user);
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
error: "provider-error",
|
|
198
|
+
message: err instanceof Error ? err.message : "The model request failed.",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (!reply.text) {
|
|
202
|
+
return {
|
|
203
|
+
ok: false,
|
|
204
|
+
error: "provider-error",
|
|
205
|
+
message: "The model returned an empty response.",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
if (reply.truncated) {
|
|
209
|
+
// Even the retry hit the cap — don't cache a mid-sentence stump.
|
|
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
|
+
// Link losses to their GitHub issues — filing new ones when the owner
|
|
218
|
+
// enabled auto-filing, attaching already-filed ones either way.
|
|
219
|
+
const losses = await attachGithubIssues(verifyLosses(parsed.losses, user, settings.sourceDirs));
|
|
220
|
+
const summary = {
|
|
221
|
+
text: parsed.story,
|
|
222
|
+
wins: parsed.wins,
|
|
223
|
+
losses,
|
|
224
|
+
provider: settings.provider,
|
|
225
|
+
model: settings.model,
|
|
226
|
+
generatedAt: Date.now(),
|
|
227
|
+
fingerprint,
|
|
228
|
+
usage: reply.usage,
|
|
229
|
+
};
|
|
230
|
+
await setMeta(SUMMARY_KEY, JSON.stringify(summary));
|
|
231
|
+
return { ok: true, summary, regenerated: true };
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* For the dashboard's first render: the cached summary plus whether the live
|
|
235
|
+
* data has drifted from it (so the UI can show a "new data — regenerate" hint).
|
|
236
|
+
* Computing this only reads the store; it never calls a model.
|
|
237
|
+
*/
|
|
238
|
+
export async function loadSummaryState(preloaded) {
|
|
239
|
+
const [summary, data] = await Promise.all([
|
|
240
|
+
loadSummary(),
|
|
241
|
+
preloaded ? Promise.resolve(preloaded) : loadPolishdDashboardData(),
|
|
242
|
+
]);
|
|
243
|
+
if (!data.overview.ready || data.overview.totalEvents === 0) {
|
|
244
|
+
return { summary, stale: false, currentFingerprint: null };
|
|
245
|
+
}
|
|
246
|
+
const [{ settings }, profile] = await Promise.all([
|
|
247
|
+
resolveSettings(),
|
|
248
|
+
loadProjectProfile(),
|
|
249
|
+
]);
|
|
250
|
+
// Staleness only needs the fingerprint — skip the targeted source read by
|
|
251
|
+
// computing it the same way composePrompt does, without collecting excerpts.
|
|
252
|
+
const digest = buildDigest(data, settings.context);
|
|
253
|
+
const currentFingerprint = fingerprintDigest(profile ? `${digest}\nPROFILE:${profile.fingerprint}` : digest);
|
|
254
|
+
return {
|
|
255
|
+
summary,
|
|
256
|
+
stale: summary !== null && summary.fingerprint !== currentFingerprint,
|
|
257
|
+
currentFingerprint,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/ai/summary.ts"],"names":[],"mappings":"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"}
|