forgesmith 0.7.0 → 0.7.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/index.cjs +584 -4
- package/dist/index.d.cts +204 -3
- package/dist/index.d.ts +204 -3
- package/dist/index.mjs +582 -5
- package/dist/server.cjs +584 -4
- package/dist/server.d.cts +204 -3
- package/dist/server.d.ts +204 -3
- package/dist/server.mjs +582 -5
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -3540,6 +3540,583 @@ async function generateKnowledgeCapture(options) {
|
|
|
3540
3540
|
return buildFallback7(options);
|
|
3541
3541
|
}
|
|
3542
3542
|
|
|
3543
|
+
// src/generators/generateApiChangelog.ts
|
|
3544
|
+
function buildPromptContext(opts) {
|
|
3545
|
+
const { apiChangeContext: ctx, amberContext, gitContext } = opts;
|
|
3546
|
+
const lines = [
|
|
3547
|
+
`## Change Range`,
|
|
3548
|
+
`From: ${ctx.from} To: ${ctx.to}`,
|
|
3549
|
+
`Total API changes: ${ctx.totalChanged}`,
|
|
3550
|
+
``
|
|
3551
|
+
];
|
|
3552
|
+
if (ctx.breakingChanges.length > 0) {
|
|
3553
|
+
lines.push(`## Breaking Changes (${ctx.breakingChanges.length})`);
|
|
3554
|
+
for (const c of ctx.breakingChanges) {
|
|
3555
|
+
const capHint = c.capabilityName ? ` [${c.capabilityName}]` : "";
|
|
3556
|
+
lines.push(`- ${c.endpoint}${capHint} \u2014 ${c.description ?? "no description"} (file: ${c.file})`);
|
|
3557
|
+
}
|
|
3558
|
+
lines.push("");
|
|
3559
|
+
}
|
|
3560
|
+
if (ctx.newEndpoints.length > 0) {
|
|
3561
|
+
lines.push(`## New Endpoints (${ctx.newEndpoints.length})`);
|
|
3562
|
+
for (const c of ctx.newEndpoints) {
|
|
3563
|
+
const capHint = c.capabilityName ? ` [${c.capabilityName}]` : "";
|
|
3564
|
+
lines.push(`- ${c.endpoint}${capHint} \u2014 ${c.description ?? "new"} (file: ${c.file})`);
|
|
3565
|
+
}
|
|
3566
|
+
lines.push("");
|
|
3567
|
+
}
|
|
3568
|
+
if (ctx.removedEndpoints.length > 0) {
|
|
3569
|
+
lines.push(`## Removed Endpoints (${ctx.removedEndpoints.length})`);
|
|
3570
|
+
for (const c of ctx.removedEndpoints) {
|
|
3571
|
+
lines.push(`- ${c.endpoint} \u2014 removed from ${c.file}`);
|
|
3572
|
+
}
|
|
3573
|
+
lines.push("");
|
|
3574
|
+
}
|
|
3575
|
+
const modified = ctx.changes.filter((c) => c.changeType === "modified");
|
|
3576
|
+
if (modified.length > 0) {
|
|
3577
|
+
lines.push(`## Modified Endpoints (${modified.length})`);
|
|
3578
|
+
for (const c of modified) {
|
|
3579
|
+
const capHint = c.capabilityName ? ` [${c.capabilityName}]` : "";
|
|
3580
|
+
lines.push(`- ${c.endpoint}${capHint} \u2014 ${c.description ?? "modified"} (file: ${c.file})`);
|
|
3581
|
+
}
|
|
3582
|
+
lines.push("");
|
|
3583
|
+
}
|
|
3584
|
+
if (amberContext) {
|
|
3585
|
+
lines.push(`## AMBER Capability Context`, amberContext.summary, "");
|
|
3586
|
+
}
|
|
3587
|
+
if (gitContext && gitContext.commitMessages.length > 0) {
|
|
3588
|
+
lines.push(
|
|
3589
|
+
`## Recent Commits`,
|
|
3590
|
+
...gitContext.commitMessages.slice(0, 8).map((m) => `- ${m}`),
|
|
3591
|
+
""
|
|
3592
|
+
);
|
|
3593
|
+
}
|
|
3594
|
+
return lines.join("\n");
|
|
3595
|
+
}
|
|
3596
|
+
function buildSystemPrompt14(audience, format) {
|
|
3597
|
+
const audienceDesc = audience === "external" ? "external API consumers (third-party developers)" : audience === "partner" ? "integration partners with existing API contracts" : "internal engineering teams";
|
|
3598
|
+
const formatDesc = format === "migration-guide" ? "a step-by-step migration guide with code examples" : format === "release-notes" ? "polished release notes suitable for a public changelog page" : "a structured API changelog";
|
|
3599
|
+
return `You are a developer relations engineer writing ${formatDesc} for ${audienceDesc}. Be precise about endpoint paths, HTTP methods, and request/response changes. For breaking changes, always include a migration path. Generate ONLY valid JSON \u2014 no markdown fences, no prose outside the JSON object.`;
|
|
3600
|
+
}
|
|
3601
|
+
function buildUserPrompt14(opts, context) {
|
|
3602
|
+
const { projectName, version, targetAudience, format } = opts;
|
|
3603
|
+
const v = version || opts.apiChangeContext.to;
|
|
3604
|
+
return [
|
|
3605
|
+
`Generate an API ${format} for: ${projectName}`,
|
|
3606
|
+
`Version: ${v}`,
|
|
3607
|
+
`Target audience: ${targetAudience}`,
|
|
3608
|
+
`Format: ${format}`,
|
|
3609
|
+
``,
|
|
3610
|
+
context,
|
|
3611
|
+
``,
|
|
3612
|
+
`## Output Format`,
|
|
3613
|
+
`Return a single JSON object with this EXACT shape:`,
|
|
3614
|
+
`{`,
|
|
3615
|
+
` "version": "<version string>",`,
|
|
3616
|
+
` "date": "<ISO date YYYY-MM-DD>",`,
|
|
3617
|
+
` "targetAudience": "<audience>",`,
|
|
3618
|
+
` "breakingChanges": [`,
|
|
3619
|
+
` { "endpoint": "<METHOD /path>", "description": "<what changed>", "migration": "<how to migrate>" }`,
|
|
3620
|
+
` ],`,
|
|
3621
|
+
` "newFeatures": [`,
|
|
3622
|
+
` { "endpoint": "<METHOD /path>", "description": "<what it does>", "example": "<optional curl/code hint>" }`,
|
|
3623
|
+
` ],`,
|
|
3624
|
+
` "improvements": [`,
|
|
3625
|
+
` { "endpoint": "<METHOD /path>", "description": "<what improved>" }`,
|
|
3626
|
+
` ],`,
|
|
3627
|
+
` "deprecations": [`,
|
|
3628
|
+
` { "endpoint": "<METHOD /path>", "description": "<what is deprecated>", "sunset": "<optional date>" }`,
|
|
3629
|
+
` ],`,
|
|
3630
|
+
` "migrationGuide": "<full migration guidance as prose \u2014 2\u20135 paragraphs>",`,
|
|
3631
|
+
` "consumerImpactSummary": "<1 paragraph copy-ready summary for consumers>"`,
|
|
3632
|
+
`}`,
|
|
3633
|
+
``,
|
|
3634
|
+
`Rules:`,
|
|
3635
|
+
`- Every breaking change MUST have a non-empty migration string.`,
|
|
3636
|
+
`- For external/partner audiences, omit internal implementation details.`,
|
|
3637
|
+
`- migrationGuide should be empty string if no breaking changes.`,
|
|
3638
|
+
`- Return ONLY valid JSON. No markdown fences.`
|
|
3639
|
+
].join("\n");
|
|
3640
|
+
}
|
|
3641
|
+
function buildFallback8(opts) {
|
|
3642
|
+
const ctx = opts.apiChangeContext;
|
|
3643
|
+
const v = opts.version ?? ctx.to;
|
|
3644
|
+
return {
|
|
3645
|
+
version: v,
|
|
3646
|
+
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3647
|
+
targetAudience: opts.targetAudience,
|
|
3648
|
+
breakingChanges: ctx.breakingChanges.map((c) => ({
|
|
3649
|
+
endpoint: c.endpoint,
|
|
3650
|
+
description: c.description ?? "Breaking change detected",
|
|
3651
|
+
migration: "Review the updated API contract and update your client accordingly."
|
|
3652
|
+
})),
|
|
3653
|
+
newFeatures: ctx.newEndpoints.map((c) => ({
|
|
3654
|
+
endpoint: c.endpoint,
|
|
3655
|
+
description: c.description ?? "New endpoint added"
|
|
3656
|
+
})),
|
|
3657
|
+
improvements: ctx.changes.filter((c) => c.changeType === "modified").map((c) => ({
|
|
3658
|
+
endpoint: c.endpoint,
|
|
3659
|
+
description: c.description ?? "Endpoint updated"
|
|
3660
|
+
})),
|
|
3661
|
+
deprecations: ctx.removedEndpoints.map((c) => ({
|
|
3662
|
+
endpoint: c.endpoint,
|
|
3663
|
+
description: "This endpoint has been removed."
|
|
3664
|
+
})),
|
|
3665
|
+
migrationGuide: ctx.breakingChanges.length > 0 ? `This release contains ${ctx.breakingChanges.length} breaking change(s). Review the breaking changes section and update your API client before deploying. Test all affected endpoints in a staging environment.` : "",
|
|
3666
|
+
consumerImpactSummary: `Version ${v} includes ${ctx.newEndpoints.length} new endpoint(s), ${ctx.breakingChanges.length} breaking change(s), and ${ctx.changes.filter((c) => c.changeType === "modified").length} improvement(s). ` + (ctx.breakingChanges.length > 0 ? "Migration is required before upgrading." : "This release is backward-compatible.")
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3669
|
+
function parseLlmResponse8(raw) {
|
|
3670
|
+
let text = raw.trim();
|
|
3671
|
+
if (text.startsWith("```")) {
|
|
3672
|
+
text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
3673
|
+
}
|
|
3674
|
+
let parsed;
|
|
3675
|
+
try {
|
|
3676
|
+
parsed = JSON.parse(text);
|
|
3677
|
+
} catch {
|
|
3678
|
+
return null;
|
|
3679
|
+
}
|
|
3680
|
+
function parseChangeArray(key, required) {
|
|
3681
|
+
if (!Array.isArray(parsed[key])) return [];
|
|
3682
|
+
return parsed[key].filter((item) => {
|
|
3683
|
+
if (typeof item !== "object" || item === null) return false;
|
|
3684
|
+
return required.every((k) => k in item);
|
|
3685
|
+
});
|
|
3686
|
+
}
|
|
3687
|
+
return {
|
|
3688
|
+
version: typeof parsed.version === "string" ? parsed.version : "",
|
|
3689
|
+
date: typeof parsed.date === "string" ? parsed.date : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3690
|
+
targetAudience: typeof parsed.targetAudience === "string" ? parsed.targetAudience : "",
|
|
3691
|
+
breakingChanges: parseChangeArray("breakingChanges", ["endpoint", "description", "migration"]),
|
|
3692
|
+
newFeatures: parseChangeArray("newFeatures", ["endpoint", "description"]),
|
|
3693
|
+
improvements: parseChangeArray("improvements", ["endpoint", "description"]),
|
|
3694
|
+
deprecations: parseChangeArray("deprecations", ["endpoint", "description"]),
|
|
3695
|
+
migrationGuide: typeof parsed.migrationGuide === "string" ? parsed.migrationGuide : "",
|
|
3696
|
+
consumerImpactSummary: typeof parsed.consumerImpactSummary === "string" ? parsed.consumerImpactSummary : ""
|
|
3697
|
+
};
|
|
3698
|
+
}
|
|
3699
|
+
async function generateApiChangelog(opts) {
|
|
3700
|
+
const context = buildPromptContext(opts);
|
|
3701
|
+
try {
|
|
3702
|
+
const response = await opts.llm.complete({
|
|
3703
|
+
systemPrompt: buildSystemPrompt14(opts.targetAudience, opts.format),
|
|
3704
|
+
messages: [{ role: "user", content: buildUserPrompt14(opts, context) }],
|
|
3705
|
+
maxTokens: 3072
|
|
3706
|
+
});
|
|
3707
|
+
const parsed = parseLlmResponse8(response.content);
|
|
3708
|
+
if (parsed) return parsed;
|
|
3709
|
+
} catch {
|
|
3710
|
+
}
|
|
3711
|
+
return buildFallback8(opts);
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
// src/generators/generateChangeImpactBrief.ts
|
|
3715
|
+
function buildPromptContext2(opts) {
|
|
3716
|
+
const { gitContext, changeImpactContext: ctx, amberContext, greenContext } = opts;
|
|
3717
|
+
const lines = [
|
|
3718
|
+
`## Change Range`,
|
|
3719
|
+
`From: ${ctx.from}`,
|
|
3720
|
+
`To: ${ctx.to}`,
|
|
3721
|
+
`Commits: ${ctx.commitCount}`,
|
|
3722
|
+
`Files changed: ${ctx.filesChanged.length}`,
|
|
3723
|
+
``,
|
|
3724
|
+
`## Changed Files (sample)`,
|
|
3725
|
+
...ctx.filesChanged.slice(0, 20).map((f) => `- ${f}`)
|
|
3726
|
+
];
|
|
3727
|
+
if (ctx.breakingChanges.length > 0) {
|
|
3728
|
+
lines.push(``, `## Breaking Changes`, ...ctx.breakingChanges.map((b) => `- ${b}`));
|
|
3729
|
+
}
|
|
3730
|
+
if (ctx.affectedCapabilities.length > 0) {
|
|
3731
|
+
lines.push(``, `## Affected Business Capabilities`);
|
|
3732
|
+
for (const cap of ctx.affectedCapabilities) {
|
|
3733
|
+
lines.push(
|
|
3734
|
+
`- [${cap.criticality.toUpperCase()}] ${cap.name} (${cap.changedFiles.length} files changed, drift: ${cap.driftCount})`
|
|
3735
|
+
);
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
if (ctx.regulatoryCapabilities.length > 0) {
|
|
3739
|
+
lines.push(
|
|
3740
|
+
``,
|
|
3741
|
+
`## Critical Capabilities Touched (require approval)`,
|
|
3742
|
+
...ctx.regulatoryCapabilities.map((c) => `- ${c}`)
|
|
3743
|
+
);
|
|
3744
|
+
}
|
|
3745
|
+
if (ctx.coherenceScoreBefore !== null || ctx.coherenceScoreAfter !== null) {
|
|
3746
|
+
lines.push(
|
|
3747
|
+
``,
|
|
3748
|
+
`## Architecture Coherence`,
|
|
3749
|
+
`Score before: ${ctx.coherenceScoreBefore ?? "unknown"}`,
|
|
3750
|
+
`Score after: ${ctx.coherenceScoreAfter ?? "unknown"}`,
|
|
3751
|
+
`Delta: ${ctx.coherenceDelta !== null ? (ctx.coherenceDelta > 0 ? "+" : "") + ctx.coherenceDelta : "unknown"}`
|
|
3752
|
+
);
|
|
3753
|
+
}
|
|
3754
|
+
if (ctx.topRisks.length > 0) {
|
|
3755
|
+
lines.push(``, `## Top Risks`, ...ctx.topRisks.map((r) => `- ${r}`));
|
|
3756
|
+
}
|
|
3757
|
+
if (amberContext) {
|
|
3758
|
+
lines.push(``, `## AMBER Layer Context`, amberContext.summary);
|
|
3759
|
+
}
|
|
3760
|
+
if (greenContext) {
|
|
3761
|
+
lines.push(``, `## GREEN Layer Context`, greenContext.summary);
|
|
3762
|
+
}
|
|
3763
|
+
if (gitContext.commitMessages.length > 0) {
|
|
3764
|
+
lines.push(
|
|
3765
|
+
``,
|
|
3766
|
+
`## Recent Commit Messages (sample)`,
|
|
3767
|
+
...gitContext.commitMessages.slice(0, 10).map((m) => `- ${m}`)
|
|
3768
|
+
);
|
|
3769
|
+
}
|
|
3770
|
+
return lines.join("\n");
|
|
3771
|
+
}
|
|
3772
|
+
function buildSystemPrompt15(audience) {
|
|
3773
|
+
if (audience === "executive") {
|
|
3774
|
+
return "You are a VP of Engineering preparing a release briefing for the CTO and board. Write in plain business language \u2014 no jargon, no technical acronyms. Be direct about risks. Generate ONLY valid JSON \u2014 no markdown fences, no prose outside the JSON.";
|
|
3775
|
+
}
|
|
3776
|
+
if (audience === "cab") {
|
|
3777
|
+
return "You are a senior engineering manager preparing a Change Advisory Board (CAB) submission. Balance technical precision with business impact. Highlight rollback complexity and compliance implications. Generate ONLY valid JSON \u2014 no markdown fences, no prose outside the JSON.";
|
|
3778
|
+
}
|
|
3779
|
+
return "You are a principal engineer preparing a technical change impact brief. Be precise about files, capabilities, and risk vectors. Generate ONLY valid JSON \u2014 no markdown fences, no prose outside the JSON.";
|
|
3780
|
+
}
|
|
3781
|
+
function buildUserPrompt15(opts, context) {
|
|
3782
|
+
const { projectName, releaseVersion, audience } = opts;
|
|
3783
|
+
const version = releaseVersion || opts.changeImpactContext.to;
|
|
3784
|
+
return [
|
|
3785
|
+
`Generate a change impact brief for: ${projectName}`,
|
|
3786
|
+
`Release version: ${version}`,
|
|
3787
|
+
`Audience: ${audience}`,
|
|
3788
|
+
``,
|
|
3789
|
+
context,
|
|
3790
|
+
``,
|
|
3791
|
+
`## Output Format`,
|
|
3792
|
+
`Return a single JSON object with this EXACT shape:`,
|
|
3793
|
+
`{`,
|
|
3794
|
+
` "title": "<brief title>",`,
|
|
3795
|
+
` "releaseVersion": "<version string>",`,
|
|
3796
|
+
` "date": "<ISO date>",`,
|
|
3797
|
+
` "audience": "<audience>",`,
|
|
3798
|
+
` "executiveSummary": "<3 bullet points separated by \\n, plain language, max 120 chars each>",`,
|
|
3799
|
+
` "technicalSummary": "<2-3 sentences for CAB technical reviewers>",`,
|
|
3800
|
+
` "affectedBusinessAreas": ["<area 1>", "<area 2>"],`,
|
|
3801
|
+
` "riskLevel": "<one of: low | medium | high | critical>",`,
|
|
3802
|
+
` "riskJustification": "<1-2 sentences explaining the risk rating>",`,
|
|
3803
|
+
` "complianceImpact": "<which regulated capabilities are touched, or 'None' if clean>",`,
|
|
3804
|
+
` "rollbackComplexity": "<one of: simple | moderate | complex>",`,
|
|
3805
|
+
` "rollbackGuidance": "<concise rollback instructions>",`,
|
|
3806
|
+
` "recommendedActions": ["<action 1>", "<action 2>", "<action 3>"],`,
|
|
3807
|
+
` "approvalRequired": <true | false>,`,
|
|
3808
|
+
` "metrics": {`,
|
|
3809
|
+
` "commits": <number>,`,
|
|
3810
|
+
` "filesChanged": <number>,`,
|
|
3811
|
+
` "capabilitiesAffected": <number>,`,
|
|
3812
|
+
` "coherenceDelta": <number | null>`,
|
|
3813
|
+
` }`,
|
|
3814
|
+
`}`,
|
|
3815
|
+
``,
|
|
3816
|
+
`Rules:`,
|
|
3817
|
+
`- riskLevel = "critical" if any critical capabilities touched OR breaking changes exist.`,
|
|
3818
|
+
`- riskLevel = "high" if 3+ capabilities affected or coherenceDelta < -5.`,
|
|
3819
|
+
`- approvalRequired = true if riskLevel is "critical" or "high".`,
|
|
3820
|
+
`- rollbackComplexity = "complex" if breaking changes or critical capabilities touched.`,
|
|
3821
|
+
`- executiveSummary must be EXACTLY 3 bullet lines joined by \\n \u2014 each starting with a dash.`,
|
|
3822
|
+
`- Return ONLY valid JSON. No markdown. No prose outside the JSON object.`
|
|
3823
|
+
].join("\n");
|
|
3824
|
+
}
|
|
3825
|
+
function buildFallback9(opts) {
|
|
3826
|
+
const ctx = opts.changeImpactContext;
|
|
3827
|
+
const hasCritical = ctx.regulatoryCapabilities.length > 0 || ctx.breakingChanges.length > 0;
|
|
3828
|
+
const hasHigh = ctx.affectedCapabilities.filter((c) => c.criticality === "high").length >= 2;
|
|
3829
|
+
const riskLevel = hasCritical ? "critical" : hasHigh || ctx.affectedCapabilities.length >= 3 ? "high" : ctx.affectedCapabilities.length >= 1 ? "medium" : "low";
|
|
3830
|
+
const approvalRequired = riskLevel === "critical" || riskLevel === "high";
|
|
3831
|
+
const rollbackComplexity = hasCritical ? "complex" : ctx.affectedCapabilities.length >= 3 ? "moderate" : "simple";
|
|
3832
|
+
return {
|
|
3833
|
+
title: `Change Impact Brief \u2014 ${opts.projectName}`,
|
|
3834
|
+
releaseVersion: opts.releaseVersion ?? ctx.to,
|
|
3835
|
+
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3836
|
+
audience: opts.audience,
|
|
3837
|
+
executiveSummary: `- ${ctx.commitCount} commit(s) deployed across ${ctx.filesChanged.length} files
|
|
3838
|
+
- ${ctx.affectedCapabilities.length} business capability(ies) affected
|
|
3839
|
+
- Risk level: ${riskLevel.toUpperCase()}${hasCritical ? " \u2014 critical capabilities touched" : ""}`,
|
|
3840
|
+
technicalSummary: `${ctx.commitCount} commit(s) between ${ctx.from} and ${ctx.to}, changing ${ctx.filesChanged.length} file(s). ` + (ctx.breakingChanges.length > 0 ? `${ctx.breakingChanges.length} breaking change(s) detected. ` : "") + (ctx.coherenceDelta !== null ? `Coherence score moved ${ctx.coherenceDelta > 0 ? "+" : ""}${ctx.coherenceDelta}.` : ""),
|
|
3841
|
+
affectedBusinessAreas: ctx.affectedCapabilities.map((c) => c.name),
|
|
3842
|
+
riskLevel,
|
|
3843
|
+
riskJustification: hasCritical ? "Critical business capabilities were modified, requiring formal CAB sign-off." : `${ctx.affectedCapabilities.length} capabilities affected with potential for regression.`,
|
|
3844
|
+
complianceImpact: ctx.regulatoryCapabilities.length > 0 ? ctx.regulatoryCapabilities.join(", ") : "None",
|
|
3845
|
+
rollbackComplexity,
|
|
3846
|
+
rollbackGuidance: rollbackComplexity === "complex" ? "Prepare a full environment snapshot before deploying. Coordinate rollback with database team if schema changes exist." : rollbackComplexity === "moderate" ? "Tag the current deployment. Roll back using git revert on the merge commit." : "Revert the feature flag or redeploy the previous container image.",
|
|
3847
|
+
recommendedActions: [
|
|
3848
|
+
approvalRequired ? "Obtain formal CAB sign-off before deploying to production" : "Deploy during low-traffic window",
|
|
3849
|
+
ctx.breakingChanges.length > 0 ? "Notify API consumers of breaking changes at least 48h in advance" : "Run full regression suite",
|
|
3850
|
+
"Monitor error rates and coherence score for 30 minutes post-deploy"
|
|
3851
|
+
],
|
|
3852
|
+
approvalRequired,
|
|
3853
|
+
metrics: {
|
|
3854
|
+
commits: ctx.commitCount,
|
|
3855
|
+
filesChanged: ctx.filesChanged.length,
|
|
3856
|
+
capabilitiesAffected: ctx.affectedCapabilities.length,
|
|
3857
|
+
coherenceDelta: ctx.coherenceDelta
|
|
3858
|
+
}
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
var RISK_LEVELS = ["low", "medium", "high", "critical"];
|
|
3862
|
+
var ROLLBACK_LEVELS = ["simple", "moderate", "complex"];
|
|
3863
|
+
function parseLlmResponse9(raw) {
|
|
3864
|
+
let text = raw.trim();
|
|
3865
|
+
if (text.startsWith("```")) {
|
|
3866
|
+
text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
3867
|
+
}
|
|
3868
|
+
let parsed;
|
|
3869
|
+
try {
|
|
3870
|
+
parsed = JSON.parse(text);
|
|
3871
|
+
} catch {
|
|
3872
|
+
return null;
|
|
3873
|
+
}
|
|
3874
|
+
const riskLevel = RISK_LEVELS.includes(parsed.riskLevel) ? parsed.riskLevel : "medium";
|
|
3875
|
+
const rollbackComplexity = ROLLBACK_LEVELS.includes(
|
|
3876
|
+
parsed.rollbackComplexity
|
|
3877
|
+
) ? parsed.rollbackComplexity : "moderate";
|
|
3878
|
+
const recommendedActions = Array.isArray(parsed.recommendedActions) ? parsed.recommendedActions.filter((a) => typeof a === "string") : [];
|
|
3879
|
+
const affectedBusinessAreas = Array.isArray(parsed.affectedBusinessAreas) ? parsed.affectedBusinessAreas.filter((a) => typeof a === "string") : [];
|
|
3880
|
+
const metricsRaw = parsed.metrics && typeof parsed.metrics === "object" ? parsed.metrics : {};
|
|
3881
|
+
return {
|
|
3882
|
+
title: typeof parsed.title === "string" ? parsed.title : "Change Impact Brief",
|
|
3883
|
+
releaseVersion: typeof parsed.releaseVersion === "string" ? parsed.releaseVersion : "",
|
|
3884
|
+
date: typeof parsed.date === "string" ? parsed.date : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3885
|
+
audience: typeof parsed.audience === "string" ? parsed.audience : "",
|
|
3886
|
+
executiveSummary: typeof parsed.executiveSummary === "string" ? parsed.executiveSummary : "",
|
|
3887
|
+
technicalSummary: typeof parsed.technicalSummary === "string" ? parsed.technicalSummary : "",
|
|
3888
|
+
affectedBusinessAreas,
|
|
3889
|
+
riskLevel,
|
|
3890
|
+
riskJustification: typeof parsed.riskJustification === "string" ? parsed.riskJustification : "",
|
|
3891
|
+
complianceImpact: typeof parsed.complianceImpact === "string" ? parsed.complianceImpact : "None",
|
|
3892
|
+
rollbackComplexity,
|
|
3893
|
+
rollbackGuidance: typeof parsed.rollbackGuidance === "string" ? parsed.rollbackGuidance : "",
|
|
3894
|
+
recommendedActions,
|
|
3895
|
+
approvalRequired: parsed.approvalRequired === true,
|
|
3896
|
+
metrics: {
|
|
3897
|
+
commits: typeof metricsRaw.commits === "number" ? metricsRaw.commits : 0,
|
|
3898
|
+
filesChanged: typeof metricsRaw.filesChanged === "number" ? metricsRaw.filesChanged : 0,
|
|
3899
|
+
capabilitiesAffected: typeof metricsRaw.capabilitiesAffected === "number" ? metricsRaw.capabilitiesAffected : 0,
|
|
3900
|
+
coherenceDelta: typeof metricsRaw.coherenceDelta === "number" ? metricsRaw.coherenceDelta : null
|
|
3901
|
+
}
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
async function generateChangeImpactBrief(opts) {
|
|
3905
|
+
const context = buildPromptContext2(opts);
|
|
3906
|
+
try {
|
|
3907
|
+
const response = await opts.llm.complete({
|
|
3908
|
+
systemPrompt: buildSystemPrompt15(opts.audience),
|
|
3909
|
+
messages: [{ role: "user", content: buildUserPrompt15(opts, context) }],
|
|
3910
|
+
maxTokens: 2048
|
|
3911
|
+
});
|
|
3912
|
+
const parsed = parseLlmResponse9(response.content);
|
|
3913
|
+
if (parsed) return parsed;
|
|
3914
|
+
} catch {
|
|
3915
|
+
}
|
|
3916
|
+
return buildFallback9(opts);
|
|
3917
|
+
}
|
|
3918
|
+
|
|
3919
|
+
// src/generators/generateRoiSlide.ts
|
|
3920
|
+
var CURRENCY_SYMBOL = {
|
|
3921
|
+
EUR: "\u20AC",
|
|
3922
|
+
USD: "$",
|
|
3923
|
+
GBP: "\xA3"
|
|
3924
|
+
};
|
|
3925
|
+
function fmtK(n, sym) {
|
|
3926
|
+
if (n >= 1e6) return `${sym}${(n / 1e6).toFixed(1)}M`;
|
|
3927
|
+
if (n >= 1e3) return `${sym}${Math.round(n / 1e3)}k`;
|
|
3928
|
+
return `${sym}${Math.round(n)}`;
|
|
3929
|
+
}
|
|
3930
|
+
function buildFallback10(opts) {
|
|
3931
|
+
const { roiEstimate: r, organizationName, currency } = opts;
|
|
3932
|
+
const sym = CURRENCY_SYMBOL[currency] ?? "\u20AC";
|
|
3933
|
+
const org = organizationName ?? "Your Organization";
|
|
3934
|
+
const costYr = fmtK(r.maintenanceCostPerYear, sym);
|
|
3935
|
+
const saveYr = fmtK(r.savedCostPerYear, sym);
|
|
3936
|
+
const saveMo = fmtK(r.savedCostPerMonth, sym);
|
|
3937
|
+
const slides = [
|
|
3938
|
+
{
|
|
3939
|
+
type: "title",
|
|
3940
|
+
title: "Technical Debt Cost Analysis",
|
|
3941
|
+
content: `${org} \xB7 Architecture Health Report \xB7 ${(/* @__PURE__ */ new Date()).toLocaleDateString("en-GB", { month: "long", year: "numeric" })}`,
|
|
3942
|
+
highlight: r.currentGrade,
|
|
3943
|
+
highlightLabel: "Current Architecture Grade"
|
|
3944
|
+
},
|
|
3945
|
+
{
|
|
3946
|
+
type: "problem",
|
|
3947
|
+
title: "The Hidden Cost of Architecture Debt",
|
|
3948
|
+
content: `Your codebase currently has grade ${r.currentGrade} (${r.currentScore}/100). This translates directly to developer time lost to maintenance overhead every month.`,
|
|
3949
|
+
highlight: fmtK(r.maintenanceCostPerMonth, sym),
|
|
3950
|
+
highlightLabel: "Estimated monthly maintenance cost",
|
|
3951
|
+
bullets: [
|
|
3952
|
+
`Import cycles: ${r.breakdown.importCycles.count} cycles consuming ${r.breakdown.importCycles.hoursPerMonth}h/mo`,
|
|
3953
|
+
`Documentation drift: ${r.breakdown.documentationDrift.count} drifted capabilities \u2014 ${r.breakdown.documentationDrift.hoursPerMonth}h/mo in context-searching`,
|
|
3954
|
+
`High-churn files: ${r.breakdown.highChurnFiles.count} hot files adding ${r.breakdown.highChurnFiles.hoursPerMonth}h/mo in review overhead`,
|
|
3955
|
+
`Orphaned capabilities: ${r.breakdown.orphanedCode.count} untracked modules \u2014 ${r.breakdown.orphanedCode.hoursPerMonth}h/mo wasted`
|
|
3956
|
+
]
|
|
3957
|
+
},
|
|
3958
|
+
{
|
|
3959
|
+
type: "cost-breakdown",
|
|
3960
|
+
title: "Where Developer Time Goes",
|
|
3961
|
+
content: `Total: ${r.estimatedMaintenanceHoursPerMonth}h/month in maintenance overhead = ${costYr}/year at current state`,
|
|
3962
|
+
bullets: [
|
|
3963
|
+
`Import cycles \u2192 ${fmtK(r.breakdown.importCycles.cost, sym)}/mo (${r.breakdown.importCycles.hoursPerMonth}h debugging)`,
|
|
3964
|
+
`Doc drift \u2192 ${fmtK(r.breakdown.documentationDrift.cost, sym)}/mo (${r.breakdown.documentationDrift.hoursPerMonth}h searching context)`,
|
|
3965
|
+
`Churn overhead \u2192 ${fmtK(r.breakdown.highChurnFiles.cost, sym)}/mo (${r.breakdown.highChurnFiles.hoursPerMonth}h in review)`,
|
|
3966
|
+
`Orphaned code \u2192 ${fmtK(r.breakdown.orphanedCode.cost, sym)}/mo (${r.breakdown.orphanedCode.hoursPerMonth}h ownership gaps)`
|
|
3967
|
+
]
|
|
3968
|
+
},
|
|
3969
|
+
{
|
|
3970
|
+
type: "scenarios",
|
|
3971
|
+
title: "What Reaching Grade B Saves",
|
|
3972
|
+
content: `Moving from ${r.currentGrade} to ${r.targetGrade} cuts maintenance overhead by ~${Math.round(r.savedCostPerMonth / Math.max(r.maintenanceCostPerMonth, 1) * 100)}%.`,
|
|
3973
|
+
highlight: saveYr,
|
|
3974
|
+
highlightLabel: `Annual savings at grade ${r.targetGrade}`,
|
|
3975
|
+
bullets: [
|
|
3976
|
+
`Monthly savings: ${saveMo}/mo`,
|
|
3977
|
+
`ROI multiple: ${r.roiMultiple}\xD7 return on remediation investment`,
|
|
3978
|
+
`Break-even: ~${r.breakEvenMonths < 1 ? `${Math.round(r.breakEvenMonths * 30)} days` : `${r.breakEvenMonths} months`}`,
|
|
3979
|
+
`Remediation effort: ~${r.estimatedRemediationDays} engineering days`
|
|
3980
|
+
]
|
|
3981
|
+
},
|
|
3982
|
+
{
|
|
3983
|
+
type: "recommendation",
|
|
3984
|
+
title: "Recommended Remediation Path",
|
|
3985
|
+
content: r.recommendation,
|
|
3986
|
+
bullets: [
|
|
3987
|
+
`Step 1: Resolve ${r.breakdown.importCycles.count} import cycles (est. ${Math.round(r.estimatedRemediationDays * 0.4)} days)`,
|
|
3988
|
+
`Step 2: Fix ${r.breakdown.documentationDrift.count} drifted capability docs (est. ${Math.round(r.estimatedRemediationDays * 0.3)} days)`,
|
|
3989
|
+
`Step 3: Assign ownership for ${r.breakdown.orphanedCode.count} orphaned capabilities (est. ${Math.round(r.estimatedRemediationDays * 0.2)} days)`,
|
|
3990
|
+
`Step 4: Add coverage to top churn files (est. ${Math.round(r.estimatedRemediationDays * 0.1)} days)`
|
|
3991
|
+
]
|
|
3992
|
+
},
|
|
3993
|
+
{
|
|
3994
|
+
type: "cta",
|
|
3995
|
+
title: `Approve ${(/* @__PURE__ */ new Date()).toLocaleString("default", { month: "short" })} Refactoring Budget`,
|
|
3996
|
+
content: `Investment: ~${fmtK(r.estimatedRemediationDays * 8 * 150, sym)} (${r.estimatedRemediationDays} days of engineering effort)
|
|
3997
|
+
Return: ${saveYr}/year in recovered developer capacity`,
|
|
3998
|
+
highlight: `${r.roiMultiple}\xD7`,
|
|
3999
|
+
highlightLabel: "ROI multiple",
|
|
4000
|
+
bullets: [
|
|
4001
|
+
`${saveYr}/year recurring savings`,
|
|
4002
|
+
`Break-even in ${r.breakEvenMonths < 1 ? `${Math.round(r.breakEvenMonths * 30)} days` : `${r.breakEvenMonths} months`}`,
|
|
4003
|
+
`Measurable via PRISM architecture grade (${r.currentGrade} \u2192 ${r.targetGrade})`
|
|
4004
|
+
]
|
|
4005
|
+
}
|
|
4006
|
+
];
|
|
4007
|
+
const executiveSummary = [
|
|
4008
|
+
`\u2022 Current architecture grade ${r.currentGrade} (${r.currentScore}/100) costs ~${costYr}/year in maintenance overhead.`,
|
|
4009
|
+
`\u2022 Improving to grade ${r.targetGrade} saves ~${saveYr}/year \u2014 ${r.roiMultiple}\xD7 return on a ${r.estimatedRemediationDays}-day remediation effort.`,
|
|
4010
|
+
`\u2022 Break-even: ~${r.breakEvenMonths < 1 ? `${Math.round(r.breakEvenMonths * 30)} days` : `${r.breakEvenMonths} months`}. Primary sources: ${r.breakdown.importCycles.count} import cycles, ${r.breakdown.documentationDrift.count} drifted docs, ${r.breakdown.orphanedCode.count} orphaned capabilities.`
|
|
4011
|
+
].join("\n");
|
|
4012
|
+
const oneLinePitch = `Moving from ${r.currentGrade} to ${r.targetGrade} saves ${saveYr} annually \u2014 ${r.roiMultiple}\xD7 ROI on a ${r.estimatedRemediationDays}-day investment.`;
|
|
4013
|
+
return {
|
|
4014
|
+
title: `Technical Debt ROI \u2014 ${org}`,
|
|
4015
|
+
slides,
|
|
4016
|
+
executiveSummary,
|
|
4017
|
+
oneLinePitch
|
|
4018
|
+
};
|
|
4019
|
+
}
|
|
4020
|
+
function buildSystemPrompt16() {
|
|
4021
|
+
return "You are a VP of Engineering creating a concise, business-value-focused presentation for C-suite audiences. Generate ONLY valid JSON \u2014 no markdown fences, no prose outside the JSON object.";
|
|
4022
|
+
}
|
|
4023
|
+
function buildUserPrompt16(opts) {
|
|
4024
|
+
const { roiEstimate: r, organizationName, currency } = opts;
|
|
4025
|
+
const sym = CURRENCY_SYMBOL[currency] ?? "\u20AC";
|
|
4026
|
+
const org = organizationName ?? "the organization";
|
|
4027
|
+
return [
|
|
4028
|
+
`Generate a 6-slide executive ROI presentation for ${org}.`,
|
|
4029
|
+
``,
|
|
4030
|
+
`## ROI Data`,
|
|
4031
|
+
`Current grade: ${r.currentGrade} (score ${r.currentScore}/100)`,
|
|
4032
|
+
`Target grade: ${r.targetGrade} (score ${r.targetScore}/100)`,
|
|
4033
|
+
`Monthly maintenance cost: ${sym}${r.maintenanceCostPerMonth.toLocaleString()}`,
|
|
4034
|
+
`Annual maintenance cost: ${sym}${r.maintenanceCostPerYear.toLocaleString()}`,
|
|
4035
|
+
`Monthly savings if improved: ${sym}${r.savedCostPerMonth.toLocaleString()}`,
|
|
4036
|
+
`Annual savings if improved: ${sym}${r.savedCostPerYear.toLocaleString()}`,
|
|
4037
|
+
`ROI multiple: ${r.roiMultiple}x`,
|
|
4038
|
+
`Break-even: ${r.breakEvenMonths} months`,
|
|
4039
|
+
`Remediation days: ${r.estimatedRemediationDays}`,
|
|
4040
|
+
``,
|
|
4041
|
+
`## Pain sources`,
|
|
4042
|
+
`Import cycles: ${r.breakdown.importCycles.count} cycles, ${r.breakdown.importCycles.hoursPerMonth}h/mo, ${sym}${r.breakdown.importCycles.cost.toLocaleString()}/mo`,
|
|
4043
|
+
`Doc drift: ${r.breakdown.documentationDrift.count} drifted, ${r.breakdown.documentationDrift.hoursPerMonth}h/mo, ${sym}${r.breakdown.documentationDrift.cost.toLocaleString()}/mo`,
|
|
4044
|
+
`High churn: ${r.breakdown.highChurnFiles.count} files, ${r.breakdown.highChurnFiles.hoursPerMonth}h/mo, ${sym}${r.breakdown.highChurnFiles.cost.toLocaleString()}/mo`,
|
|
4045
|
+
`Orphaned: ${r.breakdown.orphanedCode.count} capabilities, ${r.breakdown.orphanedCode.hoursPerMonth}h/mo, ${sym}${r.breakdown.orphanedCode.cost.toLocaleString()}/mo`,
|
|
4046
|
+
``,
|
|
4047
|
+
`## Output Format`,
|
|
4048
|
+
`Return a single JSON object with this exact shape:`,
|
|
4049
|
+
`{`,
|
|
4050
|
+
` "title": "<deck title>",`,
|
|
4051
|
+
` "slides": [`,
|
|
4052
|
+
` {`,
|
|
4053
|
+
` "type": "<title|problem|cost-breakdown|scenarios|recommendation|cta>",`,
|
|
4054
|
+
` "title": "<slide title>",`,
|
|
4055
|
+
` "content": "<1-2 sentences of slide body copy>",`,
|
|
4056
|
+
` "highlight": "<optional large callout \u2014 a number or grade>",`,
|
|
4057
|
+
` "highlightLabel": "<label for the highlight>",`,
|
|
4058
|
+
` "bullets": ["<bullet 1>", "<bullet 2>", "<bullet 3>"]`,
|
|
4059
|
+
` }`,
|
|
4060
|
+
` ],`,
|
|
4061
|
+
` "executiveSummary": "<3-bullet executive summary as a single string, bullets separated by \\n>",`,
|
|
4062
|
+
` "oneLinePitch": "<one sentence pitch for email subject line>"`,
|
|
4063
|
+
`}`,
|
|
4064
|
+
``,
|
|
4065
|
+
`Rules:`,
|
|
4066
|
+
`- Exactly 6 slides in order: title, problem, cost-breakdown, scenarios, recommendation, cta`,
|
|
4067
|
+
`- bullets: max 4 per slide, each \u2264 90 characters`,
|
|
4068
|
+
`- content: 1\u20132 sentences, specific numbers from the data above`,
|
|
4069
|
+
`- Use business language \u2014 avoid engineering jargon`,
|
|
4070
|
+
`- Return ONLY valid JSON. No markdown. No prose outside the JSON.`
|
|
4071
|
+
].join("\n");
|
|
4072
|
+
}
|
|
4073
|
+
function parseResponse(raw) {
|
|
4074
|
+
let text = raw.trim();
|
|
4075
|
+
if (text.startsWith("```")) {
|
|
4076
|
+
text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
4077
|
+
}
|
|
4078
|
+
try {
|
|
4079
|
+
const parsed = JSON.parse(text);
|
|
4080
|
+
const rawSlides = Array.isArray(parsed.slides) ? parsed.slides : [];
|
|
4081
|
+
if (rawSlides.length === 0) return null;
|
|
4082
|
+
const VALID_TYPES = ["title", "problem", "cost-breakdown", "scenarios", "recommendation", "cta"];
|
|
4083
|
+
const slides = rawSlides.map((s, i) => {
|
|
4084
|
+
const slide = s ?? {};
|
|
4085
|
+
const type = typeof slide.type === "string" && VALID_TYPES.includes(slide.type) ? slide.type : VALID_TYPES[i] ?? "recommendation";
|
|
4086
|
+
const bullets = Array.isArray(slide.bullets) ? slide.bullets.filter((b) => typeof b === "string").slice(0, 4) : void 0;
|
|
4087
|
+
return {
|
|
4088
|
+
type,
|
|
4089
|
+
title: typeof slide.title === "string" ? slide.title : `Slide ${i + 1}`,
|
|
4090
|
+
content: typeof slide.content === "string" ? slide.content : "",
|
|
4091
|
+
...typeof slide.highlight === "string" && slide.highlight ? { highlight: slide.highlight } : {},
|
|
4092
|
+
...typeof slide.highlightLabel === "string" && slide.highlightLabel ? { highlightLabel: slide.highlightLabel } : {},
|
|
4093
|
+
...bullets && bullets.length > 0 ? { bullets } : {}
|
|
4094
|
+
};
|
|
4095
|
+
});
|
|
4096
|
+
return {
|
|
4097
|
+
title: typeof parsed.title === "string" ? parsed.title : "Technical Debt ROI",
|
|
4098
|
+
slides,
|
|
4099
|
+
executiveSummary: typeof parsed.executiveSummary === "string" ? parsed.executiveSummary : "",
|
|
4100
|
+
oneLinePitch: typeof parsed.oneLinePitch === "string" ? parsed.oneLinePitch : ""
|
|
4101
|
+
};
|
|
4102
|
+
} catch {
|
|
4103
|
+
return null;
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
async function generateRoiSlide(opts) {
|
|
4107
|
+
try {
|
|
4108
|
+
const response = await opts.llm.complete({
|
|
4109
|
+
systemPrompt: buildSystemPrompt16(),
|
|
4110
|
+
messages: [{ role: "user", content: buildUserPrompt16(opts) }],
|
|
4111
|
+
maxTokens: 3e3
|
|
4112
|
+
});
|
|
4113
|
+
const parsed = parseResponse(response.content);
|
|
4114
|
+
if (parsed) return parsed;
|
|
4115
|
+
} catch {
|
|
4116
|
+
}
|
|
4117
|
+
return buildFallback10(opts);
|
|
4118
|
+
}
|
|
4119
|
+
|
|
3543
4120
|
// src/forge/types.ts
|
|
3544
4121
|
var asAudienceId = (id) => id;
|
|
3545
4122
|
|
|
@@ -6000,7 +6577,7 @@ function getDispatchChannel(id) {
|
|
|
6000
6577
|
}
|
|
6001
6578
|
|
|
6002
6579
|
// src/forge/dispatch.ts
|
|
6003
|
-
function
|
|
6580
|
+
function buildSystemPrompt17(channel, audience, brand, blueprintContext, toneOffset) {
|
|
6004
6581
|
const lines = [
|
|
6005
6582
|
`You are a skilled content writer producing a ${channel.name} post.`,
|
|
6006
6583
|
"",
|
|
@@ -6051,7 +6628,7 @@ function truncate(content, maxLength) {
|
|
|
6051
6628
|
async function generateForChannel(ask, channel, provider, opts) {
|
|
6052
6629
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6053
6630
|
try {
|
|
6054
|
-
const system =
|
|
6631
|
+
const system = buildSystemPrompt17(
|
|
6055
6632
|
channel,
|
|
6056
6633
|
opts.audience,
|
|
6057
6634
|
opts.brand,
|
|
@@ -6196,7 +6773,7 @@ function nextVersionNumber(versions) {
|
|
|
6196
6773
|
}
|
|
6197
6774
|
|
|
6198
6775
|
// src/forge/refineAsset.ts
|
|
6199
|
-
function
|
|
6776
|
+
function buildSystemPrompt18(input) {
|
|
6200
6777
|
const parts = [
|
|
6201
6778
|
`You are a content refinement assistant for a developer-focused content tool (forge0x2B).`,
|
|
6202
6779
|
`You are refining an existing ${input.assetType.replace(/-/g, " ")} asset.`,
|
|
@@ -6235,7 +6812,7 @@ function parseRefinedResponse(raw) {
|
|
|
6235
6812
|
return { newContent, llmReply };
|
|
6236
6813
|
}
|
|
6237
6814
|
async function refineAsset(input, provider) {
|
|
6238
|
-
const systemPrompt =
|
|
6815
|
+
const systemPrompt = buildSystemPrompt18(input);
|
|
6239
6816
|
if (scanForSecrets(systemPrompt)) {
|
|
6240
6817
|
throw new Error("refineAsset: secret pattern detected in asset content. Refusing to send to LLM.");
|
|
6241
6818
|
}
|
|
@@ -6469,9 +7046,11 @@ exports.extractDependencyHotspots = extractDependencyHotspots;
|
|
|
6469
7046
|
exports.extractTopChurnFiles = extractTopChurnFiles;
|
|
6470
7047
|
exports.extractZones = extractZones;
|
|
6471
7048
|
exports.generateADR = generateADR;
|
|
7049
|
+
exports.generateApiChangelog = generateApiChangelog;
|
|
6472
7050
|
exports.generateArc42 = generateArc42;
|
|
6473
7051
|
exports.generateArchitectureWalkthrough = generateArchitectureWalkthrough;
|
|
6474
7052
|
exports.generateAskDrivenAsset = generateAskDrivenAsset;
|
|
7053
|
+
exports.generateChangeImpactBrief = generateChangeImpactBrief;
|
|
6475
7054
|
exports.generateChangesSince = generateChangesSince;
|
|
6476
7055
|
exports.generateComplianceDoc = generateComplianceDoc;
|
|
6477
7056
|
exports.generateKnowledgeCapture = generateKnowledgeCapture;
|
|
@@ -6481,6 +7060,7 @@ exports.generatePresentation = generatePresentation;
|
|
|
6481
7060
|
exports.generateRadio = generateRadio;
|
|
6482
7061
|
exports.generateRefactoringReport = generateRefactoringReport;
|
|
6483
7062
|
exports.generateReleaseNotes = generateReleaseNotes;
|
|
7063
|
+
exports.generateRoiSlide = generateRoiSlide;
|
|
6484
7064
|
exports.generateSprintRetro = generateSprintRetro;
|
|
6485
7065
|
exports.getDispatchChannel = getDispatchChannel;
|
|
6486
7066
|
exports.getPrismTemplate = getPrismTemplate;
|