@agentblueprint/mcp-server 0.2.1 → 0.3.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.
package/dist/renderers.js CHANGED
@@ -24,6 +24,26 @@ function arr(val) {
24
24
  function rec(val) {
25
25
  return val && typeof val === 'object' && !Array.isArray(val) ? val : {};
26
26
  }
27
+ /** Returns string representation for numbers, passes through strings, '' otherwise */
28
+ function numStr(val) {
29
+ if (typeof val === 'number')
30
+ return String(val);
31
+ if (typeof val === 'string')
32
+ return val;
33
+ return '';
34
+ }
35
+ /** Checks if a string value is a placeholder/garbage value that shouldn't be rendered */
36
+ function isPlaceholder(val) {
37
+ return ['—', '–', '-', 'N/A', 'n/a', 'TBD', 'null', 'undefined', 'none'].includes(val.trim());
38
+ }
39
+ /** Strips a trailing unit suffix to prevent double-units (e.g. "3.6 months" + " months") */
40
+ function stripTrailingUnit(val, unit) {
41
+ return val.replace(new RegExp(`\\s*${unit}\\s*$`, 'i'), '');
42
+ }
43
+ /** Joins string arrays with separator; returns '' for non-arrays */
44
+ function arrStr(val, sep = ', ') {
45
+ return Array.isArray(val) ? val.filter((v) => typeof v === 'string').join(sep) : '';
46
+ }
27
47
  function getPlatformName(bp) {
28
48
  const pr = rec(bp.platformRecommendation);
29
49
  const pp = rec(pr.primaryPlatform);
@@ -43,7 +63,12 @@ function getInvestmentTier(bc) {
43
63
  const amount = str(ask.investmentAmount);
44
64
  if (!amount)
45
65
  return 'unknown';
46
- const num = parseFloat(amount.replace(/[^0-9.]/g, ''));
66
+ // Extract the first number group only (avoid concatenating multiple numbers
67
+ // e.g. "$13,143 one-time + $2,981 annual" → 13143, not 131432981)
68
+ const match = amount.match(/[\d,]+(?:\.\d+)?/);
69
+ if (!match)
70
+ return 'unknown';
71
+ const num = parseFloat(match[0].replace(/,/g, ''));
47
72
  if (isNaN(num))
48
73
  return 'unknown';
49
74
  if (num < 100000)
@@ -131,89 +156,130 @@ function buildSkillBody(input) {
131
156
  });
132
157
  lines.push('');
133
158
  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)}`);
159
+ // Phase rendering — prefer implementation plan epics when available
160
+ const ipEpics = input.implementationPlanData ? arr(rec(input.implementationPlanData).epics) : [];
161
+ if (ipEpics.length > 0) {
162
+ const pilotEpics = ipEpics.filter((e) => str(rec(e).phase).toLowerCase().includes('pilot'));
163
+ const fullEpics = ipEpics.filter((e) => !str(rec(e).phase).toLowerCase().includes('pilot'));
164
+ lines.push('## Phase 1: Pilot', '');
165
+ if (pilotEpics.length > 0) {
166
+ const seen = new Set();
167
+ for (const epic of pilotEpics) {
168
+ const e = rec(epic);
169
+ const name = str(e.name);
170
+ if (name && !seen.has(name)) {
171
+ seen.add(name);
172
+ lines.push(`- **${name}**${str(e.estimatedDuration) ? ` (${str(e.estimatedDuration)})` : ''}`);
173
+ }
153
174
  }
154
175
  lines.push('');
155
176
  }
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)}`);
177
+ else {
178
+ lines.push('_No pilot epics defined. See `references/implementation-roadmap.md` for phasing._', '');
179
+ }
180
+ lines.push('## Phase 2: Full Implementation', '');
181
+ if (fullEpics.length > 0) {
182
+ const seen = new Set();
183
+ for (const epic of fullEpics) {
184
+ const e = rec(epic);
185
+ const name = str(e.name);
186
+ if (name && !seen.has(name)) {
187
+ seen.add(name);
188
+ lines.push(`- **${name}**${str(e.estimatedDuration) ? ` (${str(e.estimatedDuration)})` : ''}`);
189
+ }
163
190
  }
164
191
  lines.push('');
165
192
  }
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('');
193
+ else {
194
+ lines.push('_See `references/implementation-roadmap.md` for full rollout plan._', '');
172
195
  }
173
196
  }
