@agentblueprint/mcp-server 0.1.0 → 0.2.1

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,989 @@
1
+ // =============================================================================
2
+ // Agent Skills directory renderer
3
+ // Ported from implementation-spec-export.service.ts (main app)
4
+ // Converts blueprint + business case + implementation plan + use case JSON
5
+ // into a Map<string, string> of { relativePath → fileContent }
6
+ // =============================================================================
7
+ // =============================================================================
8
+ // HELPERS
9
+ // =============================================================================
10
+ export function slugify(input) {
11
+ return input
12
+ .toLowerCase()
13
+ .trim()
14
+ .replace(/[^a-z0-9]+/g, '-')
15
+ .replace(/^-+|-+$/g, '')
16
+ .slice(0, 60);
17
+ }
18
+ function str(val) {
19
+ return typeof val === 'string' ? val : '';
20
+ }
21
+ function arr(val) {
22
+ return Array.isArray(val) ? val : [];
23
+ }
24
+ function rec(val) {
25
+ return val && typeof val === 'object' && !Array.isArray(val) ? val : {};
26
+ }
27
+ function getPlatformName(bp) {
28
+ const pr = rec(bp.platformRecommendation);
29
+ const pp = rec(pr.primaryPlatform);
30
+ return str(pp.name) || 'Vendor-Agnostic';
31
+ }
32
+ function getAgenticPattern(bp) {
33
+ return str(bp.agenticPattern) || 'Multi-Agent';
34
+ }
35
+ function getTeam(bp) {
36
+ return arr(bp.enhancedDigitalTeam).filter((a) => !!a && typeof a === 'object');
37
+ }
38
+ function getInvestmentTier(bc) {
39
+ if (!bc)
40
+ return 'unknown';
41
+ const es = rec(bc.executiveSummary);
42
+ const ask = rec(es.ask);
43
+ const amount = str(ask.investmentAmount);
44
+ if (!amount)
45
+ return 'unknown';
46
+ const num = parseFloat(amount.replace(/[^0-9.]/g, ''));
47
+ if (isNaN(num))
48
+ return 'unknown';
49
+ if (num < 100000)
50
+ return 'low';
51
+ if (num < 500000)
52
+ return 'medium';
53
+ return 'high';
54
+ }
55
+ // =============================================================================
56
+ // SKILL.md — FRONTMATTER
57
+ // =============================================================================
58
+ function buildSkillFrontmatter(input) {
59
+ const bp = input.blueprintData;
60
+ const team = getTeam(bp);
61
+ const platform = getPlatformName(bp);
62
+ const pattern = getAgenticPattern(bp);
63
+ const slug = slugify(input.blueprintTitle) || 'implementation-spec';
64
+ const lines = [
65
+ '---',
66
+ `name: ${slug}`,
67
+ 'description: >-',
68
+ ` Implementation specification for ${input.blueprintTitle}. ${team.length} AI agents,`,
69
+ ` ${pattern} pattern, targeting ${platform}.`,
70
+ 'compatibility: Any coding agent (Claude Code, Codex, Cursor).',
71
+ 'metadata:',
72
+ ' generated-by: agent-blueprint',
73
+ ` generated-at: "${new Date().toISOString()}"`,
74
+ ` blueprint-id: "${input.blueprintId}"`,
75
+ ` platform: "${platform}"`,
76
+ ` agent-count: "${team.length}"`,
77
+ ` pattern: "${pattern}"`,
78
+ ` investment-tier: "${getInvestmentTier(input.businessCaseData)}"`,
79
+ '---',
80
+ ];
81
+ return lines.join('\n');
82
+ }
83
+ // =============================================================================
84
+ // SKILL.md — BODY
85
+ // =============================================================================
86
+ function buildSkillBody(input) {
87
+ const bp = input.blueprintData;
88
+ const bc = input.businessCaseData;
89
+ const team = getTeam(bp);
90
+ const platform = getPlatformName(bp);
91
+ const pattern = getAgenticPattern(bp);
92
+ const execSummary = str(bp.executiveSummary);
93
+ const lines = [];
94
+ // Overview
95
+ lines.push('# Implementation Specification', '');
96
+ lines.push(`> ${execSummary || input.blueprintTitle}`, '');
97
+ // Business Problem
98
+ lines.push('## Business Problem', '');
99
+ if (input.useCaseData) {
100
+ const uc = input.useCaseData;
101
+ if (str(uc.businessChallenge)) {
102
+ lines.push(str(uc.businessChallenge), '');
103
+ }
104
+ else if (str(uc.description)) {
105
+ lines.push(str(uc.description), '');
106
+ }
107
+ const painPoints = arr(uc.currentPainPoints);
108
+ if (painPoints.length > 0) {
109
+ lines.push('**Current pain points:**', '');
110
+ for (const p of painPoints)
111
+ lines.push(`- ${p}`);
112
+ lines.push('');
113
+ }
114
+ }
115
+ else {
116
+ lines.push(execSummary || '_See references/business-context.md for details._', '');
117
+ }
118
+ // Solution Architecture
119
+ lines.push('## Solution Architecture', '');
120
+ lines.push(`- **Platform:** ${platform}`);
121
+ lines.push(`- **Pattern:** ${pattern}`);
122
+ lines.push(`- **Agents:** ${team.length}`, '');
123
+ // Agent summary table
124
+ lines.push('| # | Agent | Role | Type |');
125
+ lines.push('|---|-------|------|------|');
126
+ team.forEach((agent, i) => {
127
+ const name = str(agent.name) || `Agent ${i + 1}`;
128
+ const role = str(agent.role) || str(rec(agent.instructions).role) || str(agent.agentRole) || '';
129
+ const type = str(agent.agentRole) || str(agent.orchestrationRole) || str(agent.type) || 'Worker';
130
+ lines.push(`| ${i + 1} | ${name} | ${role} | ${type} |`);
131
+ });
132
+ lines.push('');
133
+ lines.push('> Full agent specifications in `references/agent-specifications.md`', '');
134
+ // Phase 1: Pilot
135
+ lines.push('## Phase 1: Pilot', '');
136
+ const phases = arr(bp.phases);
137
+ const pilotPhase = phases.find((p) => str(p?.name).toLowerCase().includes('pilot') || str(p?.name).toLowerCase().includes('phase 1'));
138
+ if (pilotPhase) {
139
+ const p = rec(pilotPhase);
140
+ if (str(p.phaseGoal))
141
+ lines.push(`**Goal:** ${str(p.phaseGoal)}`, '');
142
+ if (p.durationWeeks)
143
+ lines.push(`**Duration:** ${p.durationWeeks} weeks`);
144
+ if (str(p.phaseCost))
145
+ lines.push(`**Cost target:** ${str(p.phaseCost)}`);
146
+ lines.push('');
147
+ const workstreams = arr(p.workstreams);
148
+ if (workstreams.length > 0) {
149
+ lines.push('**Pilot workstreams:**', '');
150
+ for (const ws of workstreams) {
151
+ const w = rec(ws);
152
+ lines.push(`- ${str(w.title)}`);
153
+ }
154
+ lines.push('');
155
+ }
156
+ const gate = rec(p.decisionGate);
157
+ if (gate.criteria) {
158
+ lines.push('**Decision gate criteria:**', '');
159
+ for (const c of arr(gate.criteria)) {
160
+ const cr = rec(c);
161
+ const label = str(cr.name) || str(cr.criterion) || str(cr.metric) || str(cr.description) || 'Unnamed criterion';
162
+ lines.push(`- ${label}: ${str(cr.target) || str(cr.threshold)}`);
163
+ }
164
+ lines.push('');
165
+ }
166
+ const exitCriteria = arr(p.exitCriteria);
167
+ if (exitCriteria.length > 0) {
168
+ lines.push('**Exit criteria:**', '');
169
+ for (const c of exitCriteria)
170
+ lines.push(`- ${c}`);
171
+ lines.push('');
172
+ }
173
+ }
174
+ else {
175
+ lines.push('_No pilot phase defined. See `references/implementation-roadmap.md` for phasing._', '');
176
+ }
177
+ // Phase 2: Full Implementation
178
+ lines.push('## Phase 2: Full Implementation', '');
179
+ const fullPhases = phases.filter((p) => !str(p?.name).toLowerCase().includes('pilot') && !str(p?.name).toLowerCase().includes('phase 1'));
180
+ if (fullPhases.length > 0) {
181
+ for (const phase of fullPhases) {
182
+ const p = rec(phase);
183
+ lines.push(`### ${str(p.name)}`, '');
184
+ if (str(p.phaseGoal))
185
+ lines.push(str(p.phaseGoal), '');
186
+ if (p.durationWeeks)
187
+ lines.push(`**Duration:** ${p.durationWeeks} weeks`);
188
+ if (str(p.phaseCost))
189
+ lines.push(`**Cost:** ${str(p.phaseCost)}`);
190
+ lines.push('');
191
+ }
192
+ }
193
+ else {
194
+ lines.push('_See `references/implementation-roadmap.md` for full rollout plan._', '');
195
+ }
196
+ // Financial Summary
197
+ lines.push('## Financial Summary', '');
198
+ if (bc) {
199
+ const benefits = rec(bc.benefits);
200
+ const quantifiedROI = rec(benefits.quantifiedROI);
201
+ if (str(quantifiedROI.roi))
202
+ lines.push(`- **ROI:** ${str(quantifiedROI.roi)}`);
203
+ if (str(quantifiedROI.npv))
204
+ lines.push(`- **NPV:** ${str(quantifiedROI.npv)}`);
205
+ if (str(quantifiedROI.paybackPeriod))
206
+ lines.push(`- **Payback:** ${str(quantifiedROI.paybackPeriod)}`);
207
+ const pilotROI = rec(quantifiedROI.pilotROI);
208
+ if (str(pilotROI.pilotCost) || str(pilotROI.pilotBenefit)) {
209
+ lines.push('');
210
+ lines.push('**Pilot economics:**');
211
+ if (str(pilotROI.pilotCost))
212
+ lines.push(`- Pilot cost: ${str(pilotROI.pilotCost)}`);
213
+ if (str(pilotROI.pilotBenefit))
214
+ lines.push(`- Pilot benefit: ${str(pilotROI.pilotBenefit)}`);
215
+ if (str(pilotROI.pilotROI))
216
+ lines.push(`- Pilot ROI: ${str(pilotROI.pilotROI)}`);
217
+ }
218
+ lines.push('');
219
+ lines.push('> Full financial analysis in `references/financial-case.md`', '');
220
+ }
221
+ else {
222
+ lines.push('_Generate a Business Case to enrich this section._', '');
223
+ }
224
+ // Agent Specifications Summary
225
+ lines.push('## Agent Specifications Summary', '');
226
+ for (const agent of team.slice(0, 5)) {
227
+ const name = str(agent.name);
228
+ const role = str(agent.role) || str(rec(agent.instructions).role) || '';
229
+ lines.push(`- **${name}**: ${role}`);
230
+ }
231
+ if (team.length > 5)
232
+ lines.push(`- _...and ${team.length - 5} more agents_`);
233
+ lines.push('');
234
+ lines.push('> Full specifications in `references/agent-specifications.md`', '');
235
+ // Risk & Governance Summary
236
+ lines.push('## Risk & Governance Summary', '');
237
+ const riskAssessment = rec(bp.riskAssessment);
238
+ const techRisks = arr(riskAssessment.technicalRisks);
239
+ const bizRisks = arr(riskAssessment.businessRisks);
240
+ if (techRisks.length > 0 || bizRisks.length > 0) {
241
+ if (techRisks.length > 0) {
242
+ lines.push('**Technical risks:**', '');
243
+ for (const r of techRisks.slice(0, 3))
244
+ lines.push(`- ${r}`);
245
+ lines.push('');
246
+ }
247
+ if (bizRisks.length > 0) {
248
+ lines.push('**Business risks:**', '');
249
+ for (const r of bizRisks.slice(0, 3))
250
+ lines.push(`- ${r}`);
251
+ lines.push('');
252
+ }
253
+ }
254
+ else {
255
+ lines.push('_See `references/guardrails-and-governance.md` for risk details._', '');
256
+ }
257
+ lines.push('> Full governance framework in `references/guardrails-and-governance.md`', '');
258
+ // How to Use This Spec
259
+ lines.push('## How to Use This Spec', '');
260
+ lines.push('1. **Load this skill** into your coding agent (Claude Code, Codex, Cursor)');
261
+ lines.push('2. **Review** the reference files for full context');
262
+ lines.push('3. **Start with Phase 1** (Pilot) — implement the lead agent first');
263
+ lines.push('4. **Use decision gates** to validate before expanding to full implementation');
264
+ lines.push('5. **Reference `scripts/validate-spec.sh`** to verify spec completeness', '');
265
+ // Generated By
266
+ lines.push('---', '');
267
+ lines.push('Generated by [Agent Blueprint](https://app.agentblueprint.ai)', '');
268
+ return lines.join('\n');
269
+ }
270
+ // =============================================================================
271
+ // REFERENCE FILES
272
+ // =============================================================================
273
+ function buildBusinessContext(input) {
274
+ const bp = input.blueprintData;
275
+ const uc = input.useCaseData;
276
+ const lines = ['# Business Context', ''];
277
+ const execSummary = str(bp.executiveSummary);
278
+ if (execSummary) {
279
+ lines.push('## Executive Summary', '', execSummary, '');
280
+ }
281
+ if (uc) {
282
+ if (str(uc.title))
283
+ lines.push(`## Use Case: ${str(uc.title)}`, '');
284
+ if (str(uc.description))
285
+ lines.push(str(uc.description), '');
286
+ const fiveWs = rec(uc.description5Ws);
287
+ if (fiveWs.who || fiveWs.what) {
288
+ lines.push('## Five Ws', '');
289
+ if (str(fiveWs.who))
290
+ lines.push(`- **Who:** ${str(fiveWs.who)}`);
291
+ if (str(fiveWs.what))
292
+ lines.push(`- **What:** ${str(fiveWs.what)}`);
293
+ if (str(fiveWs.where))
294
+ lines.push(`- **Where:** ${str(fiveWs.where)}`);
295
+ if (str(fiveWs.when))
296
+ lines.push(`- **When:** ${str(fiveWs.when)}`);
297
+ if (str(fiveWs.why))
298
+ lines.push(`- **Why:** ${str(fiveWs.why)}`);
299
+ lines.push('');
300
+ }
301
+ if (str(uc.businessChallenge)) {
302
+ lines.push('## Business Challenge', '', str(uc.businessChallenge), '');
303
+ }
304
+ const painPoints = arr(uc.currentPainPoints);
305
+ if (painPoints.length > 0) {
306
+ lines.push('## Current Pain Points', '');
307
+ for (const p of painPoints)
308
+ lines.push(`- ${p}`);
309
+ lines.push('');
310
+ }
311
+ const outcomes = arr(uc.desiredBusinessOutcomes);
312
+ if (outcomes.length > 0) {
313
+ lines.push('## Desired Business Outcomes', '');
314
+ for (const o of outcomes)
315
+ lines.push(`- ${o}`);
316
+ lines.push('');
317
+ }
318
+ const procDoc = rec(uc.processDocumentation);
319
+ const steps = arr(procDoc.steps);
320
+ if (steps.length > 0) {
321
+ lines.push('## Current Process', '');
322
+ for (const step of steps) {
323
+ const s = rec(step);
324
+ lines.push(`${s.stepNumber || '-'}. ${str(s.description)} _(${str(s.performer) || 'Unknown'})_`);
325
+ }
326
+ lines.push('');
327
+ }
328
+ const ts = rec(uc.transformationStory);
329
+ if (str(ts.situation)) {
330
+ lines.push('## Transformation Story', '');
331
+ lines.push(`**Situation:** ${str(ts.situation)}`);
332
+ if (str(ts.complication))
333
+ lines.push(`**Complication:** ${str(ts.complication)}`);
334
+ if (str(ts.resolution))
335
+ lines.push(`**Resolution:** ${str(ts.resolution)}`);
336
+ lines.push('');
337
+ }
338
+ if (str(uc.strategicAlignment)) {
339
+ lines.push('## Strategic Alignment', '', str(uc.strategicAlignment), '');
340
+ }
341
+ }
342
+ else {
343
+ lines.push('_Use case data not available. Generate a Use Case analysis to enrich this section._', '');
344
+ }
345
+ return lines.join('\n');
346
+ }
347
+ function buildAgentSpecifications(input) {
348
+ const bp = input.blueprintData;
349
+ const team = getTeam(bp);
350
+ const lines = ['# Agent Specifications', ''];
351
+ for (const agent of team) {
352
+ const name = str(agent.name);
353
+ lines.push(`## ${name}`, '');
354
+ const role = str(agent.role);
355
+ const type = str(agent.agentRole) || str(agent.orchestrationRole) || str(agent.type) || 'Worker';
356
+ const supervision = str(agent.supervisionLevel) || 'Supervised';
357
+ lines.push(`- **Role:** ${role}`);
358
+ lines.push(`- **Type:** ${type}`);
359
+ lines.push(`- **Supervision:** ${supervision}`);
360
+ lines.push('');
361
+ const instructions = rec(agent.instructions);
362
+ if (str(instructions.description)) {
363
+ lines.push('### Instructions', '', str(instructions.description), '');
364
+ }
365
+ if (str(instructions.role)) {
366
+ lines.push(`**Role:** ${str(instructions.role)}`, '');
367
+ }
368
+ const steps = arr(instructions.steps);
369
+ if (steps.length > 0) {
370
+ lines.push('**Steps:**', '');
371
+ for (const step of steps)
372
+ lines.push(`1. ${step}`);
373
+ lines.push('');
374
+ }
375
+ const responsibilities = arr(agent.responsibilities);
376
+ if (responsibilities.length > 0) {
377
+ lines.push('### Responsibilities', '');
378
+ for (const r of responsibilities)
379
+ lines.push(`- ${r}`);
380
+ lines.push('');
381
+ }
382
+ const tools = arr(agent.enhancedTools);
383
+ if (tools.length > 0) {
384
+ lines.push('### Tools', '');
385
+ lines.push('| Tool | Category | Description |');
386
+ lines.push('|------|----------|-------------|');
387
+ for (const tool of tools) {
388
+ const t = rec(tool);
389
+ const tName = str(t.name);
390
+ const tCat = str(t.toolCategory) || str(t.type) || '';
391
+ const tDesc = str(t.description).replace(/\|/g, '\\|').slice(0, 100);
392
+ lines.push(`| ${tName} | ${tCat} | ${tDesc} |`);
393
+ }
394
+ lines.push('');
395
+ }
396
+ const guardrails = arr(agent.guardrails);
397
+ if (guardrails.length > 0) {
398
+ lines.push('### Guardrails', '');
399
+ for (const g of guardrails) {
400
+ const gr = rec(g);
401
+ lines.push(`- **${str(gr.type)}**: ${str(gr.condition) || str(gr.description)}`);
402
+ }
403
+ lines.push('');
404
+ }
405
+ const escalation = arr(agent.escalationRules);
406
+ if (escalation.length > 0) {
407
+ lines.push('### Escalation Rules', '');
408
+ for (const rule of escalation)
409
+ lines.push(`- ${rule}`);
410
+ lines.push('');
411
+ }
412
+ const risk = rec(agent.riskAssessment);
413
+ if (str(risk.level)) {
414
+ lines.push('### Risk Assessment', '');
415
+ lines.push(`- **Level:** ${str(risk.level)}`);
416
+ lines.push(`- **Impact:** ${str(risk.impact)}`);
417
+ const controls = arr(risk.controls);
418
+ if (controls.length > 0) {
419
+ lines.push('- **Controls:**');
420
+ for (const c of controls)
421
+ lines.push(` - ${c}`);
422
+ }
423
+ lines.push('');
424
+ }
425
+ const cost = rec(agent.operatingCost);
426
+ if (arr(cost.drivers).length > 0 || str(cost.breakeven)) {
427
+ lines.push('### Cost Drivers', '');
428
+ for (const d of arr(cost.drivers))
429
+ lines.push(`- ${d}`);
430
+ if (str(cost.breakeven))
431
+ lines.push(`- **Breakeven:** ${str(cost.breakeven)}`);
432
+ lines.push('');
433
+ }
434
+ const metrics = arr(agent.successMetrics);
435
+ if (metrics.length > 0) {
436
+ lines.push('### Success Metrics', '');
437
+ lines.push('| Metric | Target |');
438
+ lines.push('|--------|--------|');
439
+ for (const m of metrics) {
440
+ const mr = rec(m);
441
+ lines.push(`| ${str(mr.metric)} | ${str(mr.target)} |`);
442
+ }
443
+ lines.push('');
444
+ }
445
+ lines.push('---', '');
446
+ }
447
+ return lines.join('\n');
448
+ }
449
+ function buildFinancialCase(input) {
450
+ const bc = input.businessCaseData;
451
+ const lines = ['# Financial Case', ''];
452
+ if (!bc) {
453
+ lines.push('_No business case data available. Generate a Business Case to enrich this section._', '');
454
+ return lines.join('\n');
455
+ }
456
+ const es = rec(bc.executiveSummary);
457
+ const ask = rec(es.ask);
458
+ if (str(es.purpose))
459
+ lines.push('## Purpose', '', str(es.purpose), '');
460
+ if (str(ask.investmentAmount) || str(ask.timeline)) {
461
+ lines.push('## Investment Ask', '');
462
+ if (str(ask.investmentAmount))
463
+ lines.push(`- **Amount:** ${str(ask.investmentAmount)}`);
464
+ if (str(ask.timeline))
465
+ lines.push(`- **Timeline:** ${str(ask.timeline)}`);
466
+ const keyOutcomes = arr(ask.keyOutcomes);
467
+ if (keyOutcomes.length > 0) {
468
+ lines.push('- **Key outcomes:**');
469
+ for (const o of keyOutcomes)
470
+ lines.push(` - ${o}`);
471
+ }
472
+ lines.push('');
473
+ }
474
+ if (str(es.valueProposition)) {
475
+ lines.push('## Value Proposition', '', str(es.valueProposition), '');
476
+ }
477
+ const benefits = rec(bc.benefits);
478
+ const qROI = rec(benefits.quantifiedROI);
479
+ if (str(qROI.roi) || str(qROI.npv) || str(qROI.paybackPeriod)) {
480
+ lines.push('## Return on Investment', '');
481
+ if (str(qROI.roi))
482
+ lines.push(`- **ROI:** ${str(qROI.roi)}`);
483
+ if (str(qROI.npv))
484
+ lines.push(`- **NPV:** ${str(qROI.npv)}`);
485
+ if (str(qROI.paybackPeriod))
486
+ lines.push(`- **Payback period:** ${str(qROI.paybackPeriod)}`);
487
+ lines.push('');
488
+ }
489
+ const laborDetail = rec(qROI.laborCostDetail);
490
+ if (str(laborDetail.annualLaborCost) || str(laborDetail.avgFullyLoadedRate)) {
491
+ lines.push('## Labor Cost Analysis', '');
492
+ if (str(laborDetail.avgFullyLoadedRate))
493
+ lines.push(`- **Avg. fully-loaded rate:** ${str(laborDetail.avgFullyLoadedRate)}`);
494
+ if (str(laborDetail.annualLaborCost))
495
+ lines.push(`- **Annual labor cost:** ${str(laborDetail.annualLaborCost)}`);
496
+ if (str(laborDetail.annualHoursAffected))
497
+ lines.push(`- **Annual hours affected:** ${str(laborDetail.annualHoursAffected)}`);
498
+ if (str(laborDetail.automationSavings))
499
+ lines.push(`- **Automation savings:** ${str(laborDetail.automationSavings)}`);
500
+ lines.push('');
501
+ }
502
+ const costBreakdown = rec(qROI.costBreakdown);
503
+ if (str(costBreakdown.implementation) || str(costBreakdown.annualLicensing)) {
504
+ lines.push('## Cost Breakdown', '');
505
+ if (str(costBreakdown.implementation))
506
+ lines.push(`- **Implementation:** ${str(costBreakdown.implementation)}`);
507
+ if (str(costBreakdown.annualLicensing))
508
+ lines.push(`- **Annual licensing:** ${str(costBreakdown.annualLicensing)}`);
509
+ if (str(costBreakdown.annualSupportMaintenance))
510
+ lines.push(`- **Annual support/maintenance:** ${str(costBreakdown.annualSupportMaintenance)}`);
511
+ lines.push('');
512
+ }
513
+ const pilotROI = rec(qROI.pilotROI);
514
+ if (str(pilotROI.pilotCost) || str(pilotROI.pilotBenefit)) {
515
+ lines.push('## Pilot Economics', '');
516
+ if (str(pilotROI.pilotCost))
517
+ lines.push(`- **Pilot cost:** ${str(pilotROI.pilotCost)}`);
518
+ if (str(pilotROI.pilotBenefit))
519
+ lines.push(`- **Pilot benefit:** ${str(pilotROI.pilotBenefit)}`);
520
+ if (str(pilotROI.pilotROI))
521
+ lines.push(`- **Pilot ROI:** ${str(pilotROI.pilotROI)}`);
522
+ if (str(pilotROI.pilotDuration))
523
+ lines.push(`- **Duration:** ${str(pilotROI.pilotDuration)}`);
524
+ lines.push('');
525
+ }
526
+ const sensitivity = rec(qROI.sensitivity);
527
+ if (sensitivity.conservative || sensitivity.realistic || sensitivity.optimistic) {
528
+ lines.push('## Sensitivity Analysis', '');
529
+ lines.push('| Scenario | NPV | ROI | Payback |');
530
+ lines.push('|----------|-----|-----|---------|');
531
+ for (const [label, key] of [['Conservative', 'conservative'], ['Realistic', 'realistic'], ['Optimistic', 'optimistic']]) {
532
+ const s = rec(sensitivity[key]);
533
+ lines.push(`| ${label} | ${str(s.npv)} | ${str(s.roi)} | ${str(s.paybackPeriod)} |`);
534
+ }
535
+ lines.push('');
536
+ }
537
+ const fiveYear = arr(qROI.fiveYearProjection);
538
+ if (fiveYear.length > 0) {
539
+ lines.push('## Five-Year Projection', '');
540
+ lines.push('| Year | Investment | Value | Net Cash Flow | Cumulative |');
541
+ lines.push('|------|-----------|-------|---------------|------------|');
542
+ for (const yr of fiveYear) {
543
+ const y = rec(yr);
544
+ lines.push(`| ${str(y.year)} | ${str(y.investment)} | ${str(y.value)} | ${str(y.netCashFlow)} | ${str(y.cumulative)} |`);
545
+ }
546
+ lines.push('');
547
+ }
548
+ const tangible = rec(benefits.tangibleBenefits);
549
+ if (str(tangible.costSavings) || str(tangible.processEfficiency)) {
550
+ lines.push('## Tangible Benefits', '');
551
+ if (str(tangible.costSavings))
552
+ lines.push(`- **Cost savings:** ${str(tangible.costSavings)}`);
553
+ if (str(tangible.revenueUplift))
554
+ lines.push(`- **Revenue uplift:** ${str(tangible.revenueUplift)}`);
555
+ if (str(tangible.processEfficiency))
556
+ lines.push(`- **Process efficiency:** ${str(tangible.processEfficiency)}`);
557
+ if (str(tangible.timeToMarket))
558
+ lines.push(`- **Time to market:** ${str(tangible.timeToMarket)}`);
559
+ lines.push('');
560
+ }
561
+ return lines.join('\n');
562
+ }
563
+ function buildImplementationRoadmap(input) {
564
+ const ip = input.implementationPlanData;
565
+ const lines = ['# Implementation Roadmap', ''];
566
+ if (!ip) {
567
+ lines.push('_No implementation plan data available. Generate an Implementation Plan to enrich this section._', '');
568
+ return lines.join('\n');
569
+ }
570
+ const overview = rec(ip.projectOverview);
571
+ if (str(overview.projectName)) {
572
+ lines.push(`## ${str(overview.projectName)}`, '');
573
+ }
574
+ if (str(overview.executiveSummary)) {
575
+ lines.push(str(overview.executiveSummary), '');
576
+ }
577
+ if (str(overview.scope)) {
578
+ lines.push('### Scope', '', str(overview.scope), '');
579
+ }
580
+ const assumptions = arr(overview.assumptions);
581
+ if (assumptions.length > 0) {
582
+ lines.push('### Assumptions', '');
583
+ for (const a of assumptions)
584
+ lines.push(`- ${a}`);
585
+ lines.push('');
586
+ }
587
+ const epics = arr(ip.epics);
588
+ if (epics.length > 0) {
589
+ lines.push('## Epics', '');
590
+ for (const epic of epics) {
591
+ const e = rec(epic);
592
+ lines.push(`### ${str(e.name)}`, '');
593
+ if (str(e.description))
594
+ lines.push(str(e.description), '');
595
+ lines.push(`- **Phase:** ${str(e.phase)}`);
596
+ lines.push(`- **Priority:** ${str(e.priority)}`);
597
+ if (str(e.estimatedDuration))
598
+ lines.push(`- **Duration:** ${str(e.estimatedDuration)}`);
599
+ if (str(e.businessValue))
600
+ lines.push(`- **Business value:** ${str(e.businessValue)}`);
601
+ lines.push('');
602
+ const ac = arr(e.acceptanceCriteria);
603
+ if (ac.length > 0) {
604
+ lines.push('**Acceptance criteria:**', '');
605
+ for (const c of ac)
606
+ lines.push(`- [ ] ${c}`);
607
+ lines.push('');
608
+ }
609
+ const stories = arr(e.stories);
610
+ if (stories.length > 0) {
611
+ lines.push('**User stories:**', '');
612
+ for (const story of stories) {
613
+ const s = rec(story);
614
+ const userStory = `As ${str(s.asA)}, I want ${str(s.iWant)}, so that ${str(s.soThat)}`;
615
+ lines.push(`- **${str(s.title)}**: ${userStory}`);
616
+ if (str(s.estimatedEffort))
617
+ lines.push(` - Effort: ${str(s.estimatedEffort)}`);
618
+ }
619
+ lines.push('');
620
+ }
621
+ const deps = arr(e.dependencies);
622
+ if (deps.length > 0) {
623
+ lines.push('**Dependencies:**', '');
624
+ for (const d of deps)
625
+ lines.push(`- ${d}`);
626
+ lines.push('');
627
+ }
628
+ }
629
+ }
630
+ const agentSpecs = arr(ip.agentSpecifications);
631
+ if (agentSpecs.length > 0) {
632
+ lines.push('## Agent Build Specifications', '');
633
+ for (const spec of agentSpecs) {
634
+ const s = rec(spec);
635
+ lines.push(`### ${str(s.name)}`, '');
636
+ if (str(s.role))
637
+ lines.push(str(s.role), '');
638
+ if (str(s.instructions))
639
+ lines.push('**Instructions:**', '', str(s.instructions), '');
640
+ if (str(s.linkedStoryId))
641
+ lines.push(`_Linked to story: ${str(s.linkedStoryId)}_`, '');
642
+ }
643
+ }
644
+ const resources = rec(ip.resources);
645
+ const timeline = rec(resources.timeline);
646
+ if (str(timeline.totalDuration)) {
647
+ lines.push('## Timeline', '');
648
+ lines.push(`**Total duration:** ${str(timeline.totalDuration)}`, '');
649
+ const timelinePhases = arr(timeline.phases);
650
+ if (timelinePhases.length > 0) {
651
+ for (const phase of timelinePhases) {
652
+ const p = rec(phase);
653
+ lines.push(`### ${str(p.name)} (${str(p.duration)})`, '');
654
+ for (const m of arr(p.milestones))
655
+ lines.push(`- ${m}`);
656
+ lines.push('');
657
+ }
658
+ }
659
+ }
660
+ const roles = arr(resources.roles);
661
+ if (roles.length > 0) {
662
+ lines.push('## Required Roles', '');
663
+ lines.push('| Role | Allocation | Duration | Key Skills |');
664
+ lines.push('|------|-----------|----------|------------|');
665
+ for (const role of roles) {
666
+ const r = rec(role);
667
+ const skills = arr(r.skillsRequired).slice(0, 3).join(', ');
668
+ lines.push(`| ${str(r.role)} | ${str(r.allocation)} | ${str(r.duration)} | ${skills} |`);
669
+ }
670
+ lines.push('');
671
+ }
672
+ const deps = arr(ip.dependencies);
673
+ if (deps.length > 0) {
674
+ lines.push('## Dependencies', '');
675
+ for (const dep of deps) {
676
+ const d = rec(dep);
677
+ lines.push(`- **${str(d.type)}** (${str(d.criticality)}): ${str(d.description)}`);
678
+ }
679
+ lines.push('');
680
+ }
681
+ return lines.join('\n');
682
+ }
683
+ function buildArchitectureDecisions(input) {
684
+ const bp = input.blueprintData;
685
+ const lines = ['# Architecture Decisions', ''];
686
+ const pr = rec(bp.platformRecommendation);
687
+ const pp = rec(pr.primaryPlatform);
688
+ if (str(pp.name)) {
689
+ lines.push(`## Platform: ${str(pp.name)}`, '');
690
+ if (str(pp.summary))
691
+ lines.push(str(pp.summary), '');
692
+ if (str(pp.justification))
693
+ lines.push(`**Justification:** ${str(pp.justification)}`, '');
694
+ const pros = arr(pp.pros);
695
+ if (pros.length > 0) {
696
+ lines.push('**Pros:**', '');
697
+ for (const p of pros)
698
+ lines.push(`- ${p}`);
699
+ lines.push('');
700
+ }
701
+ const cons = arr(pp.cons);
702
+ if (cons.length > 0) {
703
+ lines.push('**Cons:**', '');
704
+ for (const c of cons)
705
+ lines.push(`- ${c}`);
706
+ lines.push('');
707
+ }
708
+ if (str(pp.implementationTime))
709
+ lines.push(`**Implementation time:** ${str(pp.implementationTime)}`);
710
+ if (str(pp.estimatedCost))
711
+ lines.push(`**Estimated cost:** ${str(pp.estimatedCost)}`);
712
+ if (str(pp.integrationComplexity))
713
+ lines.push(`**Integration complexity:** ${str(pp.integrationComplexity)}`);
714
+ lines.push('');
715
+ }
716
+ const rationale = rec(bp.architectureRationale);
717
+ const whyAgentic = arr(rationale.whyAgentic);
718
+ if (whyAgentic.length > 0) {
719
+ lines.push('## Why Agentic AI', '');
720
+ for (const w of whyAgentic)
721
+ lines.push(`- ${w}`);
722
+ lines.push('');
723
+ }
724
+ const hybrid = arr(rationale.hybridComponents);
725
+ if (hybrid.length > 0) {
726
+ lines.push('## Hybrid Components', '');
727
+ lines.push('| Component | Approach | Rationale |');
728
+ lines.push('|-----------|----------|-----------|');
729
+ for (const h of hybrid) {
730
+ const hr = rec(h);
731
+ lines.push(`| ${str(hr.component)} | ${str(hr.approach)} | ${str(hr.rationale)} |`);
732
+ }
733
+ lines.push('');
734
+ }
735
+ const wins = arr(rationale.immediateWins);
736
+ if (wins.length > 0) {
737
+ lines.push('## Immediate Wins', '');
738
+ for (const w of wins)
739
+ lines.push(`- ${w}`);
740
+ lines.push('');
741
+ }
742
+ const reasoning = rec(bp.reasoning);
743
+ const bizDecisions = rec(reasoning.businessDecisions);
744
+ const patternSelection = rec(bizDecisions.patternSelection);
745
+ if (str(patternSelection.decision)) {
746
+ lines.push('## Pattern Selection', '');
747
+ lines.push(`**Selected:** ${str(patternSelection.decision)}`);
748
+ if (str(patternSelection.rationale))
749
+ lines.push(`**Rationale:** ${str(patternSelection.rationale)}`);
750
+ if (str(patternSelection.reasoning))
751
+ lines.push(`**Business factors:** ${str(patternSelection.reasoning)}`);
752
+ const alts = arr(patternSelection.alternatives);
753
+ if (alts.length > 0)
754
+ lines.push(`**Alternatives considered:** ${alts.join(', ')}`);
755
+ lines.push('');
756
+ }
757
+ const gaps = arr(bp.integrationGaps);
758
+ if (gaps.length > 0) {
759
+ lines.push('## Integration Gaps', '');
760
+ lines.push('| System | Gap Type | Severity | Impact | Recommendation |');
761
+ lines.push('|--------|----------|----------|--------|----------------|');
762
+ for (const gap of gaps) {
763
+ const g = rec(gap);
764
+ lines.push(`| ${str(g.systemNeeded)} | ${str(g.gapType)} | ${str(g.severity)} | ${str(g.impact)} | ${str(g.recommendation)} |`);
765
+ }
766
+ lines.push('');
767
+ }
768
+ const altPlatforms = arr(pr.alternativePlatforms);
769
+ if (altPlatforms.length > 0) {
770
+ lines.push('## Alternative Platforms Considered', '');
771
+ for (const alt of altPlatforms) {
772
+ const a = rec(alt);
773
+ lines.push(`### ${str(a.name)}`, '');
774
+ if (str(a.justification))
775
+ lines.push(str(a.justification), '');
776
+ if (str(a.estimatedCost))
777
+ lines.push(`- **Cost:** ${str(a.estimatedCost)}`);
778
+ if (str(a.implementationTime))
779
+ lines.push(`- **Timeline:** ${str(a.implementationTime)}`);
780
+ if (str(a.integrationComplexity))
781
+ lines.push(`- **Complexity:** ${str(a.integrationComplexity)}`);
782
+ lines.push('');
783
+ }
784
+ }
785
+ const feasibility = rec(bp.feasibilityIndicators);
786
+ if (str(feasibility.overallScore) || str(feasibility.recommendation)) {
787
+ lines.push('## Feasibility Assessment', '');
788
+ if (str(feasibility.overallScore))
789
+ lines.push(`**Score:** ${str(feasibility.overallScore)}`);
790
+ if (str(feasibility.recommendation))
791
+ lines.push(`**Recommendation:** ${str(feasibility.recommendation)}`);
792
+ lines.push('');
793
+ }
794
+ return lines.join('\n');
795
+ }
796
+ function buildGuardrailsAndGovernance(input) {
797
+ const bp = input.blueprintData;
798
+ const bc = input.businessCaseData;
799
+ const team = getTeam(bp);
800
+ const lines = ['# Guardrails & Governance', ''];
801
+ const riskAssessment = rec(bp.riskAssessment);
802
+ const techRisks = arr(riskAssessment.technicalRisks);
803
+ const bizRisks = arr(riskAssessment.businessRisks);
804
+ const mitStrategies = arr(riskAssessment.mitigationStrategies);
805
+ const contingencies = arr(riskAssessment.contingencyPlans);
806
+ if (techRisks.length > 0) {
807
+ lines.push('## Technical Risks', '');
808
+ for (const r of techRisks)
809
+ lines.push(`- ${r}`);
810
+ lines.push('');
811
+ }
812
+ if (bizRisks.length > 0) {
813
+ lines.push('## Business Risks', '');
814
+ for (const r of bizRisks)
815
+ lines.push(`- ${r}`);
816
+ lines.push('');
817
+ }
818
+ if (mitStrategies.length > 0) {
819
+ lines.push('## Mitigation Strategies', '');
820
+ for (const m of mitStrategies)
821
+ lines.push(`- ${m}`);
822
+ lines.push('');
823
+ }
824
+ if (contingencies.length > 0) {
825
+ lines.push('## Contingency Plans', '');
826
+ for (const c of contingencies)
827
+ lines.push(`- ${c}`);
828
+ lines.push('');
829
+ }
830
+ const agentsWithGuardrails = team.filter(a => arr(a.guardrails).length > 0 || arr(a.escalationRules).length > 0);
831
+ if (agentsWithGuardrails.length > 0) {
832
+ lines.push('## Agent-Level Guardrails', '');
833
+ for (const agent of agentsWithGuardrails) {
834
+ lines.push(`### ${str(agent.name)}`, '');
835
+ const guardrails = arr(agent.guardrails);
836
+ if (guardrails.length > 0) {
837
+ lines.push('**Guardrails:**', '');
838
+ for (const g of guardrails) {
839
+ const gr = rec(g);
840
+ lines.push(`- **${str(gr.type)}**: ${str(gr.condition) || str(gr.description)}`);
841
+ }
842
+ lines.push('');
843
+ }
844
+ const escalation = arr(agent.escalationRules);
845
+ if (escalation.length > 0) {
846
+ lines.push('**Escalation rules:**', '');
847
+ for (const rule of escalation)
848
+ lines.push(`- ${rule}`);
849
+ lines.push('');
850
+ }
851
+ const risk = rec(agent.riskAssessment);
852
+ if (str(risk.level)) {
853
+ lines.push(`**Risk:** ${str(risk.level)} — ${str(risk.impact)}`);
854
+ lines.push('');
855
+ }
856
+ }
857
+ }
858
+ if (bc) {
859
+ const bcRisks = rec(bc.risks);
860
+ const implRisks = arr(bcRisks.implementationRisks);
861
+ const opRisks = arr(bcRisks.operationalRisks);
862
+ const mitigationPlan = arr(bcRisks.mitigationPlan);
863
+ if (implRisks.length > 0) {
864
+ lines.push('## Implementation Risks (Business Case)', '');
865
+ lines.push('| Risk | Severity | Impact |');
866
+ lines.push('|------|----------|--------|');
867
+ for (const risk of implRisks) {
868
+ const r = rec(risk);
869
+ lines.push(`| ${str(r.title)} | ${str(r.severity)} | ${str(r.impact)} |`);
870
+ }
871
+ lines.push('');
872
+ }
873
+ if (opRisks.length > 0) {
874
+ lines.push('## Operational Risks (Business Case)', '');
875
+ lines.push('| Risk | Severity | Impact |');
876
+ lines.push('|------|----------|--------|');
877
+ for (const risk of opRisks) {
878
+ const r = rec(risk);
879
+ lines.push(`| ${str(r.title)} | ${str(r.severity)} | ${str(r.impact)} |`);
880
+ }
881
+ lines.push('');
882
+ }
883
+ if (mitigationPlan.length > 0) {
884
+ lines.push('## Mitigation Plan', '');
885
+ for (const mit of mitigationPlan) {
886
+ const m = rec(mit);
887
+ lines.push(`### ${str(m.riskTitle)}`, '');
888
+ lines.push(`- **Strategy:** ${str(m.strategy)}`);
889
+ if (str(m.owner))
890
+ lines.push(`- **Owner:** ${str(m.owner)}`);
891
+ if (str(m.timeline))
892
+ lines.push(`- **Timeline:** ${str(m.timeline)}`);
893
+ lines.push('');
894
+ }
895
+ }
896
+ }
897
+ return lines.join('\n');
898
+ }
899
+ function buildValidateScript() {
900
+ return `#!/bin/bash
901
+ # validate-spec.sh — Validates implementation spec structure completeness
902
+ # Usage: ./scripts/validate-spec.sh
903
+
904
+ set -e
905
+
906
+ ERRORS=0
907
+ WARNINGS=0
908
+
909
+ check_file() {
910
+ if [ ! -f "$1" ]; then
911
+ echo "ERROR: Missing required file: $1"
912
+ ERRORS=$((ERRORS + 1))
913
+ else
914
+ echo "OK: $1"
915
+ fi
916
+ }
917
+
918
+ check_optional() {
919
+ if [ ! -f "$1" ]; then
920
+ echo "WARN: Optional file missing: $1 (consider generating the missing artifact)"
921
+ WARNINGS=$((WARNINGS + 1))
922
+ else
923
+ echo "OK: $1"
924
+ fi
925
+ }
926
+
927
+ echo "=== Implementation Spec Validator ==="
928
+ echo ""
929
+
930
+ # Required files
931
+ echo "--- Required Files ---"
932
+ check_file "SKILL.md"
933
+ check_file "references/agent-specifications.md"
934
+ check_file "references/architecture-decisions.md"
935
+
936
+ # Check SKILL.md has frontmatter
937
+ if [ -f "SKILL.md" ]; then
938
+ if ! head -1 SKILL.md | grep -q "^---"; then
939
+ echo "ERROR: SKILL.md missing YAML frontmatter"
940
+ ERRORS=$((ERRORS + 1))
941
+ fi
942
+ fi
943
+
944
+ echo ""
945
+ echo "--- Optional Files ---"
946
+ check_optional "references/business-context.md"
947
+ check_optional "references/financial-case.md"
948
+ check_optional "references/implementation-roadmap.md"
949
+ check_optional "references/guardrails-and-governance.md"
950
+
951
+ echo ""
952
+ echo "=== Results ==="
953
+ echo "Errors: $ERRORS"
954
+ echo "Warnings: $WARNINGS"
955
+
956
+ if [ $ERRORS -gt 0 ]; then
957
+ echo "FAILED: Fix $ERRORS error(s) before proceeding."
958
+ exit 1
959
+ else
960
+ echo "PASSED"
961
+ exit 0
962
+ fi
963
+ `;
964
+ }
965
+ // =============================================================================
966
+ // MAIN RENDER FUNCTION
967
+ // =============================================================================
968
+ /**
969
+ * Renders a complete Agent Skills directory from blueprint data.
970
+ * Returns a Map of { relativePath → fileContent }.
971
+ */
972
+ export function renderSkillDirectory(input) {
973
+ const files = new Map();
974
+ // SKILL.md
975
+ const frontmatter = buildSkillFrontmatter(input);
976
+ const body = buildSkillBody(input);
977
+ files.set('SKILL.md', `${frontmatter}\n\n${body}`);
978
+ // Reference files
979
+ files.set('references/business-context.md', buildBusinessContext(input));
980
+ files.set('references/agent-specifications.md', buildAgentSpecifications(input));
981
+ files.set('references/financial-case.md', buildFinancialCase(input));
982
+ files.set('references/implementation-roadmap.md', buildImplementationRoadmap(input));
983
+ files.set('references/architecture-decisions.md', buildArchitectureDecisions(input));
984
+ files.set('references/guardrails-and-governance.md', buildGuardrailsAndGovernance(input));
985
+ // Scripts
986
+ files.set('scripts/validate-spec.sh', buildValidateScript());
987
+ return files;
988
+ }
989
+ //# sourceMappingURL=renderers.js.map