quackscore 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.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +158 -0
  3. package/dist/commands/create.d.ts +6 -0
  4. package/dist/commands/create.d.ts.map +1 -0
  5. package/dist/commands/create.js +165 -0
  6. package/dist/commands/create.js.map +1 -0
  7. package/dist/commands/init.d.ts +8 -0
  8. package/dist/commands/init.d.ts.map +1 -0
  9. package/dist/commands/init.js +62 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/leaderboard.d.ts +2 -0
  12. package/dist/commands/leaderboard.d.ts.map +1 -0
  13. package/dist/commands/leaderboard.js +36 -0
  14. package/dist/commands/leaderboard.js.map +1 -0
  15. package/dist/commands/mock-report.d.ts +4 -0
  16. package/dist/commands/mock-report.d.ts.map +1 -0
  17. package/dist/commands/mock-report.js +311 -0
  18. package/dist/commands/mock-report.js.map +1 -0
  19. package/dist/commands/show.d.ts +2 -0
  20. package/dist/commands/show.d.ts.map +1 -0
  21. package/dist/commands/show.js +17 -0
  22. package/dist/commands/show.js.map +1 -0
  23. package/dist/commands/update.d.ts +3 -0
  24. package/dist/commands/update.d.ts.map +1 -0
  25. package/dist/commands/update.js +175 -0
  26. package/dist/commands/update.js.map +1 -0
  27. package/dist/config/index.d.ts +4 -0
  28. package/dist/config/index.d.ts.map +1 -0
  29. package/dist/config/index.js +3 -0
  30. package/dist/config/index.js.map +1 -0
  31. package/dist/config/manager.d.ts +7 -0
  32. package/dist/config/manager.d.ts.map +1 -0
  33. package/dist/config/manager.js +29 -0
  34. package/dist/config/manager.js.map +1 -0
  35. package/dist/config/types.d.ts +14 -0
  36. package/dist/config/types.d.ts.map +1 -0
  37. package/dist/config/types.js +21 -0
  38. package/dist/config/types.js.map +1 -0
  39. package/dist/github/client.d.ts +8 -0
  40. package/dist/github/client.d.ts.map +1 -0
  41. package/dist/github/client.js +241 -0
  42. package/dist/github/client.js.map +1 -0
  43. package/dist/github/index.d.ts +3 -0
  44. package/dist/github/index.d.ts.map +1 -0
  45. package/dist/github/index.js +2 -0
  46. package/dist/github/index.js.map +1 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +93 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/llm/analyzer.d.ts +7 -0
  52. package/dist/llm/analyzer.d.ts.map +1 -0
  53. package/dist/llm/analyzer.js +249 -0
  54. package/dist/llm/analyzer.js.map +1 -0
  55. package/dist/llm/character.d.ts +16 -0
  56. package/dist/llm/character.d.ts.map +1 -0
  57. package/dist/llm/character.js +245 -0
  58. package/dist/llm/character.js.map +1 -0
  59. package/dist/llm/client.d.ts +5 -0
  60. package/dist/llm/client.d.ts.map +1 -0
  61. package/dist/llm/client.js +98 -0
  62. package/dist/llm/client.js.map +1 -0
  63. package/dist/llm/index.d.ts +4 -0
  64. package/dist/llm/index.d.ts.map +1 -0
  65. package/dist/llm/index.js +4 -0
  66. package/dist/llm/index.js.map +1 -0
  67. package/dist/llm/prompts.d.ts +4 -0
  68. package/dist/llm/prompts.d.ts.map +1 -0
  69. package/dist/llm/prompts.js +109 -0
  70. package/dist/llm/prompts.js.map +1 -0
  71. package/dist/llm/providers.d.ts +10 -0
  72. package/dist/llm/providers.d.ts.map +1 -0
  73. package/dist/llm/providers.js +70 -0
  74. package/dist/llm/providers.js.map +1 -0
  75. package/dist/report/generate.d.ts +3 -0
  76. package/dist/report/generate.d.ts.map +1 -0
  77. package/dist/report/generate.js +1540 -0
  78. package/dist/report/generate.js.map +1 -0
  79. package/dist/report/index.d.ts +2 -0
  80. package/dist/report/index.d.ts.map +1 -0
  81. package/dist/report/index.js +2 -0
  82. package/dist/report/index.js.map +1 -0
  83. package/dist/scoring/index.d.ts +3 -0
  84. package/dist/scoring/index.d.ts.map +1 -0
  85. package/dist/scoring/index.js +3 -0
  86. package/dist/scoring/index.js.map +1 -0
  87. package/dist/scoring/points.d.ts +8 -0
  88. package/dist/scoring/points.d.ts.map +1 -0
  89. package/dist/scoring/points.js +28 -0
  90. package/dist/scoring/points.js.map +1 -0
  91. package/dist/scoring/stats.d.ts +3 -0
  92. package/dist/scoring/stats.d.ts.map +1 -0
  93. package/dist/scoring/stats.js +80 -0
  94. package/dist/scoring/stats.js.map +1 -0
  95. package/dist/shared/diagnostics.d.ts +8 -0
  96. package/dist/shared/diagnostics.d.ts.map +1 -0
  97. package/dist/shared/diagnostics.js +99 -0
  98. package/dist/shared/diagnostics.js.map +1 -0
  99. package/dist/shared/pr-summary.d.ts +5 -0
  100. package/dist/shared/pr-summary.d.ts.map +1 -0
  101. package/dist/shared/pr-summary.js +272 -0
  102. package/dist/shared/pr-summary.js.map +1 -0
  103. package/dist/shared/profile-summary.d.ts +5 -0
  104. package/dist/shared/profile-summary.d.ts.map +1 -0
  105. package/dist/shared/profile-summary.js +262 -0
  106. package/dist/shared/profile-summary.js.map +1 -0
  107. package/dist/shared/technologies.d.ts +5 -0
  108. package/dist/shared/technologies.d.ts.map +1 -0
  109. package/dist/shared/technologies.js +211 -0
  110. package/dist/shared/technologies.js.map +1 -0
  111. package/dist/shared/types.d.ts +61 -0
  112. package/dist/shared/types.d.ts.map +1 -0
  113. package/dist/shared/types.js +14 -0
  114. package/dist/shared/types.js.map +1 -0
  115. package/dist/shared/ui.d.ts +7 -0
  116. package/dist/shared/ui.d.ts.map +1 -0
  117. package/dist/shared/ui.js +24 -0
  118. package/dist/shared/ui.js.map +1 -0
  119. package/dist/storage/index.d.ts +4 -0
  120. package/dist/storage/index.d.ts.map +1 -0
  121. package/dist/storage/index.js +4 -0
  122. package/dist/storage/index.js.map +1 -0
  123. package/dist/storage/leaderboard.d.ts +4 -0
  124. package/dist/storage/leaderboard.d.ts.map +1 -0
  125. package/dist/storage/leaderboard.js +37 -0
  126. package/dist/storage/leaderboard.js.map +1 -0
  127. package/dist/storage/paths.d.ts +6 -0
  128. package/dist/storage/paths.d.ts.map +1 -0
  129. package/dist/storage/paths.js +19 -0
  130. package/dist/storage/paths.js.map +1 -0
  131. package/dist/storage/report.d.ts +3 -0
  132. package/dist/storage/report.d.ts.map +1 -0
  133. package/dist/storage/report.js +21 -0
  134. package/dist/storage/report.js.map +1 -0
  135. package/dist/storage/user.d.ts +4 -0
  136. package/dist/storage/user.d.ts.map +1 -0
  137. package/dist/storage/user.js +44 -0
  138. package/dist/storage/user.js.map +1 -0
  139. package/package.json +52 -0