174
197
  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)}`, '');
198
+ lines.push('## Phase 1: Pilot', '');
199
+ const phases = arr(bp.phases);
200
+ const pilotPhase = phases.find((p) => str(p?.name).toLowerCase().includes('pilot') || str(p?.name).toLowerCase().includes('phase 1'));
201
+ if (pilotPhase) {
202
+ const p = rec(pilotPhase);
184
203
  if (str(p.phaseGoal))
185
- lines.push(str(p.phaseGoal), '');
204
+ lines.push(`**Goal:** ${str(p.phaseGoal)}`, '');
186
205
  if (p.durationWeeks)
187
206
  lines.push(`**Duration:** ${p.durationWeeks} weeks`);
188
207
  if (str(p.phaseCost))
189
- lines.push(`**Cost:** ${str(p.phaseCost)}`);
208
+ lines.push(`**Cost target:** ${str(p.phaseCost)}`);
190
209
  lines.push('');
210
+ const workstreams = arr(p.workstreams);
211
+ if (workstreams.length > 0) {
212
+ lines.push('**Pilot workstreams:**', '');
213
+ for (const ws of workstreams) {
214
+ const w = rec(ws);
215
+ lines.push(`- ${str(w.title)}`);
216
+ }
217
+ lines.push('');
218
+ }
219
+ const gate = rec(p.decisionGate);
220
+ if (gate.criteria) {
221
+ lines.push('**Decision gate criteria:**', '');
222
+ for (const c of arr(gate.criteria)) {
223
+ const cr = rec(c);
224
+ const label = str(cr.name) || str(cr.criterion) || str(cr.metric) || str(cr.description) || 'Unnamed criterion';
225
+ lines.push(`- ${label}: ${str(cr.target) || str(cr.threshold)}`);
226
+ }
227
+ lines.push('');
228
+ }
229
+ const exitCriteria = arr(p.exitCriteria);
230
+ if (exitCriteria.length > 0) {
231
+ lines.push('**Exit criteria:**', '');
232
+ for (const c of exitCriteria)
233
+ lines.push(`- ${c}`);
234
+ lines.push('');
235
+ }
236
+ }
237
+ else {
238
+ lines.push('_No pilot phase defined. See `references/implementation-roadmap.md` for phasing._', '');
239
+ }
240
+ lines.push('## Phase 2: Full Implementation', '');
241
+ const fullPhases = phases.filter((p) => !str(p?.name).toLowerCase().includes('pilot') && !str(p?.name).toLowerCase().includes('phase 1'));
242
+ if (fullPhases.length > 0) {
243
+ for (const phase of fullPhases) {
244
+ const p = rec(phase);
245
+ lines.push(`### ${str(p.name)}`, '');
246
+ if (str(p.phaseGoal))
247
+ lines.push(str(p.phaseGoal), '');
248
+ if (p.durationWeeks)
249
+ lines.push(`**Duration:** ${p.durationWeeks} weeks`);
250
+ if (str(p.phaseCost))
251
+ lines.push(`**Cost:** ${str(p.phaseCost)}`);
252
+ lines.push('');
253
+ }
254
+ }
255
+ else {
256
+ lines.push('_See `references/implementation-roadmap.md` for full rollout plan._', '');
191
257
  }
192
- }
193
- else {
194
- lines.push('_See `references/implementation-roadmap.md` for full rollout plan._', '');
195
258
  }
196
259
  // Financial Summary
197
260
  lines.push('## Financial Summary', '');
