@sonnechasser/ntrp 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.
@@ -0,0 +1,394 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/demo/seed.ts
4
+ function mulberry32(seed) {
5
+ let a = seed | 0;
6
+ return () => {
7
+ a = a + 1831565813 | 0;
8
+ let t = Math.imul(a ^ a >>> 15, 1 | a);
9
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
10
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
11
+ };
12
+ }
13
+ function createSeededRandom(seed) {
14
+ const raw = mulberry32(seed);
15
+ const rng = {
16
+ next: raw,
17
+ nextInt(min, max) {
18
+ return Math.floor(raw() * (max - min + 1)) + min;
19
+ },
20
+ nextFloat(min, max) {
21
+ return raw() * (max - min) + min;
22
+ },
23
+ pick(arr) {
24
+ if (arr.length === 0) {
25
+ throw new Error("Cannot pick from an empty array");
26
+ }
27
+ return arr[Math.floor(raw() * arr.length)];
28
+ },
29
+ pickN(arr, n) {
30
+ const copy = [...arr];
31
+ rng.shuffle(copy);
32
+ return copy.slice(0, Math.min(n, copy.length));
33
+ },
34
+ shuffle(arr) {
35
+ for (let i = arr.length - 1; i > 0; i--) {
36
+ const j = Math.floor(raw() * (i + 1));
37
+ const current = arr[i];
38
+ arr[i] = arr[j];
39
+ arr[j] = current;
40
+ }
41
+ return arr;
42
+ },
43
+ chance(probability) {
44
+ return raw() < probability;
45
+ },
46
+ uuid() {
47
+ const bytes = Array.from({ length: 16 }, () => Math.floor(raw() * 256));
48
+ bytes[6] = bytes[6] & 15 | 64;
49
+ bytes[8] = bytes[8] & 63 | 128;
50
+ const hex = bytes.map((b) => b.toString(16).padStart(2, "0")).join("");
51
+ return [
52
+ hex.slice(0, 8),
53
+ hex.slice(8, 12),
54
+ hex.slice(12, 16),
55
+ hex.slice(16, 20),
56
+ hex.slice(20, 32)
57
+ ].join("-");
58
+ },
59
+ date(start, end) {
60
+ const s = start.getTime();
61
+ const e = end.getTime();
62
+ return new Date(s + raw() * (e - s));
63
+ },
64
+ weightedPick(items, weights) {
65
+ if (items.length === 0) {
66
+ throw new Error("Cannot pick from an empty weighted item list");
67
+ }
68
+ const total = weights.reduce((sum, w) => sum + w, 0);
69
+ let r = raw() * total;
70
+ for (let i = 0; i < items.length; i++) {
71
+ r -= weights[i] ?? 0;
72
+ if (r <= 0) return items[i];
73
+ }
74
+ return items[items.length - 1];
75
+ }
76
+ };
77
+ return rng;
78
+ }
79
+
80
+ // src/demo/whimsy-names.ts
81
+ var WHIMSY_FIGURES = [
82
+ // ── Music (band members, real names — no stage names) ──
83
+ { first: "James", last: "Hetfield", category: "music" },
84
+ { first: "Lars", last: "Ulrich", category: "music" },
85
+ { first: "Kirk", last: "Hammett", category: "music" },
86
+ { first: "Robert", last: "Trujillo", category: "music" },
87
+ { first: "Myles", last: "Kennedy", category: "music" },
88
+ { first: "Mark", last: "Tremonti", category: "music" },
89
+ { first: "Scott", last: "Stapp", category: "music" },
90
+ { first: "Dave", last: "Grohl", category: "music" },
91
+ { first: "Taylor", last: "Hawkins", category: "music" },
92
+ { first: "Eddie", last: "Vedder", category: "music" },
93
+ { first: "Mike", last: "McCready", category: "music" },
94
+ { first: "Stone", last: "Gossard", category: "music" },
95
+ { first: "Geddy", last: "Lee", category: "music" },
96
+ { first: "Alex", last: "Lifeson", category: "music" },
97
+ { first: "Neil", last: "Peart", category: "music" },
98
+ { first: "Robert", last: "Plant", category: "music" },
99
+ { first: "Jimmy", last: "Page", category: "music" },
100
+ { first: "Brian", last: "May", category: "music" },
101
+ { first: "Roger", last: "Taylor", category: "music" },
102
+ { first: "Adam", last: "Jones", category: "music" },
103
+ { first: "Danny", last: "Carey", category: "music" },
104
+ { first: "Chris", last: "Cornell", category: "music" },
105
+ { first: "Angus", last: "Young", category: "music" },
106
+ { first: "Chad", last: "Smith", category: "music" },
107
+ { first: "Sammy", last: "Hagar", category: "music" },
108
+ { first: "Maynard", last: "Keenan", category: "music" },
109
+ { first: "Thom", last: "Yorke", category: "music" },
110
+ { first: "Tony", last: "Iommi", category: "music" },
111
+ { first: "Billie", last: "Armstrong", category: "music" },
112
+ { first: "Bruce", last: "Dickinson", category: "music" },
113
+ { first: "Stevie", last: "Nicks", category: "music" },
114
+ { first: "Jon", last: "Jovi", category: "music" },
115
+ { first: "Richie", last: "Sambora", category: "music" },
116
+ // ── Sports (legends, broadly uncontroversial) ──
117
+ { first: "Michael", last: "Jordan", category: "sports" },
118
+ { first: "Wayne", last: "Gretzky", category: "sports" },
119
+ { first: "Roger", last: "Federer", category: "sports" },
120
+ { first: "Serena", last: "Williams", category: "sports" },
121
+ { first: "Lionel", last: "Messi", category: "sports" },
122
+ { first: "Peyton", last: "Manning", category: "sports" },
123
+ { first: "Derek", last: "Jeter", category: "sports" },
124
+ { first: "Sidney", last: "Crosby", category: "sports" },
125
+ { first: "Mia", last: "Hamm", category: "sports" },
126
+ { first: "Larry", last: "Bird", category: "sports" },
127
+ { first: "Steph", last: "Curry", category: "sports" },
128
+ { first: "Patrick", last: "Mahomes", category: "sports" },
129
+ { first: "Jackie", last: "Robinson", category: "sports" },
130
+ { first: "Bonnie", last: "Blair", category: "sports" },
131
+ { first: "Peggy", last: "Fleming", category: "sports" },
132
+ { first: "Tiger", last: "Woods", category: "sports" },
133
+ { first: "Simone", last: "Biles", category: "sports" },
134
+ { first: "Venus", last: "Williams", category: "sports" },
135
+ { first: "Tom", last: "Brady", category: "sports" },
136
+ { first: "Naomi", last: "Osaka", category: "sports" },
137
+ { first: "Rafael", last: "Nadal", category: "sports" },
138
+ // ── Film / TV (well-known actors) ──
139
+ { first: "Tom", last: "Hanks", category: "film" },
140
+ { first: "Meryl", last: "Streep", category: "film" },
141
+ { first: "Denzel", last: "Washington", category: "film" },
142
+ { first: "Harrison", last: "Ford", category: "film" },
143
+ { first: "Sigourney", last: "Weaver", category: "film" },
144
+ { first: "Keanu", last: "Reeves", category: "film" },
145
+ { first: "Morgan", last: "Freeman", category: "film" },
146
+ { first: "Bryan", last: "Cranston", category: "film" },
147
+ { first: "Jeff", last: "Goldblum", category: "film" },
148
+ { first: "Cate", last: "Blanchett", category: "film" },
149
+ { first: "Viola", last: "Davis", category: "film" },
150
+ { first: "Jodie", last: "Foster", category: "film" },
151
+ { first: "Sandra", last: "Bullock", category: "film" },
152
+ { first: "Idris", last: "Elba", category: "film" },
153
+ { first: "Emma", last: "Stone", category: "film" },
154
+ { first: "Steve", last: "Carell", category: "film" },
155
+ { first: "Jennifer", last: "Aniston", category: "film" },
156
+ { first: "Matt", last: "Damon", category: "film" },
157
+ { first: "Julia", last: "Roberts", category: "film" },
158
+ { first: "Leonardo", last: "DiCaprio", category: "film" },
159
+ { first: "Aaron", last: "Paul", category: "film" },
160
+ { first: "Gillian", last: "Anderson", category: "film" }
161
+ ];
162
+ function createFigureDrawer(rng, categories) {
163
+ const pool = categories && categories.length > 0 ? WHIMSY_FIGURES.filter((f) => categories.includes(f.category)) : [...WHIMSY_FIGURES];
164
+ const shuffled = rng.shuffle([...pool]);
165
+ let idx = 0;
166
+ return {
167
+ next() {
168
+ if (idx >= shuffled.length) return null;
169
+ return shuffled[idx++];
170
+ }
171
+ };
172
+ }
173
+
174
+ // src/demo/scenarios.ts
175
+ var BASELINE = {
176
+ enterpriseRatio: 0.2,
177
+ midMarketRatio: 0.3,
178
+ smbRatio: 0.5,
179
+ staleContactRatio: 0.15,
180
+ staleContactRatioEnterprise: 0.2,
181
+ staleContactRatioSmb: 0.1,
182
+ pastCloseDateRatio: 0.1,
183
+ staleDays: 120,
184
+ mqlDropRatio: 0.1,
185
+ qualifiedNoOutreachRatio: 0.1,
186
+ stuckDealRatio: 0.1,
187
+ stuckInNegotiationDays: 45,
188
+ avgDaysPerStageEnterprise: 25,
189
+ avgDaysPerStageSmb: 8,
190
+ activityVolumeMultiplier: 1,
191
+ noiseActivityRatio: 0.15,
192
+ singleThreadRatio: 0.2,
193
+ loneWolfRepIndex: null,
194
+ loneWolfSingleThreadRatio: 0,
195
+ freshnessGapDays: 90
196
+ };
197
+ var SCENARIOS = {
198
+ hidden_crisis: {
199
+ ...BASELINE,
200
+ key: "hidden_crisis",
201
+ label: "The Hidden Crisis",
202
+ description: "Overall health looks yellow but Enterprise is deep red, masked by strong SMB numbers.",
203
+ story: "Your aggregate numbers look okay \u2014 but when you break it by segment, Enterprise is dying. 60% of enterprise contacts have gone dark, deals are single-threaded, and SMB is carrying the average.",
204
+ staleContactRatio: 0.3,
205
+ staleContactRatioEnterprise: 0.6,
206
+ staleContactRatioSmb: 0.1,
207
+ singleThreadRatio: 0.5,
208
+ enterpriseRatio: 0.3,
209
+ midMarketRatio: 0.3,
210
+ smbRatio: 0.4
211
+ },
212
+ leaky_bucket: {
213
+ ...BASELINE,
214
+ key: "leaky_bucket",
215
+ label: "The Leaky Bucket",
216
+ description: "Marketing generates plenty of leads but 40% vanish at handoff to sales.",
217
+ story: "Marketing is doing its job \u2014 MQLs are flowing. But 40% of qualified leads never show up in sales workflows. They're falling through the cracks at handoff, and nobody's noticing because marketing reports MQL count and sales reports pipeline value.",
218
+ mqlDropRatio: 0.4,
219
+ qualifiedNoOutreachRatio: 0.35,
220
+ staleContactRatio: 0.2
221
+ },
222
+ stale_pipeline: {
223
+ ...BASELINE,
224
+ key: "stale_pipeline",
225
+ label: "The Stale Pipeline",
226
+ description: "Big pipeline number but half the deals are zombies stuck in late stages.",
227
+ story: "The pipeline report says $5M. But look closer: half those deals have close dates in the past, 40% are stuck in Negotiation for 120+ days, and nobody's touching them. You're forecasting on fiction.",
228
+ pastCloseDateRatio: 0.5,
229
+ stuckDealRatio: 0.4,
230
+ stuckInNegotiationDays: 120,
231
+ staleContactRatio: 0.25,
232
+ staleDays: 90
233
+ },
234
+ lone_wolf: {
235
+ ...BASELINE,
236
+ key: "lone_wolf",
237
+ label: "The Lone Wolf",
238
+ description: "One rep has great numbers but every single deal is single-threaded.",
239
+ story: "Your top rep is crushing it on paper \u2014 biggest pipeline, highest close rate. But every deal has exactly one contact. One champion goes on vacation, gets promoted, or leaves, and the entire pipeline collapses.",
240
+ loneWolfRepIndex: 0,
241
+ loneWolfSingleThreadRatio: 1,
242
+ singleThreadRatio: 0.15
243
+ },
244
+ busy_bees: {
245
+ ...BASELINE,
246
+ key: "busy_bees",
247
+ label: "The Busy Bees",
248
+ description: "High activity volume across the team, but most of it hits dead ends.",
249
+ story: "Your team is busy. Activity metrics look great \u2014 calls are up, emails are up, meetings are up. But 60% of that activity is aimed at contacts with no associated pipeline. Reps are spraying, not aiming.",
250
+ activityVolumeMultiplier: 3,
251
+ noiseActivityRatio: 0.6,
252
+ staleContactRatio: 0.2
253
+ }
254
+ };
255
+ var SCENARIO_LIST = Object.values(SCENARIOS);
256
+ var NAMED_DEMO_SCENARIOS = [
257
+ "hidden_crisis",
258
+ "leaky_bucket",
259
+ "stale_pipeline",
260
+ "lone_wolf",
261
+ "busy_bees"
262
+ ];
263
+ function resolveScenarioInput(raw) {
264
+ const input = raw?.trim();
265
+ if (!input) return void 0;
266
+ if (input === "research_blend") return "research_blend";
267
+ if (NAMED_DEMO_SCENARIOS.includes(input)) {
268
+ return input;
269
+ }
270
+ const n = Number(input);
271
+ if (Number.isInteger(n) && n >= 1 && n <= NAMED_DEMO_SCENARIOS.length) {
272
+ return NAMED_DEMO_SCENARIOS[n - 1];
273
+ }
274
+ return null;
275
+ }
276
+
277
+ // src/ai/json-response.ts
278
+ function stripJsonFences(text) {
279
+ const trimmed = text.trim();
280
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
281
+ if (fenced) return fenced[1].trim();
282
+ return trimmed.replace(/```(?:json)?\s*/gi, "").replace(/```/g, "").trim();
283
+ }
284
+ function parseJsonArrayFromText(text) {
285
+ const cleaned = stripJsonFences(text);
286
+ const start = cleaned.indexOf("[");
287
+ if (start === -1) return null;
288
+ let depth = 0;
289
+ let end = -1;
290
+ for (let i = start; i < cleaned.length; i++) {
291
+ if (cleaned[i] === "[") depth++;
292
+ else if (cleaned[i] === "]") {
293
+ depth--;
294
+ if (depth === 0) {
295
+ end = i;
296
+ break;
297
+ }
298
+ }
299
+ }
300
+ if (end === -1) return null;
301
+ try {
302
+ const parsed = JSON.parse(cleaned.slice(start, end + 1));
303
+ return Array.isArray(parsed) ? parsed : null;
304
+ } catch {
305
+ return null;
306
+ }
307
+ }
308
+
309
+ // src/demo/whimsy-smoke.ts
310
+ function assert(condition, message) {
311
+ if (!condition) {
312
+ console.error(`FAIL: ${message}`);
313
+ process.exit(1);
314
+ }
315
+ }
316
+ function testNoRepeats() {
317
+ const rng = createSeededRandom(42);
318
+ const drawer = createFigureDrawer(rng);
319
+ const seen = /* @__PURE__ */ new Set();
320
+ let count = 0;
321
+ for (let fig = drawer.next(); fig !== null; fig = drawer.next()) {
322
+ const key = `${fig.first}|${fig.last}`;
323
+ assert(!seen.has(key), `duplicate figure drawn: ${fig.first} ${fig.last}`);
324
+ seen.add(key);
325
+ count++;
326
+ }
327
+ assert(count === WHIMSY_FIGURES.length, `expected ${WHIMSY_FIGURES.length} unique draws, got ${count}`);
328
+ }
329
+ function testDeterministicOrder() {
330
+ const draw = (seed) => {
331
+ const drawer = createFigureDrawer(createSeededRandom(seed));
332
+ return Array.from({ length: 5 }, () => {
333
+ const f = drawer.next();
334
+ return f ? `${f.first} ${f.last}` : "";
335
+ });
336
+ };
337
+ assert(
338
+ JSON.stringify(draw(7)) === JSON.stringify(draw(7)),
339
+ "same seed should produce identical rep name order"
340
+ );
341
+ assert(
342
+ JSON.stringify(draw(7)) !== JSON.stringify(draw(8)),
343
+ "different seeds should shuffle differently"
344
+ );
345
+ }
346
+ function testCategoryFilter() {
347
+ const rng = createSeededRandom(123);
348
+ const drawer = createFigureDrawer(rng, ["music"]);
349
+ for (let fig = drawer.next(); fig !== null; fig = drawer.next()) {
350
+ assert(fig.category === "music", `expected music, got ${fig.category} for ${fig.first} ${fig.last}`);
351
+ }
352
+ const musicCount = WHIMSY_FIGURES.filter((f) => f.category === "music").length;
353
+ assert(musicCount > 0, "music pool should not be empty");
354
+ }
355
+ function testCategoriesPresent() {
356
+ const categories = ["music", "sports", "film"];
357
+ for (const cat of categories) {
358
+ assert(
359
+ WHIMSY_FIGURES.some((f) => f.category === cat),
360
+ `pool missing category: ${cat}`
361
+ );
362
+ }
363
+ }
364
+ function testEmailSafeLastNames() {
365
+ for (const fig of WHIMSY_FIGURES) {
366
+ assert(!fig.last.includes(" "), `${fig.first} ${fig.last} has multi-word last name`);
367
+ assert(fig.first.length > 0 && fig.last.length > 0, "empty name part");
368
+ }
369
+ }
370
+ function testResolveScenarioInput() {
371
+ assert(resolveScenarioInput(void 0) === void 0, "blank -> random");
372
+ assert(resolveScenarioInput("hidden_crisis") === "hidden_crisis", "key passthrough");
373
+ assert(resolveScenarioInput("2") === "leaky_bucket", "2 -> second scenario");
374
+ assert(resolveScenarioInput("99") === null, "out of range -> invalid");
375
+ assert(resolveScenarioInput("not-a-scenario") === null, "garbage -> invalid");
376
+ }
377
+ function testParseJsonArrayFromText() {
378
+ assert(parseJsonArrayFromText("[]")?.length === 0, "empty array");
379
+ const fenced = parseJsonArrayFromText('Here you go:\n```json\n[{"a":1}]\n```');
380
+ assert(Array.isArray(fenced) && fenced[0].a === 1, "fenced array");
381
+ assert(parseJsonArrayFromText("not json") === null, "garbage -> null");
382
+ const balanced = parseJsonArrayFromText('Note:\n[{"text":"$727K pipeline at risk"}]');
383
+ assert(Array.isArray(balanced) && balanced.length === 1, "preamble + array");
384
+ assert(stripJsonFences("```json\n[]\n```") === "[]", "strip fences");
385
+ }
386
+ testNoRepeats();
387
+ testDeterministicOrder();
388
+ testCategoryFilter();
389
+ testCategoriesPresent();
390
+ testEmailSafeLastNames();
391
+ testResolveScenarioInput();
392
+ testParseJsonArrayFromText();
393
+ console.log(`whimsy smoke passed (${WHIMSY_FIGURES.length} figures)`);
394
+ //# sourceMappingURL=whimsy-smoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/demo/seed.ts","../../src/demo/whimsy-names.ts","../../src/demo/scenarios.ts","../../src/ai/json-response.ts","../../src/demo/whimsy-smoke.ts"],"sourcesContent":["/**\n * Seeded PRNG using mulberry32 algorithm.\n * All randomness in the generator flows through this — no Math.random().\n */\n\nexport interface SeededRandom {\n /** Returns a float in [0, 1) */\n next(): number;\n /** Returns an integer in [min, max] inclusive */\n nextInt(min: number, max: number): number;\n /** Pick a random element from an array */\n pick<T>(arr: readonly T[]): T;\n /** Shuffle an array in place (Fisher-Yates) */\n shuffle<T>(arr: T[]): T[];\n /** Returns true with the given probability (0-1) */\n chance(probability: number): boolean;\n /** Generate a deterministic UUID v4 */\n uuid(): string;\n /** Generate a random date between start and end */\n date(start: Date, end: Date): Date;\n /** Pick N unique elements from an array */\n pickN<T>(arr: readonly T[], n: number): T[];\n /** Generate a float in [min, max) */\n nextFloat(min: number, max: number): number;\n /** Weighted pick: items with associated weights */\n weightedPick<T>(items: readonly T[], weights: readonly number[]): T;\n}\n\nfunction mulberry32(seed: number): () => number {\n let a = seed | 0;\n return () => {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nexport function createSeededRandom(seed: number): SeededRandom {\n const raw = mulberry32(seed);\n\n const rng: SeededRandom = {\n next: raw,\n\n nextInt(min: number, max: number): number {\n return Math.floor(raw() * (max - min + 1)) + min;\n },\n\n nextFloat(min: number, max: number): number {\n return raw() * (max - min) + min;\n },\n\n pick<T>(arr: readonly T[]): T {\n if (arr.length === 0) {\n throw new Error(\"Cannot pick from an empty array\");\n }\n return arr[Math.floor(raw() * arr.length)]!;\n },\n\n pickN<T>(arr: readonly T[], n: number): T[] {\n const copy = [...arr];\n rng.shuffle(copy);\n return copy.slice(0, Math.min(n, copy.length));\n },\n\n shuffle<T>(arr: T[]): T[] {\n for (let i = arr.length - 1; i > 0; i--) {\n const j = Math.floor(raw() * (i + 1));\n const current = arr[i]!;\n arr[i] = arr[j]!;\n arr[j] = current;\n }\n return arr;\n },\n\n chance(probability: number): boolean {\n return raw() < probability;\n },\n\n uuid(): string {\n const bytes = Array.from({ length: 16 }, () => Math.floor(raw() * 256));\n bytes[6] = (bytes[6]! & 0x0f) | 0x40; // version 4\n bytes[8] = (bytes[8]! & 0x3f) | 0x80; // variant 1\n const hex = bytes.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32),\n ].join(\"-\");\n },\n\n date(start: Date, end: Date): Date {\n const s = start.getTime();\n const e = end.getTime();\n return new Date(s + raw() * (e - s));\n },\n\n weightedPick<T>(items: readonly T[], weights: readonly number[]): T {\n if (items.length === 0) {\n throw new Error(\"Cannot pick from an empty weighted item list\");\n }\n const total = weights.reduce((sum, w) => sum + w, 0);\n let r = raw() * total;\n for (let i = 0; i < items.length; i++) {\n r -= weights[i] ?? 0;\n if (r <= 0) return items[i]!;\n }\n return items[items.length - 1]!;\n },\n };\n\n return rng;\n}\n","/**\n * Whimsy name pool — a curated, hand-picked roster of recognizable real\n * figures from SAFE cultural domains (music, sports, film/TV). Used to give\n * generated reps / account owners a little delight instead of \"John Smith\".\n *\n * Mirrors the GOODBYES pattern in src/cli/repl.ts: a flat, audited static\n * list. Names are deliberately NOT AI-generated (hallucination / safety risk)\n * and NOT derived from the company config — this is a purely cosmetic layer\n * that sits on top of the config-driven data \"shape\".\n *\n * Curation rules:\n * - Safe domains only: music, sports, film/TV. NO politics, NO religion.\n * - Real names only (no stage names) so first/last split cleanly for emails.\n * - Single-word last names only — `toEmail` concatenates `first.last`, so a\n * space (e.g. \"Van Halen\") would produce an invalid email. Keep it clean.\n * - Paired as atomic units: \"James Hetfield\" stays together, never mixed into\n * \"James Hammett\".\n */\n\nimport type { SeededRandom } from \"./seed.js\";\n\nexport type WhimsyCategory = \"music\" | \"sports\" | \"film\";\n\nexport interface WhimsyFigure {\n first: string;\n last: string;\n category: WhimsyCategory;\n}\n\nexport const WHIMSY_FIGURES: readonly WhimsyFigure[] = [\n // ── Music (band members, real names — no stage names) ──\n { first: \"James\", last: \"Hetfield\", category: \"music\" },\n { first: \"Lars\", last: \"Ulrich\", category: \"music\" },\n { first: \"Kirk\", last: \"Hammett\", category: \"music\" },\n { first: \"Robert\", last: \"Trujillo\", category: \"music\" },\n { first: \"Myles\", last: \"Kennedy\", category: \"music\" },\n { first: \"Mark\", last: \"Tremonti\", category: \"music\" },\n { first: \"Scott\", last: \"Stapp\", category: \"music\" },\n { first: \"Dave\", last: \"Grohl\", category: \"music\" },\n { first: \"Taylor\", last: \"Hawkins\", category: \"music\" },\n { first: \"Eddie\", last: \"Vedder\", category: \"music\" },\n { first: \"Mike\", last: \"McCready\", category: \"music\" },\n { first: \"Stone\", last: \"Gossard\", category: \"music\" },\n { first: \"Geddy\", last: \"Lee\", category: \"music\" },\n { first: \"Alex\", last: \"Lifeson\", category: \"music\" },\n { first: \"Neil\", last: \"Peart\", category: \"music\" },\n { first: \"Robert\", last: \"Plant\", category: \"music\" },\n { first: \"Jimmy\", last: \"Page\", category: \"music\" },\n { first: \"Brian\", last: \"May\", category: \"music\" },\n { first: \"Roger\", last: \"Taylor\", category: \"music\" },\n { first: \"Adam\", last: \"Jones\", category: \"music\" },\n { first: \"Danny\", last: \"Carey\", category: \"music\" },\n { first: \"Chris\", last: \"Cornell\", category: \"music\" },\n { first: \"Angus\", last: \"Young\", category: \"music\" },\n { first: \"Chad\", last: \"Smith\", category: \"music\" },\n { first: \"Sammy\", last: \"Hagar\", category: \"music\" },\n { first: \"Maynard\", last: \"Keenan\", category: \"music\" },\n { first: \"Thom\", last: \"Yorke\", category: \"music\" },\n { first: \"Tony\", last: \"Iommi\", category: \"music\" },\n { first: \"Billie\", last: \"Armstrong\", category: \"music\" },\n { first: \"Bruce\", last: \"Dickinson\", category: \"music\" },\n { first: \"Stevie\", last: \"Nicks\", category: \"music\" },\n { first: \"Jon\", last: \"Jovi\", category: \"music\" },\n { first: \"Richie\", last: \"Sambora\", category: \"music\" },\n\n // ── Sports (legends, broadly uncontroversial) ──\n { first: \"Michael\", last: \"Jordan\", category: \"sports\" },\n { first: \"Wayne\", last: \"Gretzky\", category: \"sports\" },\n { first: \"Roger\", last: \"Federer\", category: \"sports\" },\n { first: \"Serena\", last: \"Williams\", category: \"sports\" },\n { first: \"Lionel\", last: \"Messi\", category: \"sports\" },\n { first: \"Peyton\", last: \"Manning\", category: \"sports\" },\n { first: \"Derek\", last: \"Jeter\", category: \"sports\" },\n { first: \"Sidney\", last: \"Crosby\", category: \"sports\" },\n { first: \"Mia\", last: \"Hamm\", category: \"sports\" },\n { first: \"Larry\", last: \"Bird\", category: \"sports\" },\n { first: \"Steph\", last: \"Curry\", category: \"sports\" },\n { first: \"Patrick\", last: \"Mahomes\", category: \"sports\" },\n { first: \"Jackie\", last: \"Robinson\", category: \"sports\" },\n { first: \"Bonnie\", last: \"Blair\", category: \"sports\" },\n { first: \"Peggy\", last: \"Fleming\", category: \"sports\" },\n { first: \"Tiger\", last: \"Woods\", category: \"sports\" },\n { first: \"Simone\", last: \"Biles\", category: \"sports\" },\n { first: \"Venus\", last: \"Williams\", category: \"sports\" },\n { first: \"Tom\", last: \"Brady\", category: \"sports\" },\n { first: \"Naomi\", last: \"Osaka\", category: \"sports\" },\n { first: \"Rafael\", last: \"Nadal\", category: \"sports\" },\n\n // ── Film / TV (well-known actors) ──\n { first: \"Tom\", last: \"Hanks\", category: \"film\" },\n { first: \"Meryl\", last: \"Streep\", category: \"film\" },\n { first: \"Denzel\", last: \"Washington\", category: \"film\" },\n { first: \"Harrison\", last: \"Ford\", category: \"film\" },\n { first: \"Sigourney\", last: \"Weaver\", category: \"film\" },\n { first: \"Keanu\", last: \"Reeves\", category: \"film\" },\n { first: \"Morgan\", last: \"Freeman\", category: \"film\" },\n { first: \"Bryan\", last: \"Cranston\", category: \"film\" },\n { first: \"Jeff\", last: \"Goldblum\", category: \"film\" },\n { first: \"Cate\", last: \"Blanchett\", category: \"film\" },\n { first: \"Viola\", last: \"Davis\", category: \"film\" },\n { first: \"Jodie\", last: \"Foster\", category: \"film\" },\n { first: \"Sandra\", last: \"Bullock\", category: \"film\" },\n { first: \"Idris\", last: \"Elba\", category: \"film\" },\n { first: \"Emma\", last: \"Stone\", category: \"film\" },\n { first: \"Steve\", last: \"Carell\", category: \"film\" },\n { first: \"Jennifer\", last: \"Aniston\", category: \"film\" },\n { first: \"Matt\", last: \"Damon\", category: \"film\" },\n { first: \"Julia\", last: \"Roberts\", category: \"film\" },\n { first: \"Leonardo\", last: \"DiCaprio\", category: \"film\" },\n { first: \"Aaron\", last: \"Paul\", category: \"film\" },\n { first: \"Gillian\", last: \"Anderson\", category: \"film\" },\n];\n\n/**\n * A stateful, deterministic, draw-without-replacement cursor over the whimsy\n * pool. Each `next()` returns a unique figure so the same celebrity never\n * shows up twice in one dataset. Returns `null` once the (optionally\n * category-filtered) pool is exhausted, so callers can fall back to the\n * generic name pools for any overflow.\n */\nexport interface FigureDrawer {\n next(): WhimsyFigure | null;\n}\n\nexport function createFigureDrawer(\n rng: SeededRandom,\n categories?: readonly WhimsyCategory[],\n): FigureDrawer {\n const pool = categories && categories.length > 0\n ? WHIMSY_FIGURES.filter((f) => categories.includes(f.category))\n : [...WHIMSY_FIGURES];\n const shuffled = rng.shuffle([...pool]);\n let idx = 0;\n\n return {\n next(): WhimsyFigure | null {\n if (idx >= shuffled.length) return null;\n return shuffled[idx++]!;\n },\n };\n}\n","/**\n * 5 scenario presets for the sample data generator.\n * Each amplifies a specific problem while maintaining baseline levels of all problems.\n */\n\nimport type { DemoScenario } from \"../types.js\";\nimport type { ScenarioParams } from \"./types.js\";\n\nconst BASELINE: Omit<ScenarioParams, \"key\" | \"label\" | \"description\" | \"story\"> = {\n enterpriseRatio: 0.2,\n midMarketRatio: 0.3,\n smbRatio: 0.5,\n\n staleContactRatio: 0.15,\n staleContactRatioEnterprise: 0.2,\n staleContactRatioSmb: 0.1,\n pastCloseDateRatio: 0.1,\n staleDays: 120,\n\n mqlDropRatio: 0.1,\n qualifiedNoOutreachRatio: 0.1,\n\n stuckDealRatio: 0.1,\n stuckInNegotiationDays: 45,\n avgDaysPerStageEnterprise: 25,\n avgDaysPerStageSmb: 8,\n\n activityVolumeMultiplier: 1.0,\n noiseActivityRatio: 0.15,\n\n singleThreadRatio: 0.2,\n loneWolfRepIndex: null,\n loneWolfSingleThreadRatio: 0.0,\n\n freshnessGapDays: 90,\n};\n\nexport const SCENARIOS: Record<string, ScenarioParams> = {\n hidden_crisis: {\n ...BASELINE,\n key: \"hidden_crisis\",\n label: \"The Hidden Crisis\",\n description: \"Overall health looks yellow but Enterprise is deep red, masked by strong SMB numbers.\",\n story: \"Your aggregate numbers look okay — but when you break it by segment, Enterprise is dying. 60% of enterprise contacts have gone dark, deals are single-threaded, and SMB is carrying the average.\",\n\n staleContactRatio: 0.3,\n staleContactRatioEnterprise: 0.6,\n staleContactRatioSmb: 0.1,\n singleThreadRatio: 0.5,\n enterpriseRatio: 0.3,\n midMarketRatio: 0.3,\n smbRatio: 0.4,\n },\n\n leaky_bucket: {\n ...BASELINE,\n key: \"leaky_bucket\",\n label: \"The Leaky Bucket\",\n description: \"Marketing generates plenty of leads but 40% vanish at handoff to sales.\",\n story: \"Marketing is doing its job — MQLs are flowing. But 40% of qualified leads never show up in sales workflows. They're falling through the cracks at handoff, and nobody's noticing because marketing reports MQL count and sales reports pipeline value.\",\n\n mqlDropRatio: 0.4,\n qualifiedNoOutreachRatio: 0.35,\n staleContactRatio: 0.2,\n },\n\n stale_pipeline: {\n ...BASELINE,\n key: \"stale_pipeline\",\n label: \"The Stale Pipeline\",\n description: \"Big pipeline number but half the deals are zombies stuck in late stages.\",\n story: \"The pipeline report says $5M. But look closer: half those deals have close dates in the past, 40% are stuck in Negotiation for 120+ days, and nobody's touching them. You're forecasting on fiction.\",\n\n pastCloseDateRatio: 0.5,\n stuckDealRatio: 0.4,\n stuckInNegotiationDays: 120,\n staleContactRatio: 0.25,\n staleDays: 90,\n },\n\n lone_wolf: {\n ...BASELINE,\n key: \"lone_wolf\",\n label: \"The Lone Wolf\",\n description: \"One rep has great numbers but every single deal is single-threaded.\",\n story: \"Your top rep is crushing it on paper — biggest pipeline, highest close rate. But every deal has exactly one contact. One champion goes on vacation, gets promoted, or leaves, and the entire pipeline collapses.\",\n\n loneWolfRepIndex: 0,\n loneWolfSingleThreadRatio: 1.0,\n singleThreadRatio: 0.15,\n },\n\n busy_bees: {\n ...BASELINE,\n key: \"busy_bees\",\n label: \"The Busy Bees\",\n description: \"High activity volume across the team, but most of it hits dead ends.\",\n story: \"Your team is busy. Activity metrics look great — calls are up, emails are up, meetings are up. But 60% of that activity is aimed at contacts with no associated pipeline. Reps are spraying, not aiming.\",\n\n activityVolumeMultiplier: 3.0,\n noiseActivityRatio: 0.6,\n staleContactRatio: 0.2,\n },\n};\n\nexport const SCENARIO_LIST = Object.values(SCENARIOS);\n\nexport function getScenario(key: string): ScenarioParams {\n const scenario = SCENARIOS[key];\n if (!scenario) {\n throw new Error(`Unknown scenario: ${key}. Valid: ${Object.keys(SCENARIOS).join(\", \")}`);\n }\n return scenario;\n}\n\n/** Scenario keys accepted by the demo generator (excludes research_blend). */\nexport const NAMED_DEMO_SCENARIOS = [\n \"hidden_crisis\",\n \"leaky_bucket\",\n \"stale_pipeline\",\n \"lone_wolf\",\n \"busy_bees\",\n] as const satisfies readonly DemoScenario[];\n\n/**\n * Resolve a --scenario flag or wizard answer into a scenario key.\n * - blank → undefined (caller picks random)\n * - \"hidden_crisis\" etc. → that key\n * - \"1\"-\"5\" → NAMED_DEMO_SCENARIOS[n-1] (menu-style input)\n * - anything else → null (invalid)\n */\nexport function resolveScenarioInput(\n raw: string | undefined,\n): DemoScenario | \"research_blend\" | undefined | null {\n const input = raw?.trim();\n if (!input) return undefined;\n if (input === \"research_blend\") return \"research_blend\";\n if ((NAMED_DEMO_SCENARIOS as readonly string[]).includes(input)) {\n return input as DemoScenario;\n }\n const n = Number(input);\n if (Number.isInteger(n) && n >= 1 && n <= NAMED_DEMO_SCENARIOS.length) {\n return NAMED_DEMO_SCENARIOS[n - 1]!;\n }\n return null;\n}\n\n/**\n * Named-scenario pool used by `pickRandomScenario`. Deliberately excludes\n * `research_blend` — the 5 named presets are the \"multiple potential\n * scenarios\" that /demo randomizes across.\n */\nconst RANDOM_POOL: DemoScenario[] = [\n \"hidden_crisis\",\n \"leaky_bucket\",\n \"stale_pipeline\",\n \"lone_wolf\",\n \"busy_bees\",\n];\n\n/**\n * Pick a fresh random scenario per /demo invocation. Uses Math.random() at\n * the CLI boundary (not the seeded RNG) so successive runs differ.\n */\nexport function pickRandomScenario(): DemoScenario {\n return RANDOM_POOL[Math.floor(Math.random() * RANDOM_POOL.length)]!;\n}\n\n/**\n * Creates a composite ScenarioParams by mixing BASELINE with moderate\n * problem seeding across all vital signs. CLI version always returns\n * the baseline blend (no company research integration).\n */\nexport function blendScenarios(_research: null): ScenarioParams {\n // Start from baseline with moderate problem seeding\n const blended: ScenarioParams = {\n ...BASELINE,\n key: \"research_blend\",\n label: \"Research-Derived Blend\",\n description: \"Realistic data with mild-to-moderate problems across all vital signs.\",\n story: \"Generated with default research blend. Problems are seeded across all vital signs at realistic levels.\",\n\n // Bump all problems slightly above baseline for discoverability\n staleContactRatio: 0.2,\n pastCloseDateRatio: 0.15,\n mqlDropRatio: 0.15,\n qualifiedNoOutreachRatio: 0.15,\n stuckDealRatio: 0.15,\n noiseActivityRatio: 0.2,\n singleThreadRatio: 0.25,\n };\n\n return blended;\n}\n","/**\n * Shared helpers for parsing JSON from LLM text responses.\n * Models often wrap arrays in markdown fences or add a short preamble —\n * always extract the outermost balanced `[...]` before parsing.\n */\n\n/** Strip ```json fences and trim. */\nexport function stripJsonFences(text: string): string {\n const trimmed = text.trim();\n const fenced = trimmed.match(/```(?:json)?\\s*([\\s\\S]*?)\\s*```/i);\n if (fenced) return fenced[1]!.trim();\n return trimmed.replace(/```(?:json)?\\s*/gi, \"\").replace(/```/g, \"\").trim();\n}\n\n/**\n * Parse a JSON array from free-form model output.\n * Returns null when no valid array can be extracted (distinct from `[]`).\n */\nexport function parseJsonArrayFromText(text: string): unknown[] | null {\n const cleaned = stripJsonFences(text);\n const start = cleaned.indexOf(\"[\");\n if (start === -1) return null;\n\n let depth = 0;\n let end = -1;\n for (let i = start; i < cleaned.length; i++) {\n if (cleaned[i] === \"[\") depth++;\n else if (cleaned[i] === \"]\") {\n depth--;\n if (depth === 0) {\n end = i;\n break;\n }\n }\n }\n if (end === -1) return null;\n\n try {\n const parsed = JSON.parse(cleaned.slice(start, end + 1));\n return Array.isArray(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n","/**\n * Smoke tests for the whimsy name drawer — run via `npm run test:whimsy`.\n * Kept as a separate tsup entry so the main CLI bundle stays single-file.\n */\n\nimport { createSeededRandom } from \"./seed.js\";\nimport { createFigureDrawer, WHIMSY_FIGURES, type WhimsyCategory } from \"./whimsy-names.js\";\nimport { resolveScenarioInput } from \"./scenarios.js\";\nimport { parseJsonArrayFromText, stripJsonFences } from \"../ai/json-response.js\";\n\nfunction assert(condition: boolean, message: string): void {\n if (!condition) {\n console.error(`FAIL: ${message}`);\n process.exit(1);\n }\n}\n\nfunction testNoRepeats(): void {\n const rng = createSeededRandom(42);\n const drawer = createFigureDrawer(rng);\n const seen = new Set<string>();\n let count = 0;\n for (let fig = drawer.next(); fig !== null; fig = drawer.next()) {\n const key = `${fig.first}|${fig.last}`;\n assert(!seen.has(key), `duplicate figure drawn: ${fig.first} ${fig.last}`);\n seen.add(key);\n count++;\n }\n assert(count === WHIMSY_FIGURES.length, `expected ${WHIMSY_FIGURES.length} unique draws, got ${count}`);\n}\n\nfunction testDeterministicOrder(): void {\n const draw = (seed: number) => {\n const drawer = createFigureDrawer(createSeededRandom(seed));\n return Array.from({ length: 5 }, () => {\n const f = drawer.next();\n return f ? `${f.first} ${f.last}` : \"\";\n });\n };\n assert(\n JSON.stringify(draw(7)) === JSON.stringify(draw(7)),\n \"same seed should produce identical rep name order\",\n );\n assert(\n JSON.stringify(draw(7)) !== JSON.stringify(draw(8)),\n \"different seeds should shuffle differently\",\n );\n}\n\nfunction testCategoryFilter(): void {\n const rng = createSeededRandom(123);\n const drawer = createFigureDrawer(rng, [\"music\"]);\n for (let fig = drawer.next(); fig !== null; fig = drawer.next()) {\n assert(fig.category === \"music\", `expected music, got ${fig.category} for ${fig.first} ${fig.last}`);\n }\n const musicCount = WHIMSY_FIGURES.filter((f) => f.category === \"music\").length;\n assert(musicCount > 0, \"music pool should not be empty\");\n}\n\nfunction testCategoriesPresent(): void {\n const categories: WhimsyCategory[] = [\"music\", \"sports\", \"film\"];\n for (const cat of categories) {\n assert(\n WHIMSY_FIGURES.some((f) => f.category === cat),\n `pool missing category: ${cat}`,\n );\n }\n}\n\nfunction testEmailSafeLastNames(): void {\n for (const fig of WHIMSY_FIGURES) {\n assert(!fig.last.includes(\" \"), `${fig.first} ${fig.last} has multi-word last name`);\n assert(fig.first.length > 0 && fig.last.length > 0, \"empty name part\");\n }\n}\n\nfunction testResolveScenarioInput(): void {\n assert(resolveScenarioInput(undefined) === undefined, \"blank -> random\");\n assert(resolveScenarioInput(\"hidden_crisis\") === \"hidden_crisis\", \"key passthrough\");\n assert(resolveScenarioInput(\"2\") === \"leaky_bucket\", \"2 -> second scenario\");\n assert(resolveScenarioInput(\"99\") === null, \"out of range -> invalid\");\n assert(resolveScenarioInput(\"not-a-scenario\") === null, \"garbage -> invalid\");\n}\n\nfunction testParseJsonArrayFromText(): void {\n assert(parseJsonArrayFromText(\"[]\")?.length === 0, \"empty array\");\n const fenced = parseJsonArrayFromText('Here you go:\\n```json\\n[{\"a\":1}]\\n```');\n assert(Array.isArray(fenced) && (fenced[0] as { a: number }).a === 1, \"fenced array\");\n assert(parseJsonArrayFromText(\"not json\") === null, \"garbage -> null\");\n const balanced = parseJsonArrayFromText('Note:\\n[{\"text\":\"$727K pipeline at risk\"}]');\n assert(Array.isArray(balanced) && balanced.length === 1, \"preamble + array\");\n assert(stripJsonFences(\"```json\\n[]\\n```\") === \"[]\", \"strip fences\");\n}\n\ntestNoRepeats();\ntestDeterministicOrder();\ntestCategoryFilter();\ntestCategoriesPresent();\ntestEmailSafeLastNames();\ntestResolveScenarioInput();\ntestParseJsonArrayFromText();\nconsole.log(`whimsy smoke passed (${WHIMSY_FIGURES.length} figures)`);\n"],"mappings":"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","names":[]}