@@ -0,0 +1,249 @@
1
+ import { z } from 'zod';
2
+ import { callLLM, extractJSON } from './client.js';
3
+ import { buildPRPrompt } from './prompts.js';
4
+ import { AREA_TAXONOMY, CONTRIBUTION_TYPE_TAXONOMY, } from '../shared/types.js';
5
+ import { diagError, diagLog } from '../shared/diagnostics.js';
6
+ import { normalizeTechnologies } from '../shared/technologies.js';
7
+ import { buildFallbackPRSummary, extractChangedFiles, getLowValuePRSummaryReason } from '../shared/pr-summary.js';
8
+ export { getLowValuePRSummaryReason } from '../shared/pr-summary.js';
9
+ const PRAnalysisSchema = z.object({
10
+ skipped: z.boolean(),
11
+ skipReason: z.string().nullish(),
12
+ complexity: z.number().int().min(1).max(10),
13
+ areas: z.array(z.string()),
14
+ types: z.array(z.string()),
15
+ technologies: z.array(z.string()),
16
+ summary: z.string().max(200),
17
+ });
18
+ const AREA_SET = new Set(AREA_TAXONOMY);
19
+ const CONTRIBUTION_TYPE_SET = new Set(CONTRIBUTION_TYPE_TAXONOMY);
20
+ const AREA_ALIASES = {
21
+ frontend: 'web_frontend',
22
+ web: 'web_frontend',
23
+ ui: 'web_frontend',
24
+ accessibility: 'web_frontend',
25
+ mobile: 'mobile_frontend',
26
+ api: 'backend',
27
+ server: 'backend',
28
+ services: 'backend',
29
+ testing: 'qa',
30
+ test: 'qa',
31
+ tests: 'qa',
32
+ ci_cd: 'devops',
33
+ cicd: 'devops',
34
+ infra: 'devops',
35
+ infrastructure: 'devops',
36
+ pipeline: 'devops',
37
+ pipelines: 'devops',
38
+ deployment: 'devops',
39
+ deployments: 'devops',
40
+ ops: 'sre',
41
+ observability: 'sre',
42
+ reliability: 'sre',
43
+ llm: 'ai',
44
+ ml: 'ai',
45
+ };
46
+ const CONTRIBUTION_TYPE_ALIASES = {
47
+ feature: 'new_development',
48
+ features: 'new_development',
49
+ enhancement: 'new_development',
50
+ enhancements: 'new_development',
51
+ new_feature: 'new_development',
52
+ development: 'new_development',
53
+ fix: 'bugfix',
54
+ fixes: 'bugfix',
55
+ bug: 'bugfix',
56
+ hotfix: 'bugfix',
57
+ cleanup: 'refactor',
58
+ refactoring: 'refactor',
59
+ docs: 'documentation',
60
+ doc: 'documentation',
61
+ };
62
+ const GOVERNANCE_FILE_PATTERNS = [
63
+ /(^|\/)licen[sc]e(\.[a-z0-9]+)?$/i,
64
+ /(^|\/)code_of_conduct(\.[a-z0-9]+)?$/i,
65
+ /(^|\/)contributing(\.[a-z0-9]+)?$/i,
66
+ /(^|\/)security(\.[a-z0-9]+)?$/i,
67
+ /(^|\/)support(\.[a-z0-9]+)?$/i,
68
+ /(^|\/)codeowners$/i,
69
+ /^\.github\/issue_template\//i,
70
+ /^\.github\/pull_request_template/i,
71
+ /^\.github\/discussion_template/i,
72
+ ];
73
+ function normalizeToken(value) {
74
+ return value.trim().toLowerCase().replace(/[\/\s-]+/g, '_');
75
+ }
76
+ function normalizeArea(value) {
77
+ const normalized = normalizeToken(value);
78
+ if (!normalized)
79
+ return null;
80
+ if (AREA_SET.has(normalized))
81
+ return normalized;
82
+ if (AREA_ALIASES[normalized])
83
+ return AREA_ALIASES[normalized];
84
+ if (normalized.includes('front') || normalized.includes('accessibility'))
85
+ return 'web_frontend';
86
+ if (normalized.includes('mobile'))
87
+ return 'mobile_frontend';
88
+ if (normalized.includes('back') || normalized.includes('api') || normalized.includes('server'))
89
+ return 'backend';
90
+ if (normalized.includes('script') || normalized.includes('cli') || normalized.includes('automation'))
91
+ return 'scripts';
92
+ if (normalized.includes('test') || normalized.includes('qa'))
93
+ return 'qa';
94
+ if (normalized.includes('sre') || normalized.includes('observability') || normalized.includes('reliability'))
95
+ return 'sre';
96
+ if (normalized.includes('devops') || normalized.includes('pipeline') || normalized.includes('deploy') || normalized.includes('infra'))
97
+ return 'devops';
98
+ if (normalized.includes('security'))
99
+ return 'security';
100
+ if (normalized === 'ai' || normalized.includes('llm') || normalized.includes('ml'))
101
+ return 'ai';
102
+ if (normalized.includes('ai_coding') || normalized.includes('prompt'))
103
+ return 'ai_coding_optimizations';
104
+ return null;
105
+ }
106
+ function normalizeContributionType(value) {
107
+ const normalized = normalizeToken(value);
108
+ if (!normalized)
109
+ return null;
110
+ if (CONTRIBUTION_TYPE_SET.has(normalized))
111
+ return normalized;
112
+ if (CONTRIBUTION_TYPE_ALIASES[normalized])
113
+ return CONTRIBUTION_TYPE_ALIASES[normalized];
114
+ if (normalized.includes('feature') || normalized.includes('enhancement'))
115
+ return 'new_development';
116
+ if (normalized.includes('fix') || normalized.includes('bug'))
117
+ return 'bugfix';
118
+ if (normalized.includes('refactor') || normalized.includes('cleanup'))
119
+ return 'refactor';
120
+ if (normalized.includes('doc') || normalized.includes('readme'))
121
+ return 'documentation';
122
+ return null;
123
+ }
124
+ function uniqueNormalized(values) {
125
+ return [...new Set(values.filter((value) => value !== null))];
126
+ }
127
+ function isGovernanceFile(path) {
128
+ const normalized = path.replace(/\\/g, '/').toLowerCase();
129
+ return GOVERNANCE_FILE_PATTERNS.some((pattern) => pattern.test(normalized));
130
+ }
131
+ export function getHeuristicPRAnalysis(pr) {
132
+ const changedFiles = extractChangedFiles(pr.diff);
133
+ const governanceTitle = /(license|licence|code[ _-]?of[ _-]?conduct|contributing|security|codeowners)/i.test(pr.title);
134
+ const governanceOnly = changedFiles.length > 0 && changedFiles.every((file) => isGovernanceFile(file));
135
+ if (!governanceOnly && !(changedFiles.length === 0 && governanceTitle)) {
136
+ return null;
137
+ }
138
+ const skipReason = 'Repository governance or legal template update';
139
+ return {
140
+ skipped: true,
141
+ skipReason,
142
+ complexity: 1,
143
+ areas: [],
144
+ types: ['documentation'],
145
+ technologies: [],
146
+ summary: skipReason,
147
+ };
148
+ }
149
+ export function parsePRAnalysisResponse(text) {
150
+ const json = extractJSON(text);
151
+ const parsed = PRAnalysisSchema.parse(JSON.parse(json));
152
+ const areas = uniqueNormalized(parsed.areas.map((area) => normalizeArea(area)));
153
+ const types = uniqueNormalized(parsed.types.map((type) => normalizeContributionType(type)));
154
+ const technologies = normalizeTechnologies(parsed.technologies);
155
+ const summary = parsed.summary.trim();
156
+ if (!summary) {
157
+ throw new Error('LLM response summary was empty');
158
+ }
159
+ if (!parsed.skipped && areas.length === 0) {
160
+ throw new Error(`LLM response did not contain a valid area label: ${parsed.areas.join(', ')}`);
161
+ }
162
+ if (!parsed.skipped && types.length === 0) {
163
+ throw new Error(`LLM response did not contain a valid contribution type: ${parsed.types.join(', ')}`);
164
+ }
165
+ diagLog('Parsed PR analysis response', {
166
+ skipped: parsed.skipped,
167
+ complexity: parsed.complexity,
168
+ rawAreas: parsed.areas,
169
+ rawTypes: parsed.types,
170
+ areas,
171
+ types,
172
+ technologies,
173
+ });
174
+ const { skipReason, ...rest } = parsed;
175
+ return {
176
+ ...rest,
177
+ summary,
178
+ areas,
179
+ types,
180
+ technologies,
181
+ ...(skipReason == null ? {} : { skipReason }),
182
+ };
183
+ }
184
+ export async function analyzePR(pr, model) {
185
+ const heuristicAnalysis = getHeuristicPRAnalysis(pr);
186
+ if (heuristicAnalysis) {
187
+ diagLog('Skipped PR by deterministic heuristics', {
188
+ prNumber: pr.number,
189
+ repo: pr.repo,
190
+ title: pr.title,
191
+ skipReason: heuristicAnalysis.skipReason,
192
+ changedFiles: extractChangedFiles(pr.diff),
193
+ });
194
+ return heuristicAnalysis;
195
+ }
196
+ const prompt = buildPRPrompt(pr);
197
+ diagLog('Built PR analysis prompt', {
198
+ prNumber: pr.number,
199
+ repo: pr.repo,
200
+ title: pr.title,
201
+ promptLength: prompt.length,
202
+ });
203
+ let lastError = null;
204
+ let feedbackSuffix = '';
205
+ for (let attempt = 0; attempt < 3; attempt++) {
206
+ try {
207
+ diagLog('Starting PR analysis attempt', {
208
+ prNumber: pr.number,
209
+ attempt: attempt + 1,
210
+ promptLength: (prompt + feedbackSuffix).length,
211
+ });
212
+ const raw = await callLLM(model, prompt + feedbackSuffix);
213
+ const parsed = parsePRAnalysisResponse(raw);
214
+ if (!parsed.skipped) {
215
+ const lowValueReason = getLowValuePRSummaryReason(parsed.summary);
216
+ if (lowValueReason) {
217
+ if (attempt < 2) {
218
+ throw new Error(`PR summary was low-value: ${lowValueReason}`);
219
+ }
220
+ const fallbackSummary = buildFallbackPRSummary(pr);
221
+ diagLog('Replacing low-value PR summary with fallback derived from title', {
222
+ prNumber: pr.number,
223
+ reason: lowValueReason,
224
+ fallbackSummary,
225
+ });
226
+ parsed.summary = fallbackSummary;
227
+ }
228
+ }
229
+ diagLog('Completed PR analysis attempt', {
230
+ prNumber: pr.number,
231
+ attempt: attempt + 1,
232
+ skipped: parsed.skipped,
233
+ complexity: parsed.complexity,
234
+ });
235
+ return parsed;
236
+ }
237
+ catch (err) {
238
+ lastError = err;
239
+ diagError('PR analysis attempt failed', err, {
240
+ prNumber: pr.number,
241
+ attempt: attempt + 1,
242
+ });
243
+ feedbackSuffix = `\n\nPrevious attempt failed with: ${lastError.message}. Please fix and return valid JSON only.`;
244
+ }
245
+ }
246
+ diagError('PR analysis exhausted all attempts', lastError, { prNumber: pr.number });
247
+ throw new Error(`Failed to analyze PR after 3 attempts: ${lastError?.message}`);
248
+ }
249
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/llm/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,aAAa,EACb,0BAA0B,GAK3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAElH,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAErE,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,aAAa,CAAC,CAAC;AAChD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAS,0BAA0B,CAAC,CAAC;AAE1E,MAAM,YAAY,GAAyB;IACzC,QAAQ,EAAE,cAAc;IACxB,GAAG,EAAE,cAAc;IACnB,EAAE,EAAE,cAAc;IAClB,aAAa,EAAE,cAAc;IAC7B,MAAM,EAAE,iBAAiB;IACzB,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,QAAQ;IACf,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,cAAc,EAAE,QAAQ;IACxB,QAAQ,EAAE,QAAQ;IAClB,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,WAAW,EAAE,QAAQ;IACrB,GAAG,EAAE,KAAK;IACV,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,KAAK;IAClB,GAAG,EAAE,IAAI;IACT,EAAE,EAAE,IAAI;CACT,CAAC;AAEF,MAAM,yBAAyB,GAAqC;IAClE,OAAO,EAAE,iBAAiB;IAC1B,QAAQ,EAAE,iBAAiB;IAC3B,WAAW,EAAE,iBAAiB;IAC9B,YAAY,EAAE,iBAAiB;IAC/B,WAAW,EAAE,iBAAiB;IAC9B,WAAW,EAAE,iBAAiB;IAC9B,GAAG,EAAE,QAAQ;IACb,KAAK,EAAE,QAAQ;IACf,GAAG,EAAE,QAAQ;IACb,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,UAAU;IACnB,WAAW,EAAE,UAAU;IACvB,IAAI,EAAE,eAAe;IACrB,GAAG,EAAE,eAAe;CACrB,CAAC;AAEF,MAAM,wBAAwB,GAAG;IAC/B,kCAAkC;IAClC,uCAAuC;IACvC,oCAAoC;IACpC,gCAAgC;IAChC,+BAA+B;IAC/B,oBAAoB;IACpB,8BAA8B;IAC9B,mCAAmC;IACnC,iCAAiC;CAClC,CAAC;AAEF,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,UAAkB,CAAC;IACxD,IAAI,YAAY,CAAC,UAAU,CAAC;QAAE,OAAO,YAAY,CAAC,UAAU,CAAC,CAAC;IAC9D,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,cAAc,CAAC;IAChG,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAC5D,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACjH,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,SAAS,CAAC;IACvH,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1E,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3H,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvJ,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IACvD,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAChG,IAAI,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,yBAAyB,CAAC;IACxG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAa;IAC9C,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,UAA8B,CAAC;IACjF,IAAI,yBAAyB,CAAC,UAAU,CAAC;QAAE,OAAO,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACxF,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,OAAO,iBAAiB,CAAC;IACnG,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC9E,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,UAAU,CAAC;IACzF,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,eAAe,CAAC;IACxF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAI,MAAuB;IAClD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAc,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1D,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAU;IAC/C,MAAM,YAAY,GAAG,mBAAmB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,eAAe,GAAG,+EAA+E,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACvH,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IAEvG,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,gDAAgD,CAAC;IACpE,OAAO;QACL,OAAO,EAAE,IAAI;QACb,UAAU;QACV,UAAU,EAAE,CAAC;QACb,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,YAAY,EAAE,EAAE;QAChB,OAAO,EAAE,UAAU;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChF,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5F,MAAM,YAAY,GAAG,qBAAqB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAEtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,oDAAoD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,2DAA2D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxG,CAAC;IAED,OAAO,CAAC,6BAA6B,EAAE;QACrC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,KAAK;QACtB,QAAQ,EAAE,MAAM,CAAC,KAAK;QACtB,KAAK;QACL,KAAK;QACL,YAAY;KACb,CAAC,CAAC;IACH,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IAEvC,OAAO;QACL,GAAG,IAAI;QACP,OAAO;QACP,KAAK;QACL,KAAK;QACL,YAAY;QACZ,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;KAC7B,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU,EAAE,KAAsB;IAChE,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,EAAE,CAAC,CAAC;IACrD,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,CAAC,wCAAwC,EAAE;YAChD,QAAQ,EAAE,EAAE,CAAC,MAAM;YACnB,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,UAAU,EAAE,iBAAiB,CAAC,UAAU;YACxC,YAAY,EAAE,mBAAmB,CAAC,EAAE,CAAC,IAAI,CAAC;SAC3C,CAAC,CAAC;QACH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,0BAA0B,EAAE;QAClC,QAAQ,EAAE,EAAE,CAAC,MAAM;QACnB,IAAI,EAAE,EAAE,CAAC,IAAI;QACb,KAAK,EAAE,EAAE,CAAC,KAAK;QACf,YAAY,EAAE,MAAM,CAAC,MAAM;KAC5B,CAAC,CAAC;IACH,IAAI,SAAS,GAAiB,IAAI,CAAC;IACnC,IAAI,cAAc,GAAG,EAAE,CAAC;IAExB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,CAAC,8BAA8B,EAAE;gBACtC,QAAQ,EAAE,EAAE,CAAC,MAAM;gBACnB,OAAO,EAAE,OAAO,GAAG,CAAC;gBACpB,YAAY,EAAE,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC,MAAM;aAC/C,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC;YAC1D,MAAM,MAAM,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,cAAc,GAAG,0BAA0B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAClE,IAAI,cAAc,EAAE,CAAC;oBACnB,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;wBAChB,MAAM,IAAI,KAAK,CAAC,6BAA6B,cAAc,EAAE,CAAC,CAAC;oBACjE,CAAC;oBAED,MAAM,eAAe,GAAG,sBAAsB,CAAC,EAAE,CAAC,CAAC;oBACnD,OAAO,CAAC,iEAAiE,EAAE;wBACzE,QAAQ,EAAE,EAAE,CAAC,MAAM;wBACnB,MAAM,EAAE,cAAc;wBACtB,eAAe;qBAChB,CAAC,CAAC;oBACH,MAAM,CAAC,OAAO,GAAG,eAAe,CAAC;gBACnC,CAAC;YACH,CAAC;YACD,OAAO,CAAC,+BAA+B,EAAE;gBACvC,QAAQ,EAAE,EAAE,CAAC,MAAM;gBACnB,OAAO,EAAE,OAAO,GAAG,CAAC;gBACpB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAY,CAAC;YACzB,SAAS,CAAC,4BAA4B,EAAE,GAAG,EAAE;gBAC3C,QAAQ,EAAE,EAAE,CAAC,MAAM;gBACnB,OAAO,EAAE,OAAO,GAAG,CAAC;aACrB,CAAC,CAAC;YACH,cAAc,GAAG,qCAAqC,SAAS,CAAC,OAAO,0CAA0C,CAAC;QACpH,CAAC;IACH,CAAC;IAED,SAAS,CAAC,oCAAoC,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;IACpF,MAAM,IAAI,KAAK,CAAC,0CAA0C,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;AAClF,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ import type { LanguageModelV1 } from 'ai';
3
+ import type { PlayerStats, CharacterProfile, PRData } from '../shared/types.js';
4
+ export declare const CharacterSchema: z.ZodObject<{
5
+ title: z.ZodEffects<z.ZodString, string, string>;
6
+ summary: z.ZodEffects<z.ZodString, string, string>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ title: string;
9
+ summary: string;
10
+ }, {
11
+ title: string;
12
+ summary: string;
13
+ }>;
14
+ export declare function buildFallbackCharacter(stats: PlayerStats, prs?: PRData[]): CharacterProfile;
15
+ export declare function generateCharacter(stats: PlayerStats, username: string, prs: PRData[], model: LanguageModelV1): Promise<CharacterProfile>;
16
+ //# sourceMappingURL=character.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"character.d.ts","sourceRoot":"","sources":["../../src/llm/character.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAG1C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAyBhF,eAAO,MAAM,eAAe;;;;;;;;;EAW1B,CAAC;AAiLH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,gBAAgB,CAU/F;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EAAE,EACb,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAgD3B"}
@@ -0,0 +1,245 @@
1
+ import { z } from 'zod';
2
+ import { callLLM, extractJSON } from './client.js';
3
+ import { buildCharacterPrompt } from './prompts.js';
4
+ import { diagError, diagLog } from '../shared/diagnostics.js';
5
+ import { TECHNOLOGY_TAXONOMY } from '../shared/technologies.js';
6
+ import { buildManagerProfileNotes, buildManagerProfileSummary, getNarrativePRSummary } from '../shared/profile-summary.js';
7
+ const AREA_TITLES = {
8
+ devops: 'Pipeline',
9
+ web_frontend: 'Frontend',
10
+ scripts: 'Automation',
11
+ mobile_frontend: 'Mobile',
12
+ backend: 'Backend',
13
+ sre: 'Reliability',
14
+ qa: 'Quality',
15
+ ai: 'AI',
16
+ security: 'Security',
17
+ ai_coding_optimizations: 'Prompt',
18
+ };
19
+ const TYPE_TITLES = {
20
+ bugfix: 'Warden',
21
+ new_development: 'Builder',
22
+ refactor: 'Refiner',
23
+ documentation: 'Chronicler',
24
+ };
25
+ export const CharacterSchema = z.object({
26
+ title: z
27
+ .string()
28
+ .min(4)
29
+ .max(60)
30
+ .refine((value) => value.trim() !== '...' && value.trim().toLowerCase() !== 'tbd', 'Character title was placeholder text'),
31
+ summary: z
32
+ .string()
33
+ .min(220)
34
+ .max(600)
35
+ .refine((value) => value.trim() !== '...' && value.trim().toLowerCase() !== 'tbd', 'Character summary was placeholder text'),
36
+ });
37
+ function formatLabel(value) {
38
+ return value.replace(/_/g, ' ');
39
+ }
40
+ function formatNaturalList(items) {
41
+ if (items.length === 0)
42
+ return '';
43
+ if (items.length === 1)
44
+ return items[0];
45
+ if (items.length === 2)
46
+ return `${items[0]} and ${items[1]}`;
47
+ return `${items.slice(0, -1).join(', ')}, and ${items[items.length - 1]}`;
48
+ }
49
+ function compactText(value, maxLength) {
50
+ const normalized = value.replace(/\s+/g, ' ').trim();
51
+ if (normalized.length <= maxLength)
52
+ return normalized;
53
+ const clipped = normalized.slice(0, maxLength - 3).trimEnd();
54
+ const breakIndex = Math.max(clipped.lastIndexOf('. '), clipped.lastIndexOf('; '), clipped.lastIndexOf(', '), clipped.lastIndexOf(' '));
55
+ const safeIndex = breakIndex > 120 ? breakIndex : clipped.length;
56
+ return `${clipped.slice(0, safeIndex).trimEnd()}...`;
57
+ }
58
+ function describeAreaDomain(area) {
59
+ switch (area) {
60
+ case 'backend':
61
+ return 'backend systems and service behavior';
62
+ case 'web_frontend':
63
+ return 'frontend flows and user-facing interactions';
64
+ case 'mobile_frontend':
65
+ return 'mobile-facing product surfaces';
66
+ case 'devops':
67
+ return 'delivery pipelines and platform plumbing';
68
+ case 'sre':
69
+ return 'reliability, observability, and production guardrails';
70
+ case 'qa':
71
+ return 'test coverage and release confidence';
72
+ case 'scripts':
73
+ return 'tooling, automation, and workflow glue';
74
+ case 'security':
75
+ return 'security-sensitive paths and protective guardrails';
76
+ case 'ai':
77
+ return 'AI-driven product behavior';
78
+ case 'ai_coding_optimizations':
79
+ return 'AI-assisted developer workflows';
80
+ default:
81
+ return formatLabel(area);
82
+ }
83
+ }
84
+ function describeContributionStyle(primaryType, secondaryType) {
85
+ if ((primaryType === 'new_development' && secondaryType === 'refactor')
86
+ || (primaryType === 'refactor' && secondaryType === 'new_development')) {
87
+ return 'Builds new capability and cleans up the structure underneath it.';
88
+ }
89
+ if ((primaryType === 'bugfix' && secondaryType === 'refactor')
90
+ || (primaryType === 'refactor' && secondaryType === 'bugfix')) {
91
+ return 'Steps into brittle paths, stabilizes them, and removes the friction behind the bug.';
92
+ }
93
+ switch (primaryType) {
94
+ case 'new_development':
95
+ return 'Usually turns product ideas into shipped, usable capability.';
96
+ case 'refactor':
97
+ return 'Usually takes on structural cleanup that makes future change safer and faster.';
98
+ case 'bugfix':
99
+ return 'Often gets pulled toward high-friction failures and leaves those paths more predictable.';
100
+ case 'documentation':
101
+ return 'Turns hard-won knowledge into docs and operational guidance the rest of the team can reuse.';
102
+ default:
103
+ return 'Has a habit of taking on meaningful engineering work and leaving the codebase easier to move through.';
104
+ }
105
+ }
106
+ function cleanHighlight(value) {
107
+ return value.replace(/\s+/g, ' ').trim().replace(/[.]+$/, '');
108
+ }
109
+ function getAnalyzedPRs(prs) {
110
+ return prs.filter((pr) => pr.analysis && !pr.analysis.skipped);
111
+ }
112
+ function buildCharacterHighlights(prs) {
113
+ const highlights = getAnalyzedPRs(prs)
114
+ .sort((left, right) => {
115
+ const pointDelta = (right.points ?? 0) - (left.points ?? 0);
116
+ if (pointDelta !== 0)
117
+ return pointDelta;
118
+ const complexityDelta = (right.analysis?.complexity ?? 0) - (left.analysis?.complexity ?? 0);
119
+ if (complexityDelta !== 0)
120
+ return complexityDelta;
121
+ return Date.parse(right.mergedAt) - Date.parse(left.mergedAt);
122
+ })
123
+ .map((pr) => cleanHighlight(getNarrativePRSummary(pr)))
124
+ .filter(Boolean);
125
+ return [...new Set(highlights)].slice(0, 3);
126
+ }
127
+ function buildPatternNotes(stats, prs) {
128
+ const areaEntries = Object.entries(stats.areas).sort(([, left], [, right]) => right - left);
129
+ const typeEntries = Object.entries(stats.types).sort(([, left], [, right]) => right - left);
130
+ const primaryArea = areaEntries[0]?.[0];
131
+ const secondaryArea = areaEntries[1]?.[0];
132
+ const primaryType = typeEntries[0]?.[0] ?? 'new_development';
133
+ const secondaryType = typeEntries[1]?.[0];
134
+ const multiAreaPRs = getAnalyzedPRs(prs).filter((pr) => new Set(pr.analysis?.areas ?? []).size > 1).length;
135
+ const hasDocsOrQaSupport = Boolean(stats.types['documentation'] || stats.areas['qa']);
136
+ const notes = [];
137
+ if (primaryArea) {
138
+ notes.push(`The center of gravity is ${describeAreaDomain(primaryArea)}.`);
139
+ }
140
+ if (secondaryArea && secondaryArea !== primaryArea) {
141
+ notes.push(`Regularly crosses into ${describeAreaDomain(secondaryArea)} when that is what it takes to finish the job well.`);
142
+ }
143
+ notes.push(describeContributionStyle(primaryType, secondaryType));
144
+ if (multiAreaPRs >= 2) {
145
+ notes.push('A noticeable share of the work spans multiple domains in the same change, not just isolated tickets.');
146
+ }
147
+ if (hasDocsOrQaSupport) {
148
+ notes.push('Tends to leave behind guardrails such as tests, docs, or operational guidance instead of stopping at the feature itself.');
149
+ }
150
+ return [...notes, ...buildManagerProfileNotes(stats, prs)].slice(0, 6);
151
+ }
152
+ function countTechnologyMentions(summary) {
153
+ const normalized = summary.toLowerCase();
154
+ return TECHNOLOGY_TAXONOMY.filter((technology) => {
155
+ const pattern = new RegExp(`\\b${technology.replace(/_/g, '[ _-]?')}\\b`, 'i');
156
+ return pattern.test(normalized);
157
+ }).length;
158
+ }
159
+ function getLowValueCharacterReason(summary, username) {
160
+ const normalized = summary.replace(/\s+/g, ' ').trim();
161
+ const lowercase = normalized.toLowerCase();
162
+ if (lowercase.startsWith(username.trim().toLowerCase())) {
163
+ return 'summary started with the username';
164
+ }
165
+ if (lowercase.startsWith('this developer')) {
166
+ return 'summary started with generic filler';
167
+ }
168
+ const lowValuePatterns = [
169
+ [/^mostly takes ownership of\b/i, 'summary relied on a generic ownership template'],
170
+ [/\ba good example is\b/i, 'summary used a low-value example template'],
171
+ [/\borg-scoped report\b/i, 'summary repeated report scope'],
172
+ [/\bstrongest in\b/i, 'summary described taxonomy instead of behavior'],
173
+ [/\barmed with\b/i, 'summary listed tools instead of impact'],
174
+ [/\banalyzed prs?\b/i, 'summary repeated PR counts'],
175
+ [/\bpull requests?\b/i, 'summary repeated PR counts'],
176
+ [/\blevel\s+\d+\b/i, 'summary repeated level information'],
177
+ [/\b\d[\d,]*\s*xp\b/i, 'summary repeated XP totals'],
178
+ ];
179
+ for (const [pattern, reason] of lowValuePatterns) {
180
+ if (pattern.test(normalized))
181
+ return reason;
182
+ }
183
+ if (countTechnologyMentions(normalized) >= 3) {
184
+ return 'summary was too technology-heavy';
185
+ }
186
+ return null;
187
+ }
188
+ export function buildFallbackCharacter(stats, prs = []) {
189
+ const topArea = Object.entries(stats.areas).sort(([, left], [, right]) => right - left)[0]?.[0] ?? 'backend';
190
+ const topType = Object.entries(stats.types).sort(([, left], [, right]) => right - left)[0]?.[0] ?? 'new_development';
191
+ const title = `${AREA_TITLES[topArea] ?? 'Full-Stack'} ${TYPE_TITLES[topType] ?? 'Vanguard'} Duck`;
192
+ const summary = compactText(buildManagerProfileSummary(stats, prs), 600);
193
+ return {
194
+ title,
195
+ summary,
196
+ };
197
+ }
198
+ export async function generateCharacter(stats, username, prs, model) {
199
+ const patternNotes = buildPatternNotes(stats, prs);
200
+ const highlights = buildCharacterHighlights(prs);
201
+ const prompt = buildCharacterPrompt(username, patternNotes, highlights);
202
+ diagLog('Built character prompt', {
203
+ username,
204
+ promptLength: prompt.length,
205
+ patternNoteCount: patternNotes.length,
206
+ highlightCount: highlights.length,
207
+ });
208
+ let feedbackSuffix = '';
209
+ for (let attempt = 0; attempt < 3; attempt++) {
210
+ try {
211
+ diagLog('Starting character generation attempt', {
212
+ username,
213
+ attempt: attempt + 1,
214
+ promptLength: (prompt + feedbackSuffix).length,
215
+ });
216
+ const raw = await callLLM(model, prompt + feedbackSuffix);
217
+ const json = extractJSON(raw);
218
+ const character = CharacterSchema.parse(JSON.parse(json));
219
+ const lowValueReason = getLowValueCharacterReason(character.summary, username);
220
+ if (lowValueReason) {
221
+ throw new Error(`Character summary was low-value: ${lowValueReason}`);
222
+ }
223
+ diagLog('Generated character profile', {
224
+ username,
225
+ attempt: attempt + 1,
226
+ character,
227
+ });
228
+ return character;
229
+ }
230
+ catch (err) {
231
+ diagError('Character generation attempt failed', err, {
232
+ username,
233
+ attempt: attempt + 1,
234
+ });
235
+ feedbackSuffix = `\n\nPrevious attempt failed with: ${err.message}. Return valid JSON only with keys "title" and "summary".`;
236
+ }
237
+ }
238
+ const fallbackCharacter = buildFallbackCharacter(stats, prs);
239
+ diagLog('Using fallback character profile', {
240
+ username,
241
+ fallbackCharacter,
242
+ });
243
+ return fallbackCharacter;
244
+ }
245
+ //# sourceMappingURL=character.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"character.js","sourceRoot":"","sources":["../../src/llm/character.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { LanguageModelV1 } from 'ai';
2
+ export declare function sanitizeLLMResponsePreview(text: string): string;
3
+ export declare function callLLM(model: LanguageModelV1, prompt: string): Promise<string>;
4
+ export declare function extractJSON(text: string): string;
5
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAG1C,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAsB,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBrF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBhD"}
@@ -0,0 +1,98 @@
1
+ import { generateText } from 'ai';
2
+ import { diagError, diagLog } from '../shared/diagnostics.js';
3
+ export function sanitizeLLMResponsePreview(text) {
4
+ const withoutThinkBlocks = text.replace(/<think>[\s\S]*?<\/think>/gi, ' ').replace(/\s+/g, ' ').trim();
5
+ return withoutThinkBlocks || '[empty after removing reasoning blocks]';
6
+ }
7
+ export async function callLLM(model, prompt) {
8
+ diagLog('Calling LLM', {
9
+ promptLength: prompt.length,
10
+ modelType: typeof model,
11
+ });
12
+ try {
13
+ const { text } = await generateText({
14
+ model,
15
+ prompt,
16
+ temperature: 0,
17
+ maxTokens: 1024,
18
+ });
19
+ const containsThinkBlocks = /<think>[\s\S]*?<\/think>/i.test(text);
20
+ diagLog('Received LLM response', {
21
+ responseLength: text.length,
22
+ containsThinkBlocks,
23
+ responsePreview: sanitizeLLMResponsePreview(text),
24
+ });
25
+ return text;
26
+ }
27
+ catch (err) {
28
+ diagError('LLM call failed', err, { promptLength: prompt.length });
29
+ throw err;
30
+ }
31
+ }
32
+ export function extractJSON(text) {
33
+ diagLog('Attempting to extract JSON from LLM response', { textLength: text.length });
34
+ for (let i = 0; i < text.length; i++) {
35
+ if (text[i] !== '{')
36
+ continue;
37
+ const end = findJSONEnd(text, i, '}');
38
+ if (end === -1)
39
+ continue;
40
+ const candidate = text.slice(i, end + 1);
41
+ try {
42
+ JSON.parse(candidate);
43
+ diagLog('Successfully extracted JSON from LLM response', {
44
+ startIndex: i,
45
+ jsonLength: candidate.length,
46
+ });
47
+ return candidate;
48
+ }
49
+ catch {
50
+ // Keep scanning until we find a parseable JSON value.
51
+ }
52
+ }
53
+ diagLog('Failed to extract JSON from LLM response', { textPreview: sanitizeLLMResponsePreview(text) });
54
+ throw new Error('No JSON found in LLM response');
55
+ }
56
+ function findJSONEnd(text, startIndex, closingChar) {
57
+ const stack = [closingChar];
58
+ let inString = false;
59
+ let escaped = false;
60
+ for (let i = startIndex + 1; i < text.length; i++) {
61
+ const char = text[i];
62
+ if (inString) {
63
+ if (escaped) {
64
+ escaped = false;
65
+ continue;
66
+ }
67
+ if (char === '\\') {
68
+ escaped = true;
69
+ continue;
70
+ }
71
+ if (char === '"') {
72
+ inString = false;
73
+ }
74
+ continue;
75
+ }
76
+ if (char === '"') {
77
+ inString = true;
78
+ continue;
79
+ }
80
+ if (char === '{') {
81
+ stack.push('}');
82
+ continue;
83
+ }
84
+ if (char === '[') {
85
+ stack.push(']');
86
+ continue;
87
+ }
88
+ const expected = stack[stack.length - 1];
89
+ if (char === expected) {
90
+ stack.pop();
91
+ if (stack.length === 0) {
92
+ return i;
93
+ }
94
+ }
95
+ }
96
+ return -1;
97
+ }
98
+ //# sourceMappingURL=client.js.map