continuous-improvement 3.1.0 → 3.8.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 (126) hide show
  1. package/.claude-plugin/marketplace.json +78 -0
  2. package/CHANGELOG.md +191 -0
  3. package/LICENSE +21 -21
  4. package/QUICKSTART.md +101 -81
  5. package/README.md +207 -359
  6. package/SKILL.md +87 -9
  7. package/action.yml +33 -33
  8. package/bin/analyze.sh +161 -153
  9. package/bin/backfill.mjs +172 -0
  10. package/bin/check-docs-substrings.mjs +333 -0
  11. package/bin/check-everything-mirror.mjs +145 -0
  12. package/bin/check-routing-targets.mjs +151 -0
  13. package/bin/check-skill-law-tag.mjs +128 -0
  14. package/bin/check-skill-mirror.mjs +119 -0
  15. package/bin/check-skill-tiers.mjs +116 -0
  16. package/bin/check-third-party-shape.mjs +202 -0
  17. package/bin/generate-plugin-manifests.mjs +169 -0
  18. package/bin/harvest-friction.mjs +279 -0
  19. package/bin/hook-stats.mjs +258 -0
  20. package/bin/install.mjs +417 -516
  21. package/bin/lint-transcript.mjs +182 -210
  22. package/bin/mcp-server.mjs +840 -617
  23. package/bin/observe.mjs +148 -0
  24. package/bin/pre-commit-block-strays.sh +49 -0
  25. package/bin/refresh-third-party.mjs +416 -0
  26. package/bin/unified-cli.mjs +533 -0
  27. package/commands/continuous-improvement.md +115 -74
  28. package/commands/dashboard.md +56 -56
  29. package/commands/discipline.md +51 -37
  30. package/commands/harvest.md +76 -0
  31. package/commands/learn-eval.md +117 -0
  32. package/commands/planning-with-files.md +66 -0
  33. package/commands/proceed-with-the-recommendation.md +62 -0
  34. package/commands/ralph.md +103 -0
  35. package/commands/release-train.md +81 -0
  36. package/commands/seven-laws.md +16 -0
  37. package/commands/superpowers.md +153 -0
  38. package/commands/swarm.md +101 -0
  39. package/commands/workspace-surface-audit.md +77 -0
  40. package/hooks/observe.sh +172 -134
  41. package/hooks/session.sh +106 -106
  42. package/hooks/three-section-close.mjs +181 -0
  43. package/instinct-packs/go.json +58 -58
  44. package/instinct-packs/meta.json +16 -0
  45. package/instinct-packs/python.json +58 -58
  46. package/instinct-packs/react.json +58 -58
  47. package/lib/cli-anything.mjs +401 -0
  48. package/lib/compound-engineering.mjs +831 -0
  49. package/lib/observe-event.mjs +128 -0
  50. package/lib/plugin-metadata.mjs +432 -0
  51. package/lib/pm-marketplace.mjs +61 -0
  52. package/lib/pm-skills.mjs +1274 -0
  53. package/lib/resolve-home-dir.mjs +43 -0
  54. package/lib/skill-tiers.mjs +137 -0
  55. package/lib/unified-plugin.mjs +924 -0
  56. package/llms.txt +68 -43
  57. package/package.json +28 -19
  58. package/plugins/beginner.json +17 -6
  59. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +20 -0
  60. package/plugins/continuous-improvement/.claude-plugin/plugin.json +26 -0
  61. package/plugins/continuous-improvement/LICENSE +21 -0
  62. package/plugins/continuous-improvement/README.md +56 -0
  63. package/plugins/continuous-improvement/bin/backfill.mjs +172 -0
  64. package/plugins/continuous-improvement/bin/mcp-server.mjs +886 -0
  65. package/plugins/continuous-improvement/bin/observe.mjs +148 -0
  66. package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -0
  67. package/plugins/continuous-improvement/commands/dashboard.md +56 -0
  68. package/plugins/continuous-improvement/commands/discipline.md +51 -0
  69. package/plugins/continuous-improvement/commands/harvest.md +76 -0
  70. package/plugins/continuous-improvement/commands/learn-eval.md +117 -0
  71. package/plugins/continuous-improvement/commands/planning-with-files.md +66 -0
  72. package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +62 -0
  73. package/plugins/continuous-improvement/commands/ralph.md +103 -0
  74. package/plugins/continuous-improvement/commands/release-train.md +81 -0
  75. package/plugins/continuous-improvement/commands/seven-laws.md +16 -0
  76. package/plugins/continuous-improvement/commands/superpowers.md +153 -0
  77. package/plugins/continuous-improvement/commands/swarm.md +101 -0
  78. package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -0
  79. package/plugins/continuous-improvement/hooks/hooks.json +60 -0
  80. package/plugins/continuous-improvement/hooks/observe.sh +172 -0
  81. package/plugins/continuous-improvement/hooks/session.sh +106 -0
  82. package/plugins/continuous-improvement/hooks/three-section-close.mjs +181 -0
  83. package/plugins/continuous-improvement/instinct-packs/go.json +58 -0
  84. package/plugins/continuous-improvement/instinct-packs/meta.json +16 -0
  85. package/plugins/continuous-improvement/instinct-packs/python.json +58 -0
  86. package/plugins/continuous-improvement/instinct-packs/react.json +58 -0
  87. package/plugins/continuous-improvement/lib/observe-event.mjs +128 -0
  88. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +432 -0
  89. package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +43 -0
  90. package/plugins/continuous-improvement/skills/README.md +34 -0
  91. package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +249 -0
  92. package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +131 -0
  93. package/plugins/continuous-improvement/skills/gateguard/SKILL.md +155 -0
  94. package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -0
  95. package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +454 -0
  96. package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -0
  97. package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -0
  98. package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -0
  99. package/plugins/continuous-improvement/skills/superpowers/SKILL.md +212 -0
  100. package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -0
  101. package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +136 -0
  102. package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +192 -0
  103. package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +191 -0
  104. package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +147 -0
  105. package/plugins/continuous-improvement/templates/planning-with-files/findings.md +8 -0
  106. package/plugins/continuous-improvement/templates/planning-with-files/progress.md +7 -0
  107. package/plugins/continuous-improvement/templates/planning-with-files/task_plan.md +23 -0
  108. package/plugins/expert.json +26 -5
  109. package/skills/README.md +79 -0
  110. package/skills/deploy-receipt.md +131 -0
  111. package/skills/gateguard.md +155 -0
  112. package/skills/para-memory-files.md +108 -0
  113. package/skills/proceed-with-the-recommendation.md +454 -0
  114. package/skills/ralph.md +221 -0
  115. package/skills/safety-guard.md +76 -0
  116. package/skills/strategic-compact.md +104 -0
  117. package/skills/superpowers.md +212 -0
  118. package/skills/tdd-workflow.md +411 -0
  119. package/skills/token-budget-advisor.md +136 -0
  120. package/skills/verification-loop.md +192 -0
  121. package/skills/wild-risa-balance.md +191 -0
  122. package/skills/workspace-surface-audit.md +147 -0
  123. package/templates/planning-with-files/findings.md +8 -0
  124. package/templates/planning-with-files/progress.md +7 -0
  125. package/templates/planning-with-files/task_plan.md +23 -0
  126. package/templates/verify-ladder.example.json +47 -0