198
261
  if (bc) {
199
262
  const benefits = rec(bc.benefits);
200
263
  const quantifiedROI = rec(benefits.quantifiedROI);
201
- if (str(quantifiedROI.roi))
264
+ if (str(quantifiedROI.roi) && !isPlaceholder(str(quantifiedROI.roi)))
202
265
  lines.push(`- **ROI:** ${str(quantifiedROI.roi)}`);
203
- if (str(quantifiedROI.npv))
266
+ if (str(quantifiedROI.npv) && !isPlaceholder(str(quantifiedROI.npv)))
204
267
  lines.push(`- **NPV:** ${str(quantifiedROI.npv)}`);
205
- if (str(quantifiedROI.paybackPeriod))
268
+ if (str(quantifiedROI.paybackPeriod) && !isPlaceholder(str(quantifiedROI.paybackPeriod)))
206
269
  lines.push(`- **Payback:** ${str(quantifiedROI.paybackPeriod)}`);
207
270
  const pilotROI = rec(quantifiedROI.pilotROI);
208
- if (str(pilotROI.pilotCost) || str(pilotROI.pilotBenefit)) {
271
+ const skillPilotCapex = str(rec(pilotROI.pilotCapex).value);
272
+ const skillPilotSavings = str(rec(pilotROI.pilotAnnualSavings).value);
273
+ const skillPilotYear1Net = str(rec(pilotROI.pilotYear1Net).value);
274
+ if (skillPilotCapex || skillPilotSavings) {
209
275
  lines.push('');
210
276
  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)}`);
277
+ if (skillPilotCapex)
278
+ lines.push(`- Pilot capex: ${skillPilotCapex}`);
279
+ if (skillPilotSavings)
280
+ lines.push(`- Pilot annual savings: ${skillPilotSavings}`);
281
+ if (skillPilotYear1Net)
282
+ lines.push(`- Pilot Year 1 net: ${skillPilotYear1Net}`);
217
283
  }
218
284
  lines.push('');
219
285
  lines.push('> Full financial analysis in `references/financial-case.md`', '');
@@ -344,6 +410,244 @@ function buildBusinessContext(input) {
344
410
  }
345
411
  return lines.join('\n');
346
412
  }
413
+ function buildOrganizationContext(input) {
414
+ const bp = input.businessProfileData;
415
+ const lines = ['# Organization Context', ''];
416
+ if (!bp) {
417
+ lines.push('_No business profile data available. Create a Business Profile to enrich this section._', '');
418
+ return lines.join('\n');
419
+ }
420
+ // Company overview
421
+ const companyName = str(bp.companyName);
422
+ if (companyName) {
423
+ lines.push(`## ${companyName}`, '');
424
+ }
425
+ if (str(bp.description))
426
+ lines.push(str(bp.description), '');
427
+ // Industry & scale
428
+ if (str(bp.industry) || str(bp.size) || str(bp.revenue)) {
429
+ lines.push('## Industry & Scale', '');
430
+ if (str(bp.industry))
431
+ lines.push(`- **Industry:** ${str(bp.industry)}`);
432
+ if (str(bp.size))
433
+ lines.push(`- **Company size:** ${str(bp.size)}`);
434
+ if (str(bp.revenue))
435
+ lines.push(`- **Revenue:** ${str(bp.revenue)}`);
436
+ if (str(bp.currency) && str(bp.currency) !== 'USD')
437
+ lines.push(`- **Currency:** ${str(bp.currency)}`);
438
+ lines.push('');
439
+ }
440
+ // Technology profile
441
+ const tech = rec(bp.technologyProfile);
442
+ const systems = arr(tech.systems);
443
+ const dataInfra = rec(tech.dataInfrastructure);
444
+ const integration = rec(tech.integrationCapabilities);
445
+ const security = rec(tech.securityCompliance);
446
+ if (systems.length > 0 || dataInfra.cloudPlatforms || dataInfra.dataWarehouseExists !== undefined || integration.apiReadiness || integration.apiMaturity) {
447
+ lines.push('## Technology Landscape', '');
448
+ if (systems.length > 0) {
449
+ lines.push('### Current Systems', '');
450
+ lines.push('| System | Category | Criticality |');
451
+ lines.push('|--------|----------|-------------|');
452
+ for (const sys of systems) {
453
+ const s = rec(sys);
454
+ lines.push(`| ${str(s.name)} | ${str(s.category)} | ${str(s.criticality) || str(s.businessCriticality)} |`);
455
+ }
456
+ lines.push('');
457
+ }
458
+ const cloudPlatforms = arrStr(dataInfra.cloudPlatforms);
459
+ if (cloudPlatforms || dataInfra.dataWarehouseExists !== undefined || str(dataInfra.cloudProvider)) {
460
+ lines.push('### Data Infrastructure', '');
461
+ if (cloudPlatforms)
462
+ lines.push(`- **Cloud platforms:** ${cloudPlatforms}`);
463
+ else if (str(dataInfra.cloudProvider))
464
+ lines.push(`- **Cloud provider:** ${str(dataInfra.cloudProvider)}`);
465
+ if (dataInfra.dataWarehouseExists !== undefined)
466
+ lines.push(`- **Data warehouse:** ${dataInfra.dataWarehouseExists ? 'Yes' : 'No'}`);
467
+ if (dataInfra.dataLakeExists !== undefined)
468
+ lines.push(`- **Data lake:** ${dataInfra.dataLakeExists ? 'Yes' : 'No'}`);
469
+ if (str(dataInfra.dataGovernanceMaturity))
470
+ lines.push(`- **Data governance maturity:** ${str(dataInfra.dataGovernanceMaturity)}`);
471
+ else if (str(dataInfra.dataQuality))
472
+ lines.push(`- **Data quality:** ${str(dataInfra.dataQuality)}`);
473
+ lines.push('');
474
+ }
475
+ const apiReadiness = str(integration.apiReadiness) || str(integration.apiMaturity);
476
+ const currentIntegrations = arrStr(integration.currentIntegrations);
477
+ if (apiReadiness || currentIntegrations || str(integration.integrationPatterns)) {
478
+ lines.push('### Integration Capabilities', '');
479
+ if (apiReadiness)
480
+ lines.push(`- **API readiness:** ${apiReadiness}`);
481
+ if (currentIntegrations)
482
+ lines.push(`- **Current integrations:** ${currentIntegrations}`);
483
+ else if (str(integration.integrationPatterns))
484
+ lines.push(`- **Integration patterns:** ${str(integration.integrationPatterns)}`);
485
+ if (str(integration.integrationPlatform) && !isPlaceholder(str(integration.integrationPlatform)))
486
+ lines.push(`- **Integration platform:** ${str(integration.integrationPlatform)}`);
487
+ else if (str(integration.middlewarePlatforms) && !isPlaceholder(str(integration.middlewarePlatforms)))
488
+ lines.push(`- **Middleware:** ${str(integration.middlewarePlatforms)}`);
489
+ lines.push('');
490
+ }
491
+ const complianceCerts = arrStr(security.complianceCertifications);
492
+ const privacyMeasures = arrStr(security.dataPrivacyMeasures);
493
+ if (complianceCerts || privacyMeasures || str(security.complianceFrameworks) || str(security.dataPrivacy)) {
494
+ lines.push('### Security & Compliance', '');
495
+ if (complianceCerts)
496
+ lines.push(`- **Compliance certifications:** ${complianceCerts}`);
497
+ else if (str(security.complianceFrameworks))
498
+ lines.push(`- **Compliance frameworks:** ${str(security.complianceFrameworks)}`);
499
+ if (privacyMeasures)
500
+ lines.push(`- **Data privacy measures:** ${privacyMeasures}`);
501
+ else if (str(security.dataPrivacy))
502
+ lines.push(`- **Data privacy:** ${str(security.dataPrivacy)}`);
503
+ lines.push('');
504
+ }
505
+ }
506
+ // Business operations
507
+ const ops = rec(bp.businessOperations);
508
+ const keyProcesses = arr(ops.keyProcesses);
509
+ const painPoints = arr(ops.painPoints);
510
+ const stakeholders = arr(ops.stakeholders);
511
+ if (keyProcesses.length > 0 || painPoints.length > 0) {
512
+ lines.push('## Business Operations', '');
513
+ if (keyProcesses.length > 0) {
514
+ lines.push('### Key Processes', '');
515
+ for (const proc of keyProcesses) {
516
+ const p = rec(proc);
517
+ const name = str(p.name) || str(p.processName);
518
+ const volume = str(p.volume) || str(p.transactionVolume);
519
+ if (name) {
520
+ lines.push(`- **${name}**${volume ? ` (${volume})` : ''}`);
521
+ if (str(p.frequency))
522
+ lines.push(` - Frequency: ${str(p.frequency)}`);
523
+ if (str(p.automationLevel))
524
+ lines.push(` - Automation level: ${str(p.automationLevel)}`);
525
+ }
526
+ }
527
+ lines.push('');
528
+ }
529
+ if (painPoints.length > 0) {
530
+ lines.push('### Operational Pain Points', '');
531
+ for (const pp of painPoints) {
532
+ if (typeof pp === 'string') {
533
+ lines.push(`- ${pp}`);
534
+ }
535
+ else {
536
+ const p = rec(pp);
537
+ const desc = str(p.description) || str(p.painPoint);
538
+ if (desc)
539
+ lines.push(`- ${desc}${str(p.severity) ? ` _(${str(p.severity)})_` : ''}`);
540
+ }
541
+ }
542
+ lines.push('');
543
+ }
544
+ if (stakeholders.length > 0) {
545
+ lines.push('### Key Stakeholders', '');
546
+ for (const sh of stakeholders) {
547
+ const s = rec(sh);
548
+ const role = str(s.role) || str(s.title);
549
+ const name = str(s.name);
550
+ if (role || name)
551
+ lines.push(`- **${role || name}**${name && role ? ` — ${name}` : ''}`);
552
+ }
553
+ lines.push('');
554
+ }
555
+ }
556
+ // Organizational capabilities
557
+ const caps = rec(bp.organizationalCapabilities);
558
+ const technicalTeam = rec(caps.technicalTeam);
559
+ const currentAutomation = rec(caps.currentAutomation);
560
+ const devCapacity = numStr(technicalTeam.developmentCapacity);
561
+ if (devCapacity || str(technicalTeam.size) || str(currentAutomation.level)) {
562
+ lines.push('## Organizational Capabilities', '');
563
+ if (devCapacity)
564
+ lines.push(`- **Development capacity:** ${devCapacity} FTEs`);
565
+ else if (str(technicalTeam.size))
566
+ lines.push(`- **Technical team size:** ${str(technicalTeam.size)}`);
567
+ if (str(technicalTeam.aiMlExperience))
568
+ lines.push(`- **AI/ML experience:** ${str(technicalTeam.aiMlExperience)}`);
569
+ else if (str(technicalTeam.aiExperience))
570
+ lines.push(`- **AI experience:** ${str(technicalTeam.aiExperience)}`);
571
+ if (str(currentAutomation.level))
572
+ lines.push(`- **Current automation level:** ${str(currentAutomation.level)}`);
573
+ const automatedProcesses = arrStr(currentAutomation.automatedProcesses);
574
+ if (automatedProcesses)
575
+ lines.push(`- **Automated processes:** ${automatedProcesses}`);
576
+ else if (str(currentAutomation.tools))
577
+ lines.push(`- **Automation tools:** ${str(currentAutomation.tools)}`);
578
+ lines.push('');
579
+ }
580
+ // Constraints
581
+ const constraints = rec(bp.constraintsProfile);
582
+ const budget = rec(constraints.budget);
583
+ const timeline = rec(constraints.timeline);
584
+ const technical = rec(constraints.technical);
585
+ const regulatory = rec(constraints.regulatory);
586
+ const totalBudget = str(budget.totalAiBudget) || str(budget.totalBudget);
587
+ const annualBudget = str(budget.annualOpexAvailable) || str(budget.annualBudget);
588
+ const deadlines = arrStr(timeline.criticalDeadlines);
589
+ const rolloutTimeline = str(timeline.fullRolloutTimeline) || str(timeline.preferredTimeline);
590
+ const legacyConstraints = arrStr(technical.legacySystemConstraints);
591
+ const regulations = arrStr(regulatory.industryRegulations);
592
+ if (totalBudget || deadlines || str(timeline.deadline) || regulations || str(regulatory.requirements)) {
593
+ lines.push('## Constraints', '');
594
+ if (totalBudget)
595
+ lines.push(`- **Budget:** ${totalBudget}`);
596
+ if (annualBudget)
597
+ lines.push(`- **Annual budget:** ${annualBudget}`);
598
+ if (deadlines)
599
+ lines.push(`- **Critical deadlines:** ${deadlines}`);
600
+ else if (str(timeline.deadline))
601
+ lines.push(`- **Deadline:** ${str(timeline.deadline)}`);
602
+ if (rolloutTimeline)
603
+ lines.push(`- **Rollout timeline:** ${rolloutTimeline}`);
604
+ if (legacyConstraints)
605
+ lines.push(`- **Legacy system constraints:** ${legacyConstraints}`);
606
+ else if (str(technical.limitations))
607
+ lines.push(`- **Technical limitations:** ${str(technical.limitations)}`);
608
+ if (regulations)
609
+ lines.push(`- **Industry regulations:** ${regulations}`);
610
+ else if (str(regulatory.requirements))
611
+ lines.push(`- **Regulatory:** ${str(regulatory.requirements)}`);
612
+ lines.push('');
613
+ }
614
+ // Strategic initiatives
615
+ const initiatives = arr(bp.strategicInitiatives);
616
+ if (initiatives.length > 0) {
617
+ lines.push('## Strategic Initiatives', '');
618
+ for (const init of initiatives) {
619
+ const i = rec(init);
620
+ const title = str(i.title);
621
+ if (title) {
622
+ lines.push(`### ${title}`, '');
623
+ if (str(i.description))
624
+ lines.push(str(i.description), '');
625
+ if (str(i.priority))
626
+ lines.push(`- **Priority:** ${str(i.priority)}`);
627
+ if (str(i.status))
628
+ lines.push(`- **Status:** ${str(i.status)}`);
629
+ if (str(i.budget))
630
+ lines.push(`- **Budget:** ${str(i.budget)}`);
631
+ if (str(i.timeline))
632
+ lines.push(`- **Timeline:** ${str(i.timeline)}`);
633
+ const outcomes = arr(i.expectedOutcomes);
634
+ if (outcomes.length > 0) {
635
+ lines.push('- **Expected outcomes:**');
636
+ for (const o of outcomes)
637
+ lines.push(` - ${o}`);
638
+ }
639
+ lines.push('');
640
+ }
641
+ }
642
+ }
643
+ // AI readiness
644
+ if (bp.aiReadinessScore !== null && bp.aiReadinessScore !== undefined) {
645
+ lines.push('## AI Readiness', '');
646
+ lines.push(`- **Score:** ${bp.aiReadinessScore}/100`);
647
+ lines.push('');
648
+ }
649
+ return lines.join('\n');
650
+ }
347
651
  function buildAgentSpecifications(input) {
348
652
  const bp = input.blueprintData;
349
653
  const team = getTeam(bp);
@@ -351,7 +655,7 @@ function buildAgentSpecifications(input) {
351
655
  for (const agent of team) {
352
656
  const name = str(agent.name);
353
657
  lines.push(`## ${name}`, '');
354
- const role = str(agent.role);
658
+ const role = str(agent.role) || str(rec(agent.instructions).role);
355
659
  const type = str(agent.agentRole) || str(agent.orchestrationRole) || str(agent.type) || 'Worker';
356
660
  const supervision = str(agent.supervisionLevel) || 'Supervised';
357
661
  lines.push(`- **Role:** ${role}`);
@@ -388,7 +692,7 @@ function buildAgentSpecifications(input) {
388
692
  const t = rec(tool);
389
693
  const tName = str(t.name);
390
694
  const tCat = str(t.toolCategory) || str(t.type) || '';
391
- const tDesc = str(t.description).replace(/\|/g, '\\|').slice(0, 100);
695
+ const tDesc = str(t.description).replace(/\|/g, '\\|');
392
696
  lines.push(`| ${tName} | ${tCat} | ${tDesc} |`);
393
697
  }
394
698
  lines.push('');
@@ -410,10 +714,12 @@ function buildAgentSpecifications(input) {
410
714
  lines.push('');
411
715
  }
412
716
  const risk = rec(agent.riskAssessment);
413
- if (str(risk.level)) {
717
+ if (str(risk.level) && !isPlaceholder(str(risk.level))) {
414
718
  lines.push('### Risk Assessment', '');
415
719
  lines.push(`- **Level:** ${str(risk.level)}`);
416
- lines.push(`- **Impact:** ${str(risk.impact)}`);
720
+ const riskImpact = str(risk.impact);
721
+ if (riskImpact && !isPlaceholder(riskImpact))
722
+ lines.push(`- **Impact:** ${riskImpact}`);
417
723
  const controls = arr(risk.controls);
418
724
  if (controls.length > 0) {
419
725
  lines.push('- **Controls:**');
@@ -476,64 +782,90 @@ function buildFinancialCase(input) {
476
782
  }
477
783
  const benefits = rec(bc.benefits);
478
784
  const qROI = rec(benefits.quantifiedROI);
479
- if (str(qROI.roi) || str(qROI.npv) || str(qROI.paybackPeriod)) {
785
+ const roiVal = str(qROI.roi);
786
+ const npvVal = str(qROI.npv);
787
+ const paybackVal = str(qROI.paybackPeriod);
788
+ if ((roiVal && !isPlaceholder(roiVal)) || (npvVal && !isPlaceholder(npvVal)) || (paybackVal && !isPlaceholder(paybackVal))) {
480
789
  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)}`);
790
+ if (roiVal && !isPlaceholder(roiVal))
791
+ lines.push(`- **ROI:** ${roiVal}`);
792
+ if (npvVal && !isPlaceholder(npvVal))
793
+ lines.push(`- **NPV:** ${npvVal}`);
794
+ if (paybackVal && !isPlaceholder(paybackVal))
795
+ lines.push(`- **Payback period:** ${paybackVal}`);
487
796
  lines.push('');
488
797
  }
798
+ // Labor cost detail (nested object: currentStateBaseline / projectedSavings)
489
799
  const laborDetail = rec(qROI.laborCostDetail);
490
- if (str(laborDetail.annualLaborCost) || str(laborDetail.avgFullyLoadedRate)) {
800
+ const currentBaseline = rec(laborDetail.currentStateBaseline);
801
+ const projectedSavings = rec(laborDetail.projectedSavings);
802
+ const blendedRate = str(rec(currentBaseline.blendedHourlyRate).value);
803
+ const totalAnnualCost = str(rec(currentBaseline.totalAnnualCost).value);
804
+ const totalAnnualHours = str(rec(currentBaseline.totalAnnualHours).value);
805
+ const costSavingsAnnual = str(rec(projectedSavings.costSavingsAnnual).value);
806
+ if (totalAnnualCost || blendedRate) {
491
807
  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)}`);
808
+ if (blendedRate)
809
+ lines.push(`- **Avg. fully-loaded rate:** ${blendedRate}`);
810
+ if (totalAnnualCost)
811
+ lines.push(`- **Annual labor cost:** ${totalAnnualCost}`);
812
+ if (totalAnnualHours)
813
+ lines.push(`- **Annual hours affected:** ${totalAnnualHours}`);
814
+ if (costSavingsAnnual)
815
+ lines.push(`- **Automation savings:** ${costSavingsAnnual}`);
500
816
  lines.push('');
501
817
  }
818
+ // Cost breakdown (each field is { value, notes?, source? })
502
819
  const costBreakdown = rec(qROI.costBreakdown);
503
- if (str(costBreakdown.implementation) || str(costBreakdown.annualLicensing)) {
820
+ const cbImpl = str(rec(costBreakdown.implementation).value);
821
+ const cbLic = str(rec(costBreakdown.annualLicensing).value);
822
+ const cbSupport = str(rec(costBreakdown.annualSupportMaintenance).value);
823
+ if (cbImpl || cbLic) {
504
824
  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)}`);
825
+ if (cbImpl)
826
+ lines.push(`- **Implementation:** ${cbImpl}`);
827
+ if (cbLic)
828
+ lines.push(`- **Annual licensing:** ${cbLic}`);
829
+ if (cbSupport)
830
+ lines.push(`- **Annual support/maintenance:** ${cbSupport}`);
511
831
  lines.push('');
512
832
  }
833
+ // Pilot ROI (nested: pilotCapex/pilotOpex/pilotAnnualSavings/pilotYear1Net are { value, calculation })
513
834
  const pilotROI = rec(qROI.pilotROI);
514
- if (str(pilotROI.pilotCost) || str(pilotROI.pilotBenefit)) {
835
+ const pilotCapex = str(rec(pilotROI.pilotCapex).value);
836
+ const pilotOpex = str(rec(pilotROI.pilotOpex).value);
837
+ const pilotSavings = str(rec(pilotROI.pilotAnnualSavings).value);
838
+ const pilotYear1Net = str(rec(pilotROI.pilotYear1Net).value);
839
+ const pilotPayback = numStr(pilotROI.pilotPaybackMonths);
840
+ if (pilotCapex || pilotSavings) {
515
841
  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)}`);
842
+ if (pilotCapex)
843
+ lines.push(`- **Pilot capex:** ${pilotCapex}`);
844
+ if (pilotOpex)
845
+ lines.push(`- **Pilot opex:** ${pilotOpex}`);
846
+ if (pilotSavings)
847
+ lines.push(`- **Pilot annual savings:** ${pilotSavings}`);
848
+ if (pilotYear1Net)
849
+ lines.push(`- **Pilot Year 1 net:** ${pilotYear1Net}`);
850
+ if (pilotPayback)
851
+ lines.push(`- **Payback:** ${stripTrailingUnit(pilotPayback, 'months')} months`);
524
852
  lines.push('');
525
853
  }
854
+ // Sensitivity analysis (roiPercentage, paybackMonths, annualSavings — all numbers/strings)
526
855
  const sensitivity = rec(qROI.sensitivity);
527
856
  if (sensitivity.conservative || sensitivity.realistic || sensitivity.optimistic) {
528
857
  lines.push('## Sensitivity Analysis', '');
529
- lines.push('| Scenario | NPV | ROI | Payback |');
530
- lines.push('|----------|-----|-----|---------|');
858
+ lines.push('| Scenario | ROI | Payback | Annual Savings |');
859
+ lines.push('|----------|-----|---------|----------------|');
531
860
  for (const [label, key] of [['Conservative', 'conservative'], ['Realistic', 'realistic'], ['Optimistic', 'optimistic']]) {
532
861
  const s = rec(sensitivity[key]);
533
- lines.push(`| ${label} | ${str(s.npv)} | ${str(s.roi)} | ${str(s.paybackPeriod)} |`);
862
+ const roi = numStr(s.roiPercentage);
863
+ const payback = numStr(s.paybackMonths);
864
+ lines.push(`| ${label} | ${roi ? stripTrailingUnit(roi, '%') + '%' : ''} | ${payback ? stripTrailingUnit(payback, 'months') + ' months' : ''} | ${str(s.annualSavings)} |`);
534
865
  }
535
866
  lines.push('');
536
867
  }
868
+ // 5-year projection (calculator uses costsThisYear/valueDelivered/netThisYear/runningTotal)
537
869
  const fiveYear = arr(qROI.fiveYearProjection);
538
870
  if (fiveYear.length > 0) {
539
871
  lines.push('## Five-Year Projection', '');
@@ -541,7 +873,7 @@ function buildFinancialCase(input) {
541
873
  lines.push('|------|-----------|-------|---------------|------------|');
542
874
  for (const yr of fiveYear) {
543
875
  const y = rec(yr);
544
- lines.push(`| ${str(y.year)} | ${str(y.investment)} | ${str(y.value)} | ${str(y.netCashFlow)} | ${str(y.cumulative)} |`);
876
+ lines.push(`| ${numStr(y.year)} | ${str(y.costsThisYear) || str(y.investment)} | ${str(y.valueDelivered) || str(y.value)} | ${str(y.netThisYear) || str(y.netCashFlow)} | ${str(y.runningTotal) || str(y.cumulative)} |`);
545
877
  }
546
878
  lines.push('');
547
879
  }
@@ -558,6 +890,26 @@ function buildFinancialCase(input) {
558
890
  lines.push(`- **Time to market:** ${str(tangible.timeToMarket)}`);
559
891
  lines.push('');
560
892
  }
893
+ // Recommendation
894
+ const recommendation = rec(bc.recommendation);
895
+ if (str(recommendation.summary) || str(recommendation.decisionRequest)) {
896
+ lines.push('## Recommendation', '');
897
+ if (str(recommendation.summary))
898
+ lines.push(str(recommendation.summary), '');
899
+ if (str(recommendation.decisionRequest)) {
900
+ lines.push(`**Decision request:** ${str(recommendation.decisionRequest)}`, '');
901
+ }
902
+ const immediateActions = arr(recommendation.immediateActions);
903
+ if (immediateActions.length > 0) {
904
+ lines.push('**Immediate actions upon approval:**', '');
905
+ for (const action of immediateActions)
906
+ lines.push(`1. ${action}`);
907
+ lines.push('');
908
+ }
909
+ if (str(recommendation.blueprintImplementationRef)) {
910
+ lines.push(`> ${str(recommendation.blueprintImplementationRef)}`, '');
911
+ }
912
+ }
561
913
  return lines.join('\n');
562
914
  }
563
915
  function buildImplementationRoadmap(input) {
@@ -783,12 +1135,14 @@ function buildArchitectureDecisions(input) {
783
1135
  }
784
1136
  }
785
1137
  const feasibility = rec(bp.feasibilityIndicators);
786
- if (str(feasibility.overallScore) || str(feasibility.recommendation)) {
1138
+ const feasConfidence = str(feasibility.feasibilityConfidence) || str(feasibility.overallScore);
1139
+ const feasBasis = str(feasibility.feasibilityBasis) || str(feasibility.recommendation);
1140
+ if (feasConfidence || feasBasis) {
787
1141
  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)}`);
1142
+ if (feasConfidence)
1143
+ lines.push(`**Confidence:** ${feasConfidence}`);
1144
+ if (feasBasis)
1145
+ lines.push(`**Basis:** ${feasBasis}`);
792
1146
  lines.push('');
793
1147
  }
794
1148
  return lines.join('\n');
@@ -849,8 +1203,12 @@ function buildGuardrailsAndGovernance(input) {
849
1203
  lines.push('');
850
1204
  }
851
1205
  const risk = rec(agent.riskAssessment);
852
- if (str(risk.level)) {
853
- lines.push(`**Risk:** ${str(risk.level)} ${str(risk.impact)}`);
1206
+ if (str(risk.level) && !isPlaceholder(str(risk.level))) {
1207
+ const impactStr = str(risk.impact);
1208
+ const riskLine = impactStr && !isPlaceholder(impactStr)
1209
+ ? `**Risk:** ${str(risk.level)} — ${impactStr}`
1210
+ : `**Risk:** ${str(risk.level)}`;
1211
+ lines.push(riskLine);
854
1212
  lines.push('');
855
1213
  }
856
1214
  }
@@ -944,6 +1302,7 @@ fi
944
1302
  echo ""
945
1303
  echo "--- Optional Files ---"
946
1304
  check_optional "references/business-context.md"
1305
+ check_optional "references/organization-context.md"
947
1306
  check_optional "references/financial-case.md"
948
1307
  check_optional "references/implementation-roadmap.md"
949
1308
  check_optional "references/guardrails-and-governance.md"
@@ -977,6 +1336,7 @@ export function renderSkillDirectory(input) {
977
1336
  files.set('SKILL.md', `${frontmatter}\n\n${body}`);
978
1337
  // Reference files
979
1338
  files.set('references/business-context.md', buildBusinessContext(input));
1339
+ files.set('references/organization-context.md', buildOrganizationContext(input));
980
1340
  files.set('references/agent-specifications.md', buildAgentSpecifications(input));
981
1341
  files.set('references/financial-case.md', buildFinancialCase(input));
982
1342
  files.set('references/implementation-roadmap.md', buildImplementationRoadmap(input));