@@ -0,0 +1,1274 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PM-Skills: collection of 8 product management plugins.
4
+ *
5
+ * Each skill accepts a loose input bag, normalizes it into a shared product
6
+ * context, and returns strategy output derived from that context.
7
+ */
8
+ import { mkdir, writeFile } from "node:fs/promises";
9
+ import { join } from "node:path";
10
+ const DEFAULT_OPTIONS = {
11
+ workspace: "./pm-workspace",
12
+ verbose: false,
13
+ };
14
+ function getErrorMessage(error) {
15
+ return error instanceof Error ? error.message : String(error);
16
+ }
17
+ function asArray(value) {
18
+ return Array.isArray(value) ? value : null;
19
+ }
20
+ function asRecord(value) {
21
+ return value && typeof value === "object" && !Array.isArray(value)
22
+ ? value
23
+ : null;
24
+ }
25
+ function getString(value, fallback = "") {
26
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
27
+ }
28
+ function getNumber(value) {
29
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
30
+ }
31
+ function titleCase(value) {
32
+ return value
33
+ .replace(/[_-]+/g, " ")
34
+ .split(/\s+/)
35
+ .filter(Boolean)
36
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
37
+ .join(" ");
38
+ }
39
+ function toSentenceKey(value) {
40
+ return value
41
+ .toLowerCase()
42
+ .replace(/[^a-z0-9]+/g, "_")
43
+ .replace(/^_+|_+$/g, "");
44
+ }
45
+ function uniqueStrings(values, limit = 12) {
46
+ const seen = new Set();
47
+ const result = [];
48
+ for (const value of values) {
49
+ const trimmed = value.trim();
50
+ if (!trimmed)
51
+ continue;
52
+ const key = trimmed.toLowerCase();
53
+ if (seen.has(key))
54
+ continue;
55
+ seen.add(key);
56
+ result.push(trimmed);
57
+ if (result.length >= limit)
58
+ break;
59
+ }
60
+ return result;
61
+ }
62
+ function extractNamedStrings(value) {
63
+ if (typeof value === "string") {
64
+ return value.trim() ? [value.trim()] : [];
65
+ }
66
+ if (Array.isArray(value)) {
67
+ return uniqueStrings(value.flatMap((item) => extractNamedStrings(item)));
68
+ }
69
+ const record = asRecord(value);
70
+ if (!record) {
71
+ return [];
72
+ }
73
+ return uniqueStrings([
74
+ getString(record.name),
75
+ getString(record.title),
76
+ getString(record.role),
77
+ getString(record.type),
78
+ getString(record.segment),
79
+ getString(record.feature),
80
+ getString(record.goal),
81
+ getString(record.benefit),
82
+ getString(record.pain),
83
+ getString(record.gain),
84
+ getString(record.statement),
85
+ getString(record.value),
86
+ ].filter(Boolean));
87
+ }
88
+ function mergeStringLists(...values) {
89
+ return uniqueStrings(values.flatMap((value) => extractNamedStrings(value)));
90
+ }
91
+ function parseIntegerFromString(value) {
92
+ const match = value.match(/(\d+)/);
93
+ return match ? Number.parseInt(match[1] ?? "", 10) : null;
94
+ }
95
+ function inferAudience(marketSegment, businessModel, userRoles) {
96
+ const combined = [marketSegment, businessModel, ...userRoles].join(" ").toLowerCase();
97
+ const b2bMarkers = ["smb", "enterprise", "team", "b2b", "manager", "developer", "admin"];
98
+ return b2bMarkers.some((marker) => combined.includes(marker)) ? "B2B" : "B2C";
99
+ }
100
+ function defaultGoals(productName, primaryBenefit) {
101
+ return [
102
+ `Increase adoption of ${productName}`,
103
+ `Improve retention through ${primaryBenefit.toLowerCase()}`,
104
+ "Create a repeatable revenue engine",
105
+ ];
106
+ }
107
+ function defaultFeatures(productType) {
108
+ const type = productType.toLowerCase();
109
+ if (type.includes("saas")) {
110
+ return ["workflow automation", "team collaboration", "usage analytics"];
111
+ }
112
+ if (type.includes("marketplace")) {
113
+ return ["trusted transactions", "supply matching", "rating system"];
114
+ }
115
+ return ["automation", "visibility", "guided onboarding"];
116
+ }
117
+ function defaultPains(audience, primaryFeature) {
118
+ if (audience === "B2B") {
119
+ return [
120
+ "Manual coordination slows delivery",
121
+ `Existing tools hide insight around ${primaryFeature.toLowerCase()}`,
122
+ "Teams cannot prove ROI quickly enough",
123
+ ];
124
+ }
125
+ return [
126
+ "Setup takes too long",
127
+ `Current options make ${primaryFeature.toLowerCase()} feel complicated`,
128
+ "Users churn before they see value",
129
+ ];
130
+ }
131
+ function defaultGains(audience, primaryBenefit) {
132
+ if (audience === "B2B") {
133
+ return [
134
+ primaryBenefit,
135
+ "Clearer team visibility",
136
+ "Faster time-to-value for the buying team",
137
+ ];
138
+ }
139
+ return [
140
+ primaryBenefit,
141
+ "Frictionless setup",
142
+ "Confidence that progress is improving",
143
+ ];
144
+ }
145
+ function defaultUserRoles(audience) {
146
+ return audience === "B2B"
147
+ ? ["operations manager", "product lead", "developer"]
148
+ : ["creator", "power user", "buyer"];
149
+ }
150
+ function normalizeCompetitors(input, industry) {
151
+ const market = asRecord(input.market);
152
+ const competitorsInput = asArray(input.competitors) ?? asArray(market?.competitors) ?? [];
153
+ const normalized = competitorsInput
154
+ .map((item, index) => {
155
+ const record = asRecord(item);
156
+ if (!record) {
157
+ const name = getString(item);
158
+ return name
159
+ ? {
160
+ name,
161
+ type: index === 0 ? "direct" : "indirect",
162
+ positioning: `Established option in ${industry.toLowerCase()}`,
163
+ features: [],
164
+ }
165
+ : null;
166
+ }
167
+ const name = getString(record.name);
168
+ if (!name)
169
+ return null;
170
+ const features = mergeStringLists(record.features, record.advantages, record.capabilities);
171
+ return {
172
+ name,
173
+ type: getString(record.type, index === 0 ? "direct" : "indirect"),
174
+ positioning: getString(record.positioning, `${titleCase(name)} targets adjacent ${industry.toLowerCase()} needs`),
175
+ features,
176
+ };
177
+ })
178
+ .filter((item) => item !== null);
179
+ if (normalized.length > 0) {
180
+ return normalized;
181
+ }
182
+ return [
183
+ {
184
+ name: `${titleCase(industry)} Suite Inc.`,
185
+ type: "direct",
186
+ positioning: `Broad incumbent serving ${industry.toLowerCase()} workflows`,
187
+ features: ["broad feature set", "enterprise controls"],
188
+ },
189
+ {
190
+ name: "Manual/In-house Workflow",
191
+ type: "indirect",
192
+ positioning: "Spreadsheets, email, and custom internal process",
193
+ features: ["low switching cost", "familiar workflow"],
194
+ },
195
+ ];
196
+ }
197
+ function buildSkillContext(input) {
198
+ const product = asRecord(input.product);
199
+ const market = asRecord(input.market);
200
+ const targetMarket = asRecord(input.targetMarket) ?? market;
201
+ const business = asRecord(input.business);
202
+ const customers = asRecord(input.customers);
203
+ const resources = asRecord(input.resources);
204
+ const researchData = asRecord(input.researchData);
205
+ const tentativeRoles = mergeStringLists(input.targetUsers, input.users);
206
+ const marketSegment = getString(targetMarket?.segment, getString(targetMarket?.market, getString(market?.segment, "SMB teams")));
207
+ const businessModel = getString(business?.model, getString(input.metrics, getString(market?.model, "Subscription")));
208
+ const audience = inferAudience(marketSegment, businessModel, tentativeRoles);
209
+ const productName = getString(product?.name, "Product");
210
+ const productType = getString(product?.type, audience === "B2B" ? "SaaS platform" : "digital product");
211
+ const productStage = getString(product?.stage, "Growth");
212
+ const industry = getString(input.industry, getString(market?.industry, "Technology"));
213
+ const budget = getString(input.budget, "$50,000");
214
+ const timeline = getString(input.timeline, "12 weeks");
215
+ const companySize = getString(targetMarket?.size, getString(resources?.team, "Mid-size"));
216
+ const goals = mergeStringLists(input.goals, product?.goals, input.objective);
217
+ const features = mergeStringLists(product?.features, input.features);
218
+ const benefits = mergeStringLists(product?.benefits, input.benefits, customers?.gains);
219
+ const userRoles = uniqueStrings(tentativeRoles.length > 0 ? tentativeRoles : defaultUserRoles(audience), 3);
220
+ const primaryRole = titleCase(userRoles[0] ?? "User");
221
+ const normalizedFeatures = features.length > 0 ? features : defaultFeatures(productType);
222
+ const primaryFeature = normalizedFeatures[0] ?? "automation";
223
+ const normalizedBenefits = benefits.length > 0
224
+ ? benefits
225
+ : [
226
+ audience === "B2B"
227
+ ? `More predictable ${primaryFeature.toLowerCase()} execution`
228
+ : `Faster ${primaryFeature.toLowerCase()} outcomes`,
229
+ ];
230
+ const primaryBenefit = normalizedBenefits[0];
231
+ const pains = mergeStringLists(input.pains, customers?.pains);
232
+ const normalizedPains = pains.length > 0 ? pains : defaultPains(audience, primaryFeature);
233
+ const gains = mergeStringLists(input.gains, customers?.gains, normalizedBenefits);
234
+ const normalizedGains = gains.length > 0 ? gains : defaultGains(audience, primaryBenefit);
235
+ const normalizedGoals = goals.length > 0 ? goals : defaultGoals(productName, primaryBenefit);
236
+ const primaryGoal = normalizedGoals[0];
237
+ const primaryPain = normalizedPains[0];
238
+ const primaryGain = normalizedGains[0];
239
+ const interviews = getNumber(researchData?.interviews) ?? 0;
240
+ const surveys = getNumber(researchData?.surveys) ?? 0;
241
+ const resourcesTeamSize = getNumber(resources?.team) ??
242
+ parseIntegerFromString(getString(resources?.team, "")) ??
243
+ parseIntegerFromString(getString(companySize, ""));
244
+ const competitors = normalizeCompetitors(input, industry);
245
+ const vision = getString(input.vision, `Become the trusted ${industry.toLowerCase()} platform for ${marketSegment.toLowerCase()}`);
246
+ return {
247
+ audience,
248
+ benefits: normalizedBenefits,
249
+ budget,
250
+ businessModel,
251
+ companySize,
252
+ competitors,
253
+ features: normalizedFeatures,
254
+ gains: normalizedGains,
255
+ goals: normalizedGoals,
256
+ industry,
257
+ marketSegment,
258
+ pains: normalizedPains,
259
+ primaryBenefit,
260
+ primaryFeature,
261
+ primaryGain,
262
+ primaryGoal,
263
+ primaryPain,
264
+ primaryRole,
265
+ productName,
266
+ productStage,
267
+ productType,
268
+ researchVolume: interviews + surveys,
269
+ resourcesTeamSize,
270
+ timeline,
271
+ userRoles,
272
+ vision,
273
+ };
274
+ }
275
+ function splitTimeline(totalDuration) {
276
+ const totalWeeks = parseIntegerFromString(totalDuration);
277
+ if (!totalWeeks || totalWeeks < 4) {
278
+ return {
279
+ preparation: "2 weeks",
280
+ launch: "1 week",
281
+ growth: "4 weeks",
282
+ };
283
+ }
284
+ const preparation = Math.max(2, Math.round(totalWeeks * 0.25));
285
+ const launch = Math.max(1, Math.round(totalWeeks * 0.15));
286
+ const growth = Math.max(2, totalWeeks - preparation - launch);
287
+ return {
288
+ preparation: `${preparation} week${preparation === 1 ? "" : "s"}`,
289
+ launch: `${launch} week${launch === 1 ? "" : "s"}`,
290
+ growth: `${growth} week${growth === 1 ? "" : "s"}`,
291
+ };
292
+ }
293
+ function buildPrimaryKpis(ctx) {
294
+ const goalText = ctx.goals.join(" ").toLowerCase();
295
+ const primary = [];
296
+ if (goalText.includes("revenue") || goalText.includes("arr") || goalText.includes("mrr")) {
297
+ primary.push({ metric: "monthly_recurring_growth", target: "15-20%", timeframe: "monthly" });
298
+ }
299
+ if (goalText.includes("retain") || goalText.includes("churn")) {
300
+ primary.push({ metric: "logo_retention_rate", target: "85%+", timeframe: "monthly" });
301
+ }
302
+ if (goalText.includes("user") || goalText.includes("adoption") || goalText.includes("acquisition")) {
303
+ primary.push({ metric: "activation_rate", target: "45%+", timeframe: "monthly" });
304
+ }
305
+ if (primary.length === 0) {
306
+ primary.push({ metric: "activation_rate", target: "40%+", timeframe: "monthly" }, { metric: "retention_rate", target: "80%+", timeframe: "monthly" });
307
+ }
308
+ return primary.slice(0, 2);
309
+ }
310
+ function buildGrowthLoopsResult(ctx) {
311
+ const acquisitionName = ctx.audience === "B2B" ? "Problem-led pipeline" : "Content-led discovery";
312
+ const referralName = ctx.audience === "B2B" ? "Team expansion loop" : "Social proof referral";
313
+ return {
314
+ loops: {
315
+ acquisition: [
316
+ {
317
+ name: acquisitionName,
318
+ description: `Attract ${ctx.marketSegment.toLowerCase()} users by framing the cost of ${ctx.primaryPain.toLowerCase()}`,
319
+ steps: [
320
+ `Surface the problem: ${ctx.primaryPain}`,
321
+ `Show how ${ctx.productName} improves ${ctx.primaryBenefit.toLowerCase()}`,
322
+ `Convert ${ctx.primaryRole.toLowerCase()} into a qualified trial`,
323
+ "Capture onboarding and qualification signals",
324
+ ],
325
+ metrics: uniqueStrings([
326
+ ctx.audience === "B2B" ? "qualified_pipeline" : "signup_rate",
327
+ "landing_page_conversion",
328
+ "trial_start_rate",
329
+ ]),
330
+ },
331
+ ],
332
+ activation: [
333
+ {
334
+ name: "First-value onboarding",
335
+ description: `Help new users reach ${ctx.primaryGain.toLowerCase()} in the first session`,
336
+ steps: [
337
+ `Guide ${ctx.primaryRole.toLowerCase()} to the core feature`,
338
+ `Remove setup friction around ${ctx.primaryFeature.toLowerCase()}`,
339
+ "Confirm value with a visible success moment",
340
+ "Prompt the next action before drop-off",
341
+ ],
342
+ metrics: uniqueStrings(["time_to_value", "activation_rate", "setup_completion"]),
343
+ },
344
+ ],
345
+ retention: [
346
+ {
347
+ name: "Habit and workflow retention",
348
+ description: `Turn ${ctx.primaryFeature.toLowerCase()} into a repeated workflow`,
349
+ steps: [
350
+ "Create a recurring use case",
351
+ "Expose progress and saved effort",
352
+ "Prompt repeat engagement at the right moment",
353
+ "Reinforce the outcome with reporting or reminders",
354
+ ],
355
+ metrics: uniqueStrings(["retention_rate", "weekly_active_accounts", "feature_adoption"]),
356
+ },
357
+ ],
358
+ referral: [
359
+ {
360
+ name: referralName,
361
+ description: `Use delivered value to drive expansion beyond the first ${ctx.primaryRole.toLowerCase()}`,
362
+ steps: [
363
+ "Deliver visible outcome",
364
+ "Prompt invite, share, or stakeholder proof",
365
+ "Extend value to adjacent teammates or peers",
366
+ "Increase product utility as usage expands",
367
+ ],
368
+ metrics: uniqueStrings(["invite_rate", "expansion_accounts", "referral_conversion"]),
369
+ },
370
+ ],
371
+ revenue: [
372
+ {
373
+ name: "Value-to-revenue expansion",
374
+ description: `Map revenue growth to clearer proof of ${ctx.primaryBenefit.toLowerCase()}`,
375
+ steps: [
376
+ "Deliver measurable value",
377
+ "Expose usage or ROI threshold",
378
+ "Trigger upgrade or expansion motion",
379
+ "Reinvest customer success proof into retention",
380
+ ],
381
+ metrics: uniqueStrings([
382
+ ctx.businessModel.toLowerCase().includes("usage") ? "usage_expansion" : "expansion_mrr",
383
+ "paid_conversion_rate",
384
+ "customer_lifetime_value",
385
+ ]),
386
+ },
387
+ ],
388
+ },
389
+ insights: [
390
+ `${ctx.productStage} products compound faster when acquisition promises match activation value.`,
391
+ `${ctx.primaryRole} is the critical first user because they feel ${ctx.primaryPain.toLowerCase()} most directly.`,
392
+ `${ctx.businessModel} monetization works best when revenue expansion is tied to visible proof of ${ctx.primaryBenefit.toLowerCase()}.`,
393
+ ],
394
+ recommendations: [
395
+ `Design the first-run experience around solving ${ctx.primaryPain.toLowerCase()}.`,
396
+ `Instrument activation around ${ctx.primaryFeature.toLowerCase()} instead of generic engagement.`,
397
+ `Build expansion prompts after users experience ${ctx.primaryBenefit.toLowerCase()}.`,
398
+ ],
399
+ kpis: {
400
+ acquisition: uniqueStrings(["qualified_pipeline", "signup_rate", "trial_start_rate"], 3),
401
+ activation: uniqueStrings(["activation_rate", "time_to_value", "setup_completion"], 3),
402
+ retention: uniqueStrings(["retention_rate", "feature_adoption", "weekly_active_accounts"], 3),
403
+ referral: uniqueStrings(["invite_rate", "referral_conversion", "team_expansion"], 3),
404
+ revenue: uniqueStrings(["paid_conversion_rate", "net_revenue_retention", "customer_lifetime_value"], 3),
405
+ },
406
+ timestamp: new Date().toISOString(),
407
+ };
408
+ }
409
+ function buildMarketResearchResult(ctx) {
410
+ const opportunities = uniqueStrings([
411
+ `Position ${ctx.productName} around faster ${ctx.primaryBenefit.toLowerCase()}`,
412
+ `Serve ${ctx.marketSegment.toLowerCase()} teams that are unhappy with broad suites`,
413
+ `Own a wedge around ${ctx.primaryFeature.toLowerCase()} before category leaders react`,
414
+ ]);
415
+ const risks = uniqueStrings([
416
+ ctx.competitors.length > 1
417
+ ? "Incumbents can bundle overlapping features into larger suites"
418
+ : "The category may still need proof that the problem is urgent enough to switch",
419
+ `${ctx.productStage} execution risk could slow customer trust`,
420
+ `Buyers may compare ${ctx.productName} against in-house or manual workflows`,
421
+ ]);
422
+ return {
423
+ research: {
424
+ marketSize: {
425
+ tam: `${ctx.industry} organizations that need ${ctx.primaryBenefit.toLowerCase()}`,
426
+ sam: `${ctx.marketSegment} teams willing to adopt a focused ${ctx.productType.toLowerCase()}`,
427
+ som: `${ctx.marketSegment} buyers reachable within the current ${ctx.timeline} plan`,
428
+ methodology: `Bottom-up demand model anchored on ${ctx.primaryPain.toLowerCase()}`,
429
+ sources: [
430
+ `${ctx.industry} budget trends`,
431
+ `${ctx.marketSegment} workflow pain patterns`,
432
+ "Competitor positioning and customer reviews",
433
+ ],
434
+ },
435
+ trends: [
436
+ {
437
+ trend: `${ctx.industry} workflow consolidation`,
438
+ impact: "High",
439
+ timeline: ctx.timeline,
440
+ description: `Buyers want fewer tools with faster proof of ${ctx.primaryBenefit.toLowerCase()}.`,
441
+ },
442
+ {
443
+ trend: ctx.audience === "B2B" ? "Self-serve evaluation before sales contact" : "Instant onboarding expectations",
444
+ impact: "High",
445
+ timeline: "Next 2 quarters",
446
+ description: `${ctx.primaryRole} expects to validate value before deep commitment.`,
447
+ },
448
+ {
449
+ trend: `Operational visibility around ${ctx.primaryFeature.toLowerCase()}`,
450
+ impact: "Medium",
451
+ timeline: "Ongoing",
452
+ description: "Products that surface measurable outcomes are winning trust faster.",
453
+ },
454
+ ],
455
+ competitors: {
456
+ directCompetitors: ctx.competitors.filter((competitor) => competitor.type !== "indirect"),
457
+ indirectCompetitors: ctx.competitors.filter((competitor) => competitor.type === "indirect"),
458
+ marketShare: ctx.competitors.length > 2
459
+ ? "Fragmented market with room for differentiated execution"
460
+ : "Concentrated alternatives with a clear gap for focused positioning",
461
+ positioning: `${ctx.productName} can win by focusing on ${ctx.primaryBenefit.toLowerCase()} for ${ctx.marketSegment.toLowerCase()}.`,
462
+ },
463
+ opportunities,
464
+ threats: risks,
465
+ customerNeeds: {
466
+ painPoints: ctx.pains,
467
+ gains: ctx.gains,
468
+ jobsToBeDone: uniqueStrings([
469
+ ...ctx.goals,
470
+ `Adopt ${ctx.primaryFeature.toLowerCase()} without long setup`,
471
+ `Prove ROI from ${ctx.productName} quickly`,
472
+ ]),
473
+ },
474
+ },
475
+ insights: [
476
+ `${ctx.marketSegment} buyers are most likely to switch when they see a faster path to ${ctx.primaryBenefit.toLowerCase()}.`,
477
+ `Competitive pressure is strongest around broad feature coverage, not focused execution for ${ctx.primaryRole.toLowerCase()}.`,
478
+ `Market traction will depend on whether ${ctx.productName} feels lower-risk than manual or suite-based alternatives.`,
479
+ ],
480
+ recommendations: [
481
+ `Prioritize messaging that quantifies the cost of ${ctx.primaryPain.toLowerCase()}.`,
482
+ `Track competitor claims around ${ctx.primaryFeature.toLowerCase()} and answer them with clearer proof.`,
483
+ `Use customer research to validate which ${ctx.marketSegment.toLowerCase()} segment converts fastest.`,
484
+ ],
485
+ risks,
486
+ opportunities,
487
+ timestamp: new Date().toISOString(),
488
+ };
489
+ }
490
+ function buildGTMStrategyResult(ctx) {
491
+ const channelPrimary = ctx.audience === "B2B"
492
+ ? ["Founder-led sales", "Case-study content", "Partner introductions"]
493
+ : ["Product-led onboarding", "Creator content", "Community distribution"];
494
+ const channelSecondary = ctx.audience === "B2B"
495
+ ? ["Webinars", "Account-based outreach"]
496
+ : ["Referral program", "Lifecycle email"];
497
+ const split = splitTimeline(ctx.timeline);
498
+ const pricingTiers = ctx.businessModel.toLowerCase().includes("usage")
499
+ ? [
500
+ { name: "Base", price: "$0 setup + usage", features: ["Core workflow", "Usage tracking"] },
501
+ { name: "Scale", price: "Usage + platform fee", features: ["Team controls", "Advanced reporting"] },
502
+ ]
503
+ : [
504
+ { name: "Starter", price: "$29/month", features: [ctx.primaryFeature, "Core onboarding"] },
505
+ { name: "Growth", price: "$99/month", features: ["Team workflows", "Advanced analytics"] },
506
+ { name: "Scale", price: "Custom", features: ["Security controls", "Implementation support"] },
507
+ ];
508
+ const budgetAllocation = ctx.audience === "B2B"
509
+ ? { marketing: "30%", sales: "35%", product: "25%", operations: "10%" }
510
+ : { marketing: "45%", growth: "25%", product: "20%", operations: "10%" };
511
+ return {
512
+ strategy: {
513
+ positioning: {
514
+ statement: `For ${ctx.marketSegment} teams that need to solve ${ctx.primaryPain.toLowerCase()}, ${ctx.productName} is a ${ctx.productType.toLowerCase()} that delivers ${ctx.primaryBenefit.toLowerCase()}.`,
515
+ differentiation: `Focused execution for ${ctx.primaryRole.toLowerCase()} instead of broad but slower suites.`,
516
+ valueProposition: `${ctx.productName} helps teams reach ${ctx.primaryGain.toLowerCase()} with less friction.`,
517
+ messaging: `Lead with the cost of ${ctx.primaryPain.toLowerCase()}, prove ${ctx.primaryBenefit.toLowerCase()}, then show the expansion path.`,
518
+ },
519
+ pricing: {
520
+ model: ctx.businessModel,
521
+ tiers: pricingTiers,
522
+ strategy: `Price against measurable value from ${ctx.primaryFeature.toLowerCase()} adoption.`,
523
+ revenue: `Use ${ctx.businessModel.toLowerCase()} expansion to grow after activation is proven.`,
524
+ },
525
+ channels: {
526
+ primary: channelPrimary,
527
+ secondary: channelSecondary,
528
+ channels: channelPrimary.map((name, index) => ({
529
+ name,
530
+ cost: index === 0 ? "Medium" : "Low",
531
+ reach: ctx.audience === "B2B" ? "Focused" : "Scalable",
532
+ conversion: index === 0 ? "High" : "Medium",
533
+ })),
534
+ },
535
+ launch: {
536
+ phases: [
537
+ { phase: "Pre-launch", duration: split.preparation, activities: ["Message testing", "Design partner validation"] },
538
+ { phase: "Launch", duration: split.launch, activities: ["Public release", "Sales and support enablement"] },
539
+ { phase: "Expansion", duration: split.growth, activities: ["Retention optimization", "Channel scaling"] },
540
+ ],
541
+ activities: `Sequence launch around fast proof of ${ctx.primaryBenefit.toLowerCase()}.`,
542
+ success: `Hit activation and pipeline goals before broadening spend.`,
543
+ },
544
+ sales: {
545
+ approach: ctx.audience === "B2B" ? "Product-led growth with sales assist for expansion" : "Self-serve conversion with lifecycle nudges",
546
+ team: ctx.audience === "B2B" ? "Founder/AE + customer success loop" : "Growth + lifecycle marketing loop",
547
+ process: `Qualify around ${ctx.primaryPain.toLowerCase()}, close on measurable outcomes, expand on adoption.`,
548
+ tools: "CRM, lifecycle automation, and product analytics",
549
+ },
550
+ marketing: {
551
+ awareness: uniqueStrings([
552
+ `${ctx.primaryPain} problem framing`,
553
+ "Case studies",
554
+ "Thoughtful product education",
555
+ ]),
556
+ consideration: uniqueStrings([
557
+ "Interactive demo",
558
+ `${ctx.primaryFeature} proof`,
559
+ "Customer references",
560
+ ]),
561
+ conversion: uniqueStrings([
562
+ "Free trial",
563
+ "ROI proof",
564
+ ctx.audience === "B2B" ? "Sales-assisted close" : "In-product upgrade prompt",
565
+ ]),
566
+ retention: uniqueStrings([
567
+ "Customer success onboarding",
568
+ "Lifecycle education",
569
+ "Expansion playbooks",
570
+ ]),
571
+ },
572
+ },
573
+ insights: [
574
+ `${ctx.productName} should launch with a narrow message tied to ${ctx.primaryBenefit.toLowerCase()}.`,
575
+ `${ctx.audience} go-to-market will work best when qualification starts with ${ctx.primaryPain.toLowerCase()}.`,
576
+ `Budget should scale only after the team proves repeatable conversion inside the first ${ctx.timeline}.`,
577
+ ],
578
+ recommendations: [
579
+ "Test positioning with a small number of design partners before broader spend.",
580
+ `Anchor pricing to visible value from ${ctx.primaryFeature.toLowerCase()}.`,
581
+ "Treat activation metrics as the gate before expanding channels.",
582
+ ],
583
+ timeline: {
584
+ totalDuration: ctx.timeline,
585
+ phases: {
586
+ preparation: split.preparation,
587
+ launch: split.launch,
588
+ growth: split.growth,
589
+ },
590
+ milestones: uniqueStrings([
591
+ "Validated positioning",
592
+ "First activated cohort",
593
+ "Repeatable conversion motion",
594
+ ]),
595
+ },
596
+ budget: {
597
+ total: ctx.budget,
598
+ allocation: budgetAllocation,
599
+ },
600
+ kpis: {
601
+ acquisition: uniqueStrings(["qualified_pipeline", "signup_rate", "cost_per_qualified_user"], 3),
602
+ revenue: uniqueStrings(["mrr", "arr", "net_revenue_retention"], 3),
603
+ engagement: uniqueStrings(["activation_rate", "retention_rate", "feature_adoption"], 3),
604
+ brand: uniqueStrings(["share_of_voice", "demo_requests", "case_study_pull_through"], 3),
605
+ },
606
+ timestamp: new Date().toISOString(),
607
+ };
608
+ }
609
+ function roleDefaults(role, ctx) {
610
+ const normalizedRole = role.toLowerCase();
611
+ if (normalizedRole.includes("manager") || normalizedRole.includes("lead")) {
612
+ return {
613
+ goals: uniqueStrings([ctx.primaryGoal, "Increase team throughput", "Reduce coordination drag"], 3),
614
+ painPoints: uniqueStrings([ctx.primaryPain, "Poor visibility into progress", "Hard to prove ROI"], 3),
615
+ behaviors: ["Uses dashboards", "Shares decisions across the team", "Needs stakeholder proof"],
616
+ needs: uniqueStrings([ctx.primaryBenefit, "Clear reporting", "Simple rollout"], 3),
617
+ };
618
+ }
619
+ if (normalizedRole.includes("developer") || normalizedRole.includes("engineer")) {
620
+ return {
621
+ goals: uniqueStrings([ctx.primaryGoal, "Ship reliably", "Reduce manual steps"], 3),
622
+ painPoints: uniqueStrings([ctx.primaryPain, "Tool sprawl", "Interruptions during delivery"], 3),
623
+ behaviors: ["Prefers automation", "Validates details independently", "Dislikes vague workflows"],
624
+ needs: uniqueStrings(["Low-friction setup", ctx.primaryFeature, "Clear technical documentation"], 3),
625
+ };
626
+ }
627
+ return {
628
+ goals: uniqueStrings([ctx.primaryGoal, `Achieve ${ctx.primaryBenefit.toLowerCase()}`], 3),
629
+ painPoints: uniqueStrings([ctx.primaryPain, "Too many steps before value"], 3),
630
+ behaviors: ["Learns by doing", "Values clarity", "Needs visible progress"],
631
+ needs: uniqueStrings([ctx.primaryBenefit, "Fast onboarding", "Trust signals"], 3),
632
+ };
633
+ }
634
+ function buildUserPersonasResult(ctx) {
635
+ const personas = ctx.userRoles.map((role) => {
636
+ const defaults = roleDefaults(role, ctx);
637
+ return {
638
+ name: `${titleCase(role)} Champion`,
639
+ role: titleCase(role),
640
+ demographics: {
641
+ company: ctx.companySize,
642
+ industry: ctx.industry,
643
+ experience: ctx.productStage === "MVP" ? "Early adopter mindset" : "Process-oriented operator",
644
+ },
645
+ goals: defaults.goals,
646
+ painPoints: defaults.painPoints,
647
+ behaviors: defaults.behaviors,
648
+ needs: defaults.needs,
649
+ researchBasis: `${ctx.researchVolume || 1} research signal(s) informing this persona`,
650
+ };
651
+ });
652
+ const journeys = personas.map((persona) => ({
653
+ persona: persona.name,
654
+ stages: [
655
+ {
656
+ stage: "Awareness",
657
+ actions: [
658
+ `Recognizes the cost of ${ctx.primaryPain.toLowerCase()}`,
659
+ `Looks for a faster path to ${ctx.primaryBenefit.toLowerCase()}`,
660
+ ],
661
+ emotions: ["Frustrated", "Hopeful"],
662
+ touchpoints: ["Search", "Peer referral", "Thought leadership"],
663
+ },
664
+ {
665
+ stage: "Evaluation",
666
+ actions: [
667
+ `Tests whether ${ctx.productName} fits ${persona.role.toLowerCase()} workflows`,
668
+ "Compares against existing tools or manual process",
669
+ ],
670
+ emotions: ["Curious", "Skeptical"],
671
+ touchpoints: ["Product demo", "Case study", "Trial environment"],
672
+ },
673
+ {
674
+ stage: "Adoption",
675
+ actions: [
676
+ "Rolls out the first use case",
677
+ "Measures visible gains",
678
+ "Invites or proves value to stakeholders",
679
+ ],
680
+ emotions: ["Confident", "Relieved"],
681
+ touchpoints: ["Onboarding", "Support", "Success review"],
682
+ },
683
+ ],
684
+ }));
685
+ return {
686
+ personas,
687
+ journeys,
688
+ insights: [
689
+ `${ctx.userRoles.length} distinct persona lens(es) matter for ${ctx.productName}.`,
690
+ `${ctx.primaryRole} will buy or adopt faster when messaging starts with ${ctx.primaryPain.toLowerCase()}.`,
691
+ `Persona design should reflect the ${ctx.timeline} adoption window and ${ctx.productStage} maturity.`,
692
+ ],
693
+ recommendations: [
694
+ `Design the onboarding path around ${ctx.primaryRole.toLowerCase()} first.`,
695
+ "Use persona-specific proof points in lifecycle messaging.",
696
+ "Validate persona assumptions continuously with interviews and product usage data.",
697
+ ],
698
+ timestamp: new Date().toISOString(),
699
+ };
700
+ }
701
+ function buildCompetitiveAnalysisResult(ctx) {
702
+ const directCompetitors = ctx.competitors.filter((competitor) => competitor.type !== "indirect");
703
+ const productStrengths = uniqueStrings([
704
+ `Focused on ${ctx.primaryBenefit.toLowerCase()}`,
705
+ `Simpler adoption path for ${ctx.primaryRole.toLowerCase()}`,
706
+ ctx.primaryFeature,
707
+ ]);
708
+ const productWeaknesses = uniqueStrings([
709
+ ctx.productStage === "MVP"
710
+ ? "Smaller reference base than incumbents"
711
+ : "Execution discipline must stay ahead of broader suites",
712
+ "Limited room for vague positioning",
713
+ `Can be compared against manual alternatives if ${ctx.primaryBenefit.toLowerCase()} is not obvious`,
714
+ ]);
715
+ return {
716
+ analysis: {
717
+ directCompetitors: directCompetitors.map((competitor) => ({
718
+ name: competitor.name,
719
+ product: competitor.positioning,
720
+ strengths: uniqueStrings([
721
+ ...competitor.features,
722
+ competitor.type === "direct" ? "Known brand presence" : "Low switching friction",
723
+ ], 3),
724
+ weaknesses: uniqueStrings([
725
+ `Less focused on ${ctx.primaryRole.toLowerCase()}`,
726
+ `Harder to prove ${ctx.primaryBenefit.toLowerCase()} quickly`,
727
+ ], 3),
728
+ marketShare: competitor.type === "direct" ? "Meaningful" : "Diffuse",
729
+ pricing: competitor.type === "direct" ? "Bundle or enterprise pricing" : "Low explicit cost",
730
+ })),
731
+ indirectCompetitors: ctx.competitors
732
+ .filter((competitor) => competitor.type === "indirect")
733
+ .map((competitor) => ({
734
+ name: competitor.name,
735
+ type: competitor.type,
736
+ threat: "Medium",
737
+ description: competitor.positioning,
738
+ })),
739
+ positioning: {
740
+ position: `${ctx.productName} should own the focused category around ${ctx.primaryFeature.toLowerCase()}.`,
741
+ differentiation: `Deliver ${ctx.primaryBenefit.toLowerCase()} faster than broader alternatives.`,
742
+ advantages: productStrengths,
743
+ disadvantages: productWeaknesses,
744
+ },
745
+ strengths: productStrengths,
746
+ weaknesses: productWeaknesses,
747
+ opportunities: uniqueStrings([
748
+ `Exploit gaps where competitors under-serve ${ctx.marketSegment.toLowerCase()} teams.`,
749
+ `Use faster onboarding as a wedge against slower suite deployment.`,
750
+ `Win on proof of ${ctx.primaryBenefit.toLowerCase()} rather than raw feature count.`,
751
+ ]),
752
+ threats: uniqueStrings([
753
+ "Incumbents may copy a narrow wedge once traction appears.",
754
+ "Price competition can increase if positioning becomes generic.",
755
+ "Manual or in-house workflows can slow category adoption.",
756
+ ]),
757
+ },
758
+ insights: [
759
+ `Competitive advantage will come from clarity and speed around ${ctx.primaryBenefit.toLowerCase()}.`,
760
+ `${ctx.productName} should avoid fighting incumbents on breadth before it wins on focused value.`,
761
+ `${ctx.primaryRole} is the buyer most likely to notice the difference between focused execution and generic feature volume.`,
762
+ ],
763
+ recommendations: [
764
+ "Document a competitor-by-competitor rebuttal for the top buying objections.",
765
+ `Show how ${ctx.productName} reduces the time between signup and ${ctx.primaryGain.toLowerCase()}.`,
766
+ "Use customer proof to defend against bundle and price pressure.",
767
+ ],
768
+ timestamp: new Date().toISOString(),
769
+ };
770
+ }
771
+ function buildValuePropositionResult(ctx) {
772
+ return {
773
+ analysis: {
774
+ customerJobs: uniqueStrings([
775
+ ...ctx.goals,
776
+ `Reach ${ctx.primaryBenefit.toLowerCase()} without heavy process change`,
777
+ ]),
778
+ pains: ctx.pains,
779
+ gains: ctx.gains,
780
+ products: {
781
+ painRelievers: uniqueStrings([
782
+ `Automates or simplifies ${ctx.primaryFeature.toLowerCase()}`,
783
+ `Removes friction around ${ctx.primaryPain.toLowerCase()}`,
784
+ "Makes progress visible to stakeholders",
785
+ ]),
786
+ gainCreators: uniqueStrings([
787
+ ctx.primaryBenefit,
788
+ ctx.primaryGain,
789
+ "Shorter time-to-value",
790
+ ]),
791
+ },
792
+ valueProposition: {
793
+ headline: `${ctx.productName} helps ${ctx.primaryRole.toLowerCase()} teams achieve ${ctx.primaryBenefit.toLowerCase()}.`,
794
+ subheading: `Replace ${ctx.primaryPain.toLowerCase()} with a clearer path to ${ctx.primaryGain.toLowerCase()}.`,
795
+ benefits: uniqueStrings([
796
+ ...ctx.benefits,
797
+ "Faster adoption across the buying team",
798
+ "Clearer proof of impact",
799
+ ], 4),
800
+ features: ctx.features.slice(0, 4),
801
+ },
802
+ validation: {
803
+ methods: ctx.researchVolume > 0
804
+ ? ["Customer interviews", "Usage review", "Message testing"]
805
+ : ["Discovery interviews", "Landing page tests", "Prototype demos"],
806
+ metrics: uniqueStrings(["message_resonance", "activation_rate", "sales_cycle_length"], 3),
807
+ timeline: ctx.timeline,
808
+ },
809
+ },
810
+ insights: [
811
+ `The strongest value proposition starts with the cost of ${ctx.primaryPain.toLowerCase()}.`,
812
+ `${ctx.primaryRole} will adopt faster when ${ctx.productName} feels easier to trust than incumbent options.`,
813
+ `Benefits should be framed as measurable progress toward ${ctx.primaryGoal.toLowerCase()}.`,
814
+ ],
815
+ recommendations: [
816
+ "Lead with the problem and quantified gain before feature detail.",
817
+ `Use ${ctx.primaryFeature.toLowerCase()} as the proof mechanism for the broader promise.`,
818
+ "Validate message resonance with both buyers and end users before scaling spend.",
819
+ ],
820
+ timestamp: new Date().toISOString(),
821
+ };
822
+ }
823
+ function buildRoadmapInitiatives(ctx) {
824
+ return [
825
+ {
826
+ name: `Accelerate ${ctx.primaryFeature}`,
827
+ priority: "High",
828
+ impact: `Make ${ctx.primaryBenefit.toLowerCase()} easier to realize`,
829
+ effort: "Medium",
830
+ timeline: "Quarter 1",
831
+ },
832
+ {
833
+ name: `Deepen retention around ${ctx.primaryRole}`,
834
+ priority: "High",
835
+ impact: "Improve repeat engagement and expansion readiness",
836
+ effort: "Medium",
837
+ timeline: "Quarter 2",
838
+ },
839
+ {
840
+ name: "Instrument proof and reporting",
841
+ priority: "Medium",
842
+ impact: "Give the team stronger ROI evidence for growth and sales",
843
+ effort: "Low",
844
+ timeline: "Quarter 3",
845
+ },
846
+ ];
847
+ }
848
+ function buildProductRoadmapResult(ctx) {
849
+ const initiatives = buildRoadmapInitiatives(ctx);
850
+ const nowFeatures = uniqueStrings([ctx.primaryFeature, ctx.features[1] ?? "", "activation instrumentation"], 3);
851
+ const nextFeatures = uniqueStrings(["retention playbooks", "team expansion workflow", ctx.features[2] ?? ""], 3);
852
+ const laterFeatures = uniqueStrings(["advanced reporting", "predictive insights", "ecosystem integrations"], 3);
853
+ return {
854
+ roadmap: {
855
+ vision: {
856
+ statement: ctx.vision,
857
+ timeline: ctx.timeline,
858
+ impact: `Create a durable position in ${ctx.industry.toLowerCase()} by owning ${ctx.primaryBenefit.toLowerCase()}.`,
859
+ metrics: uniqueStrings(["activation_rate", "retention_rate", "net_revenue_retention"], 3),
860
+ },
861
+ strategy: {
862
+ approach: `${ctx.productStage} roadmap focused on adoption before breadth.`,
863
+ focus: `Win the wedge around ${ctx.primaryFeature.toLowerCase()} and expand from there.`,
864
+ differentiation: `Stay easier to adopt for ${ctx.primaryRole.toLowerCase()} than broader competitors.`,
865
+ markets: uniqueStrings([ctx.marketSegment, `${ctx.marketSegment} adjacent buyers`], 2),
866
+ },
867
+ initiatives,
868
+ features: {
869
+ now: nowFeatures.map((feature) => ({ feature, priority: "High" })),
870
+ next: nextFeatures.map((feature) => ({ feature, priority: "Medium" })),
871
+ later: laterFeatures.map((feature) => ({ feature, priority: "Low" })),
872
+ },
873
+ timeline: {
874
+ quarters: {
875
+ "Quarter 1": nowFeatures,
876
+ "Quarter 2": nextFeatures,
877
+ "Quarter 3": laterFeatures,
878
+ },
879
+ resources: `${ctx.resourcesTeamSize ?? "Current"} team focused on the adoption-critical path`,
880
+ milestones: uniqueStrings([
881
+ "Core activation flow improved",
882
+ "Retention motion validated",
883
+ "Expansion-ready reporting shipped",
884
+ ], 3),
885
+ },
886
+ dependencies: uniqueStrings([
887
+ `${initiatives[1].name} depends on stable activation data from Quarter 1`,
888
+ "Proof and reporting depends on consistent event instrumentation",
889
+ "Expansion workflow depends on strong early retention signals",
890
+ ]),
891
+ risks: uniqueStrings([
892
+ `${ctx.productStage} teams can overbuild before activation is stable`,
893
+ "Competing roadmap bets can blur the wedge position",
894
+ "Resource limits can slow retention and instrumentation work",
895
+ ]),
896
+ },
897
+ insights: [
898
+ "Roadmap quality will depend on sequencing adoption work before expansion work.",
899
+ `${ctx.primaryFeature} is the right wedge if it proves ${ctx.primaryBenefit.toLowerCase()} quickly.`,
900
+ "Instrumentation is not optional because it defends both growth and pricing strategy.",
901
+ ],
902
+ recommendations: [
903
+ "Protect Quarter 1 from scope creep outside the activation-critical path.",
904
+ "Use roadmap reviews to decide whether retention or expansion needs the next investment.",
905
+ "Treat reporting as a strategic capability, not a cleanup task.",
906
+ ],
907
+ kpis: {
908
+ product: uniqueStrings(["feature_adoption", "time_to_value", "user_satisfaction"], 3),
909
+ business: uniqueStrings(["pipeline_conversion", "retention_rate", "revenue_growth"], 3),
910
+ development: uniqueStrings(["delivery_predictability", "quality_score", "instrumentation_coverage"], 3),
911
+ },
912
+ timestamp: new Date().toISOString(),
913
+ };
914
+ }
915
+ function buildMetricsDefinitionResult(ctx) {
916
+ const primaryKpis = buildPrimaryKpis(ctx);
917
+ const secondaryKpis = uniqueStrings([
918
+ "feature_adoption_rate",
919
+ "customer_satisfaction",
920
+ "expansion_pipeline",
921
+ ], 3).map((metric) => ({
922
+ metric,
923
+ target: metric === "customer_satisfaction" ? "4.5/5" : "Improve quarter over quarter",
924
+ timeframe: "quarterly",
925
+ }));
926
+ return {
927
+ metrics: {
928
+ productMetrics: {
929
+ acquisition: uniqueStrings(["qualified_signups", "activation_rate", "time_to_value"], 3),
930
+ engagement: uniqueStrings(["weekly_active_accounts", "feature_adoption", "workflow_completion"], 3),
931
+ retention: uniqueStrings(["logo_retention_rate", "churn_rate", "resurrection_rate"], 3),
932
+ satisfaction: uniqueStrings(["nps", "csat", "support_resolution_time"], 3),
933
+ },
934
+ businessMetrics: {
935
+ revenue: uniqueStrings(["mrr", "arr", "net_revenue_retention"], 3),
936
+ profitability: uniqueStrings(["gross_margin", "payback_period", "unit_economics"], 3),
937
+ efficiency: uniqueStrings(["cac", "ltv", "sales_cycle_length"], 3),
938
+ market: uniqueStrings(["win_rate", "segment_penetration", "competitive_displacement"], 3),
939
+ },
940
+ userMetrics: {
941
+ behavior: uniqueStrings(["journey_completion", "collaboration_depth", "repeat_usage"], 3),
942
+ outcomes: uniqueStrings([
943
+ toSentenceKey(ctx.primaryBenefit),
944
+ "time_saved",
945
+ "error_reduction",
946
+ ], 3),
947
+ satisfaction: uniqueStrings(["task_success_rate", "user_effort_score", "product_confidence"], 3),
948
+ },
949
+ technicalMetrics: {
950
+ performance: uniqueStrings(["load_time", "uptime", "workflow_latency"], 3),
951
+ quality: uniqueStrings(["bug_rate", "test_coverage", "release_regressions"], 3),
952
+ scalability: uniqueStrings(["concurrent_accounts", "event_volume", "response_time"], 3),
953
+ security: uniqueStrings(["vulnerabilities", "incident_count", "compliance_readiness"], 3),
954
+ },
955
+ kpis: {
956
+ primary: primaryKpis,
957
+ secondary: secondaryKpis,
958
+ },
959
+ reporting: {
960
+ dashboards: [
961
+ { name: "Executive Dashboard", audience: "Leadership", metrics: ["mrr", "retention_rate", "win_rate"] },
962
+ { name: "Product Dashboard", audience: "Product Team", metrics: ["activation_rate", "feature_adoption", "time_to_value"] },
963
+ { name: "Growth Dashboard", audience: "Growth Team", metrics: ["qualified_signups", "conversion_rate", "cac"] },
964
+ ],
965
+ frequency: {
966
+ real_time: ["system_status", "activation_events"],
967
+ daily: ["signups", "pipeline_creation"],
968
+ weekly: ["retention", "feature_adoption"],
969
+ monthly: ["revenue_growth", "segment_penetration"],
970
+ },
971
+ alerts: [
972
+ { metric: "activation_rate", threshold: "<30%", action: "review onboarding immediately" },
973
+ { metric: "logo_retention_rate", threshold: "<80%", action: "start retention diagnosis" },
974
+ ],
975
+ },
976
+ },
977
+ insights: [
978
+ `Metrics should prove whether ${ctx.productName} is delivering ${ctx.primaryBenefit.toLowerCase()}.`,
979
+ "Activation and retention deserve equal attention before scaling acquisition aggressively.",
980
+ `Stakeholders need a shared scorecard for ${ctx.timeline} execution, not isolated vanity metrics.`,
981
+ ],
982
+ recommendations: [
983
+ "Instrument the activation path before expanding the dashboard surface.",
984
+ "Map each primary KPI to a single owner and review cadence.",
985
+ "Use outcome metrics to defend pricing and roadmap decisions.",
986
+ ],
987
+ implementation: {
988
+ phases: [
989
+ { phase: "Instrumentation", duration: "2 weeks", deliverables: ["Event taxonomy", "Activation tracking"] },
990
+ { phase: "Dashboarding", duration: "2 weeks", deliverables: ["Executive dashboard", "Product dashboard"] },
991
+ { phase: "Operating Rhythm", duration: "2 weeks", deliverables: ["Metric review cadence", "Alert ownership"] },
992
+ ],
993
+ tools: ["Analytics platform", "Dashboard tool", "Alert routing"],
994
+ governance: `Assign owners across product, growth, and leadership for ${ctx.productName}.`,
995
+ },
996
+ timestamp: new Date().toISOString(),
997
+ };
998
+ }
999
+ class GrowthLoopsSkill {
1000
+ description = "Design and analyze sustainable growth loops for your product";
1001
+ category = "growth";
1002
+ async execute(input) {
1003
+ return buildGrowthLoopsResult(buildSkillContext(input));
1004
+ }
1005
+ }
1006
+ class MarketResearchSkill {
1007
+ description = "Conduct comprehensive market research and analysis";
1008
+ category = "research";
1009
+ async execute(input) {
1010
+ return buildMarketResearchResult(buildSkillContext(input));
1011
+ }
1012
+ }
1013
+ class GTMStrategySkill {
1014
+ description = "Develop go-to-market strategy and execution plan";
1015
+ category = "strategy";
1016
+ async execute(input) {
1017
+ return buildGTMStrategyResult(buildSkillContext(input));
1018
+ }
1019
+ }
1020
+ class UserPersonasSkill {
1021
+ description = "Create detailed user personas and journey maps";
1022
+ category = "users";
1023
+ async execute(input) {
1024
+ return buildUserPersonasResult(buildSkillContext(input));
1025
+ }
1026
+ }
1027
+ class CompetitiveAnalysisSkill {
1028
+ description = "Analyze competitors and competitive positioning";
1029
+ category = "competition";
1030
+ async execute(input) {
1031
+ return buildCompetitiveAnalysisResult(buildSkillContext(input));
1032
+ }
1033
+ }
1034
+ class ValuePropositionSkill {
1035
+ description = "Define and refine value proposition";
1036
+ category = "value";
1037
+ async execute(input) {
1038
+ return buildValuePropositionResult(buildSkillContext(input));
1039
+ }
1040
+ }
1041
+ class ProductRoadmapSkill {
1042
+ description = "Create strategic product roadmap";
1043
+ category = "planning";
1044
+ async execute(input) {
1045
+ return buildProductRoadmapResult(buildSkillContext(input));
1046
+ }
1047
+ }
1048
+ class MetricsDefinitionSkill {
1049
+ description = "Define comprehensive product and business metrics";
1050
+ category = "metrics";
1051
+ async execute(input) {
1052
+ return buildMetricsDefinitionResult(buildSkillContext(input));
1053
+ }
1054
+ }
1055
+ export default class PMSkills {
1056
+ options;
1057
+ skills;
1058
+ constructor(options = {}) {
1059
+ this.options = { ...DEFAULT_OPTIONS, ...options };
1060
+ this.skills = {
1061
+ growthLoops: new GrowthLoopsSkill(),
1062
+ marketResearch: new MarketResearchSkill(),
1063
+ gtmStrategy: new GTMStrategySkill(),
1064
+ userPersonas: new UserPersonasSkill(),
1065
+ competitiveAnalysis: new CompetitiveAnalysisSkill(),
1066
+ valueProposition: new ValuePropositionSkill(),
1067
+ productRoadmap: new ProductRoadmapSkill(),
1068
+ metricsDefinition: new MetricsDefinitionSkill(),
1069
+ };
1070
+ }
1071
+ async executeSkill(skillName, input) {
1072
+ if (!this.isSkillName(skillName)) {
1073
+ throw new Error(`Unknown skill: ${skillName}. Available skills: ${Object.keys(this.skills).join(", ")}`);
1074
+ }
1075
+ await this.ensureWorkspace();
1076
+ this.log(`🎯 Executing PM skill: ${skillName}`);
1077
+ const result = await this.skills[skillName].execute(input);
1078
+ const savedTo = await this.saveResult(skillName, result);
1079
+ this.log(`✅ Skill ${skillName} completed. Result saved to: ${savedTo}`);
1080
+ return { ...result, savedTo };
1081
+ }
1082
+ getAvailableSkills() {
1083
+ return Object.entries(this.skills).map(([name, skill]) => ({
1084
+ name,
1085
+ description: skill.description,
1086
+ category: skill.category,
1087
+ }));
1088
+ }
1089
+ async runProductAnalysis(productInfo) {
1090
+ this.log(`🚀 Running comprehensive product analysis`);
1091
+ const results = {};
1092
+ const skillOrder = [
1093
+ "marketResearch",
1094
+ "userPersonas",
1095
+ "competitiveAnalysis",
1096
+ "valueProposition",
1097
+ "growthLoops",
1098
+ "gtmStrategy",
1099
+ "productRoadmap",
1100
+ "metricsDefinition",
1101
+ ];
1102
+ for (const skillName of skillOrder) {
1103
+ try {
1104
+ this.log(`📊 Running ${skillName}...`);
1105
+ results[skillName] = await this.executeSkill(skillName, productInfo);
1106
+ }
1107
+ catch (error) {
1108
+ const message = getErrorMessage(error);
1109
+ this.log(`⚠️ Skill ${skillName} failed: ${message}`);
1110
+ results[skillName] = { error: message };
1111
+ }
1112
+ }
1113
+ const summary = this.generateAnalysisSummary(results);
1114
+ const savedTo = await this.saveComprehensiveAnalysis(results, summary);
1115
+ this.log(`🎉 Product analysis completed. Saved to: ${savedTo}`);
1116
+ return { results, summary, savedTo };
1117
+ }
1118
+ generateAnalysisSummary(results) {
1119
+ const summary = {
1120
+ totalSkills: Object.keys(results).length,
1121
+ completedSkills: Object.values(results).filter((r) => !("error" in r)).length,
1122
+ keyInsights: [],
1123
+ recommendations: [],
1124
+ risks: [],
1125
+ opportunities: [],
1126
+ };
1127
+ for (const result of Object.values(results)) {
1128
+ if ("error" in result)
1129
+ continue;
1130
+ const insights = asArray(result.insights);
1131
+ if (insights)
1132
+ summary.keyInsights.push(...insights);
1133
+ const recommendations = asArray(result.recommendations);
1134
+ if (recommendations)
1135
+ summary.recommendations.push(...recommendations);
1136
+ const risks = asArray(result.risks);
1137
+ if (risks)
1138
+ summary.risks.push(...risks);
1139
+ const opportunities = asArray(result.opportunities);
1140
+ if (opportunities)
1141
+ summary.opportunities.push(...opportunities);
1142
+ }
1143
+ summary.keyInsights = uniqueStrings(summary.keyInsights, 12);
1144
+ summary.recommendations = uniqueStrings(summary.recommendations, 12);
1145
+ summary.risks = uniqueStrings(summary.risks, 12);
1146
+ summary.opportunities = uniqueStrings(summary.opportunities, 12);
1147
+ return summary;
1148
+ }
1149
+ async saveResult(skillName, result) {
1150
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
1151
+ const filename = `${skillName}_${timestamp}.json`;
1152
+ const filepath = join(this.options.workspace, filename);
1153
+ await writeFile(filepath, JSON.stringify(result, null, 2));
1154
+ return filepath;
1155
+ }
1156
+ async saveComprehensiveAnalysis(results, summary) {
1157
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
1158
+ const filename = `product_analysis_${timestamp}.json`;
1159
+ const filepath = join(this.options.workspace, filename);
1160
+ const analysis = {
1161
+ timestamp: new Date().toISOString(),
1162
+ summary,
1163
+ results,
1164
+ };
1165
+ await writeFile(filepath, JSON.stringify(analysis, null, 2));
1166
+ return filepath;
1167
+ }
1168
+ async ensureWorkspace() {
1169
+ try {
1170
+ await mkdir(this.options.workspace, { recursive: true });
1171
+ }
1172
+ catch {
1173
+ // Directory may already exist.
1174
+ }
1175
+ }
1176
+ log(message) {
1177
+ if (this.options.verbose) {
1178
+ console.log(`[PM-Skills] ${message}`);
1179
+ }
1180
+ }
1181
+ isSkillName(value) {
1182
+ return Object.prototype.hasOwnProperty.call(this.skills, value);
1183
+ }
1184
+ }
1185
+ if (import.meta.url === `file://${process.argv[1]}`) {
1186
+ const [, , command, skillName, ...args] = process.argv;
1187
+ if (!command || command === "--help" || command === "-h") {
1188
+ console.log(`
1189
+ Usage: pm-skills <command> [skill-name] [options]
1190
+
1191
+ Commands:
1192
+ list List all available PM skills
1193
+ execute <skill-name> Execute a specific skill
1194
+ analyze Run comprehensive product analysis
1195
+
1196
+ Available Skills:
1197
+ growthLoops - Design sustainable growth loops
1198
+ marketResearch - Conduct market research
1199
+ gtmStrategy - Develop go-to-market strategy
1200
+ userPersonas - Create user personas
1201
+ competitiveAnalysis - Analyze competition
1202
+ valueProposition - Define value proposition
1203
+ productRoadmap - Create product roadmap
1204
+ metricsDefinition - Define product metrics
1205
+
1206
+ Options:
1207
+ --workspace <dir> Workspace directory (default: ./pm-workspace)
1208
+ --verbose Enable verbose logging
1209
+ `);
1210
+ process.exit(0);
1211
+ }
1212
+ const options = {};
1213
+ for (let i = 0; i < args.length; i++) {
1214
+ const flag = args[i];
1215
+ if (flag === "--workspace" && args[i + 1]) {
1216
+ options.workspace = args[i + 1];
1217
+ i++;
1218
+ }
1219
+ else if (flag === "--verbose") {
1220
+ options.verbose = true;
1221
+ }
1222
+ }
1223
+ const pmSkills = new PMSkills(options);
1224
+ switch (command) {
1225
+ case "list": {
1226
+ const skills = pmSkills.getAvailableSkills();
1227
+ console.log("🎯 Available PM Skills:");
1228
+ for (const skill of skills) {
1229
+ console.log(` ${skill.name.padEnd(20)} - ${skill.description} [${skill.category}]`);
1230
+ }
1231
+ break;
1232
+ }
1233
+ case "execute": {
1234
+ if (!skillName) {
1235
+ console.error("Error: Skill name required");
1236
+ process.exit(1);
1237
+ }
1238
+ const mockInput = { product: "Sample Product", market: "Technology" };
1239
+ pmSkills
1240
+ .executeSkill(skillName, mockInput)
1241
+ .then((result) => {
1242
+ console.log(`✅ Skill ${skillName} completed successfully`);
1243
+ console.log(`📁 Result saved to: ${result.savedTo}`);
1244
+ })
1245
+ .catch((error) => {
1246
+ console.error(`❌ Error: ${getErrorMessage(error)}`);
1247
+ process.exit(1);
1248
+ });
1249
+ break;
1250
+ }
1251
+ case "analyze": {
1252
+ const mockProductInfo = {
1253
+ product: "Sample Product",
1254
+ industry: "Technology",
1255
+ targetMarket: "SMB",
1256
+ };
1257
+ pmSkills
1258
+ .runProductAnalysis(mockProductInfo)
1259
+ .then((result) => {
1260
+ console.log(`🎉 Product analysis completed`);
1261
+ console.log(`📁 Results saved to: ${result.savedTo}`);
1262
+ console.log(`📊 Summary: ${result.summary.completedSkills}/${result.summary.totalSkills} skills completed`);
1263
+ })
1264
+ .catch((error) => {
1265
+ console.error(`❌ Error: ${getErrorMessage(error)}`);
1266
+ process.exit(1);
1267
+ });
1268
+ break;
1269
+ }
1270
+ default:
1271
+ console.error(`Unknown command: ${command}`);
1272
+ process.exit(1);
1273
+ }
1274
+ }