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/index.cjs
CHANGED
|
@@ -2844,6 +2844,583 @@ async function generateKnowledgeCapture(options) {
|
|
|
2844
2844
|
return buildFallback7(options);
|
|
2845
2845
|
}
|
|
2846
2846
|
|
|
2847
|
+
// src/generators/generateApiChangelog.ts
|
|
2848
|
+
function buildPromptContext(opts) {
|
|
2849
|
+
const { apiChangeContext: ctx, amberContext, gitContext } = opts;
|
|
2850
|
+
const lines = [
|
|
2851
|
+
`## Change Range`,
|
|
2852
|
+
`From: ${ctx.from} To: ${ctx.to}`,
|
|
2853
|
+
`Total API changes: ${ctx.totalChanged}`,
|
|
2854
|
+
``
|
|
2855
|
+
];
|
|
2856
|
+
if (ctx.breakingChanges.length > 0) {
|
|
2857
|
+
lines.push(`## Breaking Changes (${ctx.breakingChanges.length})`);
|
|
2858
|
+
for (const c of ctx.breakingChanges) {
|
|
2859
|
+
const capHint = c.capabilityName ? ` [${c.capabilityName}]` : "";
|
|
2860
|
+
lines.push(`- ${c.endpoint}${capHint} \u2014 ${c.description ?? "no description"} (file: ${c.file})`);
|
|
2861
|
+
}
|
|
2862
|
+
lines.push("");
|
|
2863
|
+
}
|
|
2864
|
+
if (ctx.newEndpoints.length > 0) {
|
|
2865
|
+
lines.push(`## New Endpoints (${ctx.newEndpoints.length})`);
|
|
2866
|
+
for (const c of ctx.newEndpoints) {
|
|
2867
|
+
const capHint = c.capabilityName ? ` [${c.capabilityName}]` : "";
|
|
2868
|
+
lines.push(`- ${c.endpoint}${capHint} \u2014 ${c.description ?? "new"} (file: ${c.file})`);
|
|
2869
|
+
}
|
|
2870
|
+
lines.push("");
|
|
2871
|
+
}
|
|
2872
|
+
if (ctx.removedEndpoints.length > 0) {
|
|
2873
|
+
lines.push(`## Removed Endpoints (${ctx.removedEndpoints.length})`);
|
|
2874
|
+
for (const c of ctx.removedEndpoints) {
|
|
2875
|
+
lines.push(`- ${c.endpoint} \u2014 removed from ${c.file}`);
|
|
2876
|
+
}
|
|
2877
|
+
lines.push("");
|
|
2878
|
+
}
|
|
2879
|
+
const modified = ctx.changes.filter((c) => c.changeType === "modified");
|
|
2880
|
+
if (modified.length > 0) {
|
|
2881
|
+
lines.push(`## Modified Endpoints (${modified.length})`);
|
|
2882
|
+
for (const c of modified) {
|
|
2883
|
+
const capHint = c.capabilityName ? ` [${c.capabilityName}]` : "";
|
|
2884
|
+
lines.push(`- ${c.endpoint}${capHint} \u2014 ${c.description ?? "modified"} (file: ${c.file})`);
|
|
2885
|
+
}
|
|
2886
|
+
lines.push("");
|
|
2887
|
+
}
|
|
2888
|
+
if (amberContext) {
|
|
2889
|
+
lines.push(`## AMBER Capability Context`, amberContext.summary, "");
|
|
2890
|
+
}
|
|
2891
|
+
if (gitContext && gitContext.commitMessages.length > 0) {
|
|
2892
|
+
lines.push(
|
|
2893
|
+
`## Recent Commits`,
|
|
2894
|
+
...gitContext.commitMessages.slice(0, 8).map((m) => `- ${m}`),
|
|
2895
|
+
""
|
|
2896
|
+
);
|
|
2897
|
+
}
|
|
2898
|
+
return lines.join("\n");
|
|
2899
|
+
}
|
|
2900
|
+
function buildSystemPrompt14(audience, format) {
|
|
2901
|
+
const audienceDesc = audience === "external" ? "external API consumers (third-party developers)" : audience === "partner" ? "integration partners with existing API contracts" : "internal engineering teams";
|
|
2902
|
+
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";
|
|
2903
|
+
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.`;
|
|
2904
|
+
}
|
|
2905
|
+
function buildUserPrompt14(opts, context) {
|
|
2906
|
+
const { projectName, version, targetAudience, format } = opts;
|
|
2907
|
+
const v = version || opts.apiChangeContext.to;
|
|
2908
|
+
return [
|
|
2909
|
+
`Generate an API ${format} for: ${projectName}`,
|
|
2910
|
+
`Version: ${v}`,
|
|
2911
|
+
`Target audience: ${targetAudience}`,
|
|
2912
|
+
`Format: ${format}`,
|
|
2913
|
+
``,
|
|
2914
|
+
context,
|
|
2915
|
+
``,
|
|
2916
|
+
`## Output Format`,
|
|
2917
|
+
`Return a single JSON object with this EXACT shape:`,
|
|
2918
|
+
`{`,
|
|
2919
|
+
` "version": "<version string>",`,
|
|
2920
|
+
` "date": "<ISO date YYYY-MM-DD>",`,
|
|
2921
|
+
` "targetAudience": "<audience>",`,
|
|
2922
|
+
` "breakingChanges": [`,
|
|
2923
|
+
` { "endpoint": "<METHOD /path>", "description": "<what changed>", "migration": "<how to migrate>" }`,
|
|
2924
|
+
` ],`,
|
|
2925
|
+
` "newFeatures": [`,
|
|
2926
|
+
` { "endpoint": "<METHOD /path>", "description": "<what it does>", "example": "<optional curl/code hint>" }`,
|
|
2927
|
+
` ],`,
|
|
2928
|
+
` "improvements": [`,
|
|
2929
|
+
` { "endpoint": "<METHOD /path>", "description": "<what improved>" }`,
|
|
2930
|
+
` ],`,
|
|
2931
|
+
` "deprecations": [`,
|
|
2932
|
+
` { "endpoint": "<METHOD /path>", "description": "<what is deprecated>", "sunset": "<optional date>" }`,
|
|
2933
|
+
` ],`,
|
|
2934
|
+
` "migrationGuide": "<full migration guidance as prose \u2014 2\u20135 paragraphs>",`,
|
|
2935
|
+
` "consumerImpactSummary": "<1 paragraph copy-ready summary for consumers>"`,
|
|
2936
|
+
`}`,
|
|
2937
|
+
``,
|
|
2938
|
+
`Rules:`,
|
|
2939
|
+
`- Every breaking change MUST have a non-empty migration string.`,
|
|
2940
|
+
`- For external/partner audiences, omit internal implementation details.`,
|
|
2941
|
+
`- migrationGuide should be empty string if no breaking changes.`,
|
|
2942
|
+
`- Return ONLY valid JSON. No markdown fences.`
|
|
2943
|
+
].join("\n");
|
|
2944
|
+
}
|
|
2945
|
+
function buildFallback8(opts) {
|
|
2946
|
+
const ctx = opts.apiChangeContext;
|
|
2947
|
+
const v = opts.version ?? ctx.to;
|
|
2948
|
+
return {
|
|
2949
|
+
version: v,
|
|
2950
|
+
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
2951
|
+
targetAudience: opts.targetAudience,
|
|
2952
|
+
breakingChanges: ctx.breakingChanges.map((c) => ({
|
|
2953
|
+
endpoint: c.endpoint,
|
|
2954
|
+
description: c.description ?? "Breaking change detected",
|
|
2955
|
+
migration: "Review the updated API contract and update your client accordingly."
|
|
2956
|
+
})),
|
|
2957
|
+
newFeatures: ctx.newEndpoints.map((c) => ({
|
|
2958
|
+
endpoint: c.endpoint,
|
|
2959
|
+
description: c.description ?? "New endpoint added"
|
|
2960
|
+
})),
|
|
2961
|
+
improvements: ctx.changes.filter((c) => c.changeType === "modified").map((c) => ({
|
|
2962
|
+
endpoint: c.endpoint,
|
|
2963
|
+
description: c.description ?? "Endpoint updated"
|
|
2964
|
+
})),
|
|
2965
|
+
deprecations: ctx.removedEndpoints.map((c) => ({
|
|
2966
|
+
endpoint: c.endpoint,
|
|
2967
|
+
description: "This endpoint has been removed."
|
|
2968
|
+
})),
|
|
2969
|
+
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.` : "",
|
|
2970
|
+
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.")
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2973
|
+
function parseLlmResponse8(raw) {
|
|
2974
|
+
let text = raw.trim();
|
|
2975
|
+
if (text.startsWith("```")) {
|
|
2976
|
+
text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
2977
|
+
}
|
|
2978
|
+
let parsed;
|
|
2979
|
+
try {
|
|
2980
|
+
parsed = JSON.parse(text);
|
|
2981
|
+
} catch {
|
|
2982
|
+
return null;
|
|
2983
|
+
}
|
|
2984
|
+
function parseChangeArray(key, required) {
|
|
2985
|
+
if (!Array.isArray(parsed[key])) return [];
|
|
2986
|
+
return parsed[key].filter((item) => {
|
|
2987
|
+
if (typeof item !== "object" || item === null) return false;
|
|
2988
|
+
return required.every((k) => k in item);
|
|
2989
|
+
});
|
|
2990
|
+
}
|
|
2991
|
+
return {
|
|
2992
|
+
version: typeof parsed.version === "string" ? parsed.version : "",
|
|
2993
|
+
date: typeof parsed.date === "string" ? parsed.date : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
2994
|
+
targetAudience: typeof parsed.targetAudience === "string" ? parsed.targetAudience : "",
|
|
2995
|
+
breakingChanges: parseChangeArray("breakingChanges", ["endpoint", "description", "migration"]),
|
|
2996
|
+
newFeatures: parseChangeArray("newFeatures", ["endpoint", "description"]),
|
|
2997
|
+
improvements: parseChangeArray("improvements", ["endpoint", "description"]),
|
|
2998
|
+
deprecations: parseChangeArray("deprecations", ["endpoint", "description"]),
|
|
2999
|
+
migrationGuide: typeof parsed.migrationGuide === "string" ? parsed.migrationGuide : "",
|
|
3000
|
+
consumerImpactSummary: typeof parsed.consumerImpactSummary === "string" ? parsed.consumerImpactSummary : ""
|
|
3001
|
+
};
|
|
3002
|
+
}
|
|
3003
|
+
async function generateApiChangelog(opts) {
|
|
3004
|
+
const context = buildPromptContext(opts);
|
|
3005
|
+
try {
|
|
3006
|
+
const response = await opts.llm.complete({
|
|
3007
|
+
systemPrompt: buildSystemPrompt14(opts.targetAudience, opts.format),
|
|
3008
|
+
messages: [{ role: "user", content: buildUserPrompt14(opts, context) }],
|
|
3009
|
+
maxTokens: 3072
|
|
3010
|
+
});
|
|
3011
|
+
const parsed = parseLlmResponse8(response.content);
|
|
3012
|
+
if (parsed) return parsed;
|
|
3013
|
+
} catch {
|
|
3014
|
+
}
|
|
3015
|
+
return buildFallback8(opts);
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
// src/generators/generateChangeImpactBrief.ts
|
|
3019
|
+
function buildPromptContext2(opts) {
|
|
3020
|
+
const { gitContext, changeImpactContext: ctx, amberContext, greenContext } = opts;
|
|
3021
|
+
const lines = [
|
|
3022
|
+
`## Change Range`,
|
|
3023
|
+
`From: ${ctx.from}`,
|
|
3024
|
+
`To: ${ctx.to}`,
|
|
3025
|
+
`Commits: ${ctx.commitCount}`,
|
|
3026
|
+
`Files changed: ${ctx.filesChanged.length}`,
|
|
3027
|
+
``,
|
|
3028
|
+
`## Changed Files (sample)`,
|
|
3029
|
+
...ctx.filesChanged.slice(0, 20).map((f) => `- ${f}`)
|
|
3030
|
+
];
|
|
3031
|
+
if (ctx.breakingChanges.length > 0) {
|
|
3032
|
+
lines.push(``, `## Breaking Changes`, ...ctx.breakingChanges.map((b) => `- ${b}`));
|
|
3033
|
+
}
|
|
3034
|
+
if (ctx.affectedCapabilities.length > 0) {
|
|
3035
|
+
lines.push(``, `## Affected Business Capabilities`);
|
|
3036
|
+
for (const cap of ctx.affectedCapabilities) {
|
|
3037
|
+
lines.push(
|
|
3038
|
+
`- [${cap.criticality.toUpperCase()}] ${cap.name} (${cap.changedFiles.length} files changed, drift: ${cap.driftCount})`
|
|
3039
|
+
);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
if (ctx.regulatoryCapabilities.length > 0) {
|
|
3043
|
+
lines.push(
|
|
3044
|
+
``,
|
|
3045
|
+
`## Critical Capabilities Touched (require approval)`,
|
|
3046
|
+
...ctx.regulatoryCapabilities.map((c) => `- ${c}`)
|
|
3047
|
+
);
|
|
3048
|
+
}
|
|
3049
|
+
if (ctx.coherenceScoreBefore !== null || ctx.coherenceScoreAfter !== null) {
|
|
3050
|
+
lines.push(
|
|
3051
|
+
``,
|
|
3052
|
+
`## Architecture Coherence`,
|
|
3053
|
+
`Score before: ${ctx.coherenceScoreBefore ?? "unknown"}`,
|
|
3054
|
+
`Score after: ${ctx.coherenceScoreAfter ?? "unknown"}`,
|
|
3055
|
+
`Delta: ${ctx.coherenceDelta !== null ? (ctx.coherenceDelta > 0 ? "+" : "") + ctx.coherenceDelta : "unknown"}`
|
|
3056
|
+
);
|
|
3057
|
+
}
|
|
3058
|
+
if (ctx.topRisks.length > 0) {
|
|
3059
|
+
lines.push(``, `## Top Risks`, ...ctx.topRisks.map((r) => `- ${r}`));
|
|
3060
|
+
}
|
|
3061
|
+
if (amberContext) {
|
|
3062
|
+
lines.push(``, `## AMBER Layer Context`, amberContext.summary);
|
|
3063
|
+
}
|
|
3064
|
+
if (greenContext) {
|
|
3065
|
+
lines.push(``, `## GREEN Layer Context`, greenContext.summary);
|
|
3066
|
+
}
|
|
3067
|
+
if (gitContext.commitMessages.length > 0) {
|
|
3068
|
+
lines.push(
|
|
3069
|
+
``,
|
|
3070
|
+
`## Recent Commit Messages (sample)`,
|
|
3071
|
+
...gitContext.commitMessages.slice(0, 10).map((m) => `- ${m}`)
|
|
3072
|
+
);
|
|
3073
|
+
}
|
|
3074
|
+
return lines.join("\n");
|
|
3075
|
+
}
|
|
3076
|
+
function buildSystemPrompt15(audience) {
|
|
3077
|
+
if (audience === "executive") {
|
|
3078
|
+
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.";
|
|
3079
|
+
}
|
|
3080
|
+
if (audience === "cab") {
|
|
3081
|
+
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.";
|
|
3082
|
+
}
|
|
3083
|
+
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.";
|
|
3084
|
+
}
|
|
3085
|
+
function buildUserPrompt15(opts, context) {
|
|
3086
|
+
const { projectName, releaseVersion, audience } = opts;
|
|
3087
|
+
const version = releaseVersion || opts.changeImpactContext.to;
|
|
3088
|
+
return [
|
|
3089
|
+
`Generate a change impact brief for: ${projectName}`,
|
|
3090
|
+
`Release version: ${version}`,
|
|
3091
|
+
`Audience: ${audience}`,
|
|
3092
|
+
``,
|
|
3093
|
+
context,
|
|
3094
|
+
``,
|
|
3095
|
+
`## Output Format`,
|
|
3096
|
+
`Return a single JSON object with this EXACT shape:`,
|
|
3097
|
+
`{`,
|
|
3098
|
+
` "title": "<brief title>",`,
|
|
3099
|
+
` "releaseVersion": "<version string>",`,
|
|
3100
|
+
` "date": "<ISO date>",`,
|
|
3101
|
+
` "audience": "<audience>",`,
|
|
3102
|
+
` "executiveSummary": "<3 bullet points separated by \\n, plain language, max 120 chars each>",`,
|
|
3103
|
+
` "technicalSummary": "<2-3 sentences for CAB technical reviewers>",`,
|
|
3104
|
+
` "affectedBusinessAreas": ["<area 1>", "<area 2>"],`,
|
|
3105
|
+
` "riskLevel": "<one of: low | medium | high | critical>",`,
|
|
3106
|
+
` "riskJustification": "<1-2 sentences explaining the risk rating>",`,
|
|
3107
|
+
` "complianceImpact": "<which regulated capabilities are touched, or 'None' if clean>",`,
|
|
3108
|
+
` "rollbackComplexity": "<one of: simple | moderate | complex>",`,
|
|
3109
|
+
` "rollbackGuidance": "<concise rollback instructions>",`,
|
|
3110
|
+
` "recommendedActions": ["<action 1>", "<action 2>", "<action 3>"],`,
|
|
3111
|
+
` "approvalRequired": <true | false>,`,
|
|
3112
|
+
` "metrics": {`,
|
|
3113
|
+
` "commits": <number>,`,
|
|
3114
|
+
` "filesChanged": <number>,`,
|
|
3115
|
+
` "capabilitiesAffected": <number>,`,
|
|
3116
|
+
` "coherenceDelta": <number | null>`,
|
|
3117
|
+
` }`,
|
|
3118
|
+
`}`,
|
|
3119
|
+
``,
|
|
3120
|
+
`Rules:`,
|
|
3121
|
+
`- riskLevel = "critical" if any critical capabilities touched OR breaking changes exist.`,
|
|
3122
|
+
`- riskLevel = "high" if 3+ capabilities affected or coherenceDelta < -5.`,
|
|
3123
|
+
`- approvalRequired = true if riskLevel is "critical" or "high".`,
|
|
3124
|
+
`- rollbackComplexity = "complex" if breaking changes or critical capabilities touched.`,
|
|
3125
|
+
`- executiveSummary must be EXACTLY 3 bullet lines joined by \\n \u2014 each starting with a dash.`,
|
|
3126
|
+
`- Return ONLY valid JSON. No markdown. No prose outside the JSON object.`
|
|
3127
|
+
].join("\n");
|
|
3128
|
+
}
|
|
3129
|
+
function buildFallback9(opts) {
|
|
3130
|
+
const ctx = opts.changeImpactContext;
|
|
3131
|
+
const hasCritical = ctx.regulatoryCapabilities.length > 0 || ctx.breakingChanges.length > 0;
|
|
3132
|
+
const hasHigh = ctx.affectedCapabilities.filter((c) => c.criticality === "high").length >= 2;
|
|
3133
|
+
const riskLevel = hasCritical ? "critical" : hasHigh || ctx.affectedCapabilities.length >= 3 ? "high" : ctx.affectedCapabilities.length >= 1 ? "medium" : "low";
|
|
3134
|
+
const approvalRequired = riskLevel === "critical" || riskLevel === "high";
|
|
3135
|
+
const rollbackComplexity = hasCritical ? "complex" : ctx.affectedCapabilities.length >= 3 ? "moderate" : "simple";
|
|
3136
|
+
return {
|
|
3137
|
+
title: `Change Impact Brief \u2014 ${opts.projectName}`,
|
|
3138
|
+
releaseVersion: opts.releaseVersion ?? ctx.to,
|
|
3139
|
+
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3140
|
+
audience: opts.audience,
|
|
3141
|
+
executiveSummary: `- ${ctx.commitCount} commit(s) deployed across ${ctx.filesChanged.length} files
|
|
3142
|
+
- ${ctx.affectedCapabilities.length} business capability(ies) affected
|
|
3143
|
+
- Risk level: ${riskLevel.toUpperCase()}${hasCritical ? " \u2014 critical capabilities touched" : ""}`,
|
|
3144
|
+
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}.` : ""),
|
|
3145
|
+
affectedBusinessAreas: ctx.affectedCapabilities.map((c) => c.name),
|
|
3146
|
+
riskLevel,
|
|
3147
|
+
riskJustification: hasCritical ? "Critical business capabilities were modified, requiring formal CAB sign-off." : `${ctx.affectedCapabilities.length} capabilities affected with potential for regression.`,
|
|
3148
|
+
complianceImpact: ctx.regulatoryCapabilities.length > 0 ? ctx.regulatoryCapabilities.join(", ") : "None",
|
|
3149
|
+
rollbackComplexity,
|
|
3150
|
+
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.",
|
|
3151
|
+
recommendedActions: [
|
|
3152
|
+
approvalRequired ? "Obtain formal CAB sign-off before deploying to production" : "Deploy during low-traffic window",
|
|
3153
|
+
ctx.breakingChanges.length > 0 ? "Notify API consumers of breaking changes at least 48h in advance" : "Run full regression suite",
|
|
3154
|
+
"Monitor error rates and coherence score for 30 minutes post-deploy"
|
|
3155
|
+
],
|
|
3156
|
+
approvalRequired,
|
|
3157
|
+
metrics: {
|
|
3158
|
+
commits: ctx.commitCount,
|
|
3159
|
+
filesChanged: ctx.filesChanged.length,
|
|
3160
|
+
capabilitiesAffected: ctx.affectedCapabilities.length,
|
|
3161
|
+
coherenceDelta: ctx.coherenceDelta
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
3164
|
+
}
|
|
3165
|
+
var RISK_LEVELS = ["low", "medium", "high", "critical"];
|
|
3166
|
+
var ROLLBACK_LEVELS = ["simple", "moderate", "complex"];
|
|
3167
|
+
function parseLlmResponse9(raw) {
|
|
3168
|
+
let text = raw.trim();
|
|
3169
|
+
if (text.startsWith("```")) {
|
|
3170
|
+
text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
3171
|
+
}
|
|
3172
|
+
let parsed;
|
|
3173
|
+
try {
|
|
3174
|
+
parsed = JSON.parse(text);
|
|
3175
|
+
} catch {
|
|
3176
|
+
return null;
|
|
3177
|
+
}
|
|
3178
|
+
const riskLevel = RISK_LEVELS.includes(parsed.riskLevel) ? parsed.riskLevel : "medium";
|
|
3179
|
+
const rollbackComplexity = ROLLBACK_LEVELS.includes(
|
|
3180
|
+
parsed.rollbackComplexity
|
|
3181
|
+
) ? parsed.rollbackComplexity : "moderate";
|
|
3182
|
+
const recommendedActions = Array.isArray(parsed.recommendedActions) ? parsed.recommendedActions.filter((a) => typeof a === "string") : [];
|
|
3183
|
+
const affectedBusinessAreas = Array.isArray(parsed.affectedBusinessAreas) ? parsed.affectedBusinessAreas.filter((a) => typeof a === "string") : [];
|
|
3184
|
+
const metricsRaw = parsed.metrics && typeof parsed.metrics === "object" ? parsed.metrics : {};
|
|
3185
|
+
return {
|
|
3186
|
+
title: typeof parsed.title === "string" ? parsed.title : "Change Impact Brief",
|
|
3187
|
+
releaseVersion: typeof parsed.releaseVersion === "string" ? parsed.releaseVersion : "",
|
|
3188
|
+
date: typeof parsed.date === "string" ? parsed.date : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3189
|
+
audience: typeof parsed.audience === "string" ? parsed.audience : "",
|
|
3190
|
+
executiveSummary: typeof parsed.executiveSummary === "string" ? parsed.executiveSummary : "",
|
|
3191
|
+
technicalSummary: typeof parsed.technicalSummary === "string" ? parsed.technicalSummary : "",
|
|
3192
|
+
affectedBusinessAreas,
|
|
3193
|
+
riskLevel,
|
|
3194
|
+
riskJustification: typeof parsed.riskJustification === "string" ? parsed.riskJustification : "",
|
|
3195
|
+
complianceImpact: typeof parsed.complianceImpact === "string" ? parsed.complianceImpact : "None",
|
|
3196
|
+
rollbackComplexity,
|
|
3197
|
+
rollbackGuidance: typeof parsed.rollbackGuidance === "string" ? parsed.rollbackGuidance : "",
|
|
3198
|
+
recommendedActions,
|
|
3199
|
+
approvalRequired: parsed.approvalRequired === true,
|
|
3200
|
+
metrics: {
|
|
3201
|
+
commits: typeof metricsRaw.commits === "number" ? metricsRaw.commits : 0,
|
|
3202
|
+
filesChanged: typeof metricsRaw.filesChanged === "number" ? metricsRaw.filesChanged : 0,
|
|
3203
|
+
capabilitiesAffected: typeof metricsRaw.capabilitiesAffected === "number" ? metricsRaw.capabilitiesAffected : 0,
|
|
3204
|
+
coherenceDelta: typeof metricsRaw.coherenceDelta === "number" ? metricsRaw.coherenceDelta : null
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
async function generateChangeImpactBrief(opts) {
|
|
3209
|
+
const context = buildPromptContext2(opts);
|
|
3210
|
+
try {
|
|
3211
|
+
const response = await opts.llm.complete({
|
|
3212
|
+
systemPrompt: buildSystemPrompt15(opts.audience),
|
|
3213
|
+
messages: [{ role: "user", content: buildUserPrompt15(opts, context) }],
|
|
3214
|
+
maxTokens: 2048
|
|
3215
|
+
});
|
|
3216
|
+
const parsed = parseLlmResponse9(response.content);
|
|
3217
|
+
if (parsed) return parsed;
|
|
3218
|
+
} catch {
|
|
3219
|
+
}
|
|
3220
|
+
return buildFallback9(opts);
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
// src/generators/generateRoiSlide.ts
|
|
3224
|
+
var CURRENCY_SYMBOL = {
|
|
3225
|
+
EUR: "\u20AC",
|
|
3226
|
+
USD: "$",
|
|
3227
|
+
GBP: "\xA3"
|
|
3228
|
+
};
|
|
3229
|
+
function fmtK(n, sym) {
|
|
3230
|
+
if (n >= 1e6) return `${sym}${(n / 1e6).toFixed(1)}M`;
|
|
3231
|
+
if (n >= 1e3) return `${sym}${Math.round(n / 1e3)}k`;
|
|
3232
|
+
return `${sym}${Math.round(n)}`;
|
|
3233
|
+
}
|
|
3234
|
+
function buildFallback10(opts) {
|
|
3235
|
+
const { roiEstimate: r, organizationName, currency } = opts;
|
|
3236
|
+
const sym = CURRENCY_SYMBOL[currency] ?? "\u20AC";
|
|
3237
|
+
const org = organizationName ?? "Your Organization";
|
|
3238
|
+
const costYr = fmtK(r.maintenanceCostPerYear, sym);
|
|
3239
|
+
const saveYr = fmtK(r.savedCostPerYear, sym);
|
|
3240
|
+
const saveMo = fmtK(r.savedCostPerMonth, sym);
|
|
3241
|
+
const slides = [
|
|
3242
|
+
{
|
|
3243
|
+
type: "title",
|
|
3244
|
+
title: "Technical Debt Cost Analysis",
|
|
3245
|
+
content: `${org} \xB7 Architecture Health Report \xB7 ${(/* @__PURE__ */ new Date()).toLocaleDateString("en-GB", { month: "long", year: "numeric" })}`,
|
|
3246
|
+
highlight: r.currentGrade,
|
|
3247
|
+
highlightLabel: "Current Architecture Grade"
|
|
3248
|
+
},
|
|
3249
|
+
{
|
|
3250
|
+
type: "problem",
|
|
3251
|
+
title: "The Hidden Cost of Architecture Debt",
|
|
3252
|
+
content: `Your codebase currently has grade ${r.currentGrade} (${r.currentScore}/100). This translates directly to developer time lost to maintenance overhead every month.`,
|
|
3253
|
+
highlight: fmtK(r.maintenanceCostPerMonth, sym),
|
|
3254
|
+
highlightLabel: "Estimated monthly maintenance cost",
|
|
3255
|
+
bullets: [
|
|
3256
|
+
`Import cycles: ${r.breakdown.importCycles.count} cycles consuming ${r.breakdown.importCycles.hoursPerMonth}h/mo`,
|
|
3257
|
+
`Documentation drift: ${r.breakdown.documentationDrift.count} drifted capabilities \u2014 ${r.breakdown.documentationDrift.hoursPerMonth}h/mo in context-searching`,
|
|
3258
|
+
`High-churn files: ${r.breakdown.highChurnFiles.count} hot files adding ${r.breakdown.highChurnFiles.hoursPerMonth}h/mo in review overhead`,
|
|
3259
|
+
`Orphaned capabilities: ${r.breakdown.orphanedCode.count} untracked modules \u2014 ${r.breakdown.orphanedCode.hoursPerMonth}h/mo wasted`
|
|
3260
|
+
]
|
|
3261
|
+
},
|
|
3262
|
+
{
|
|
3263
|
+
type: "cost-breakdown",
|
|
3264
|
+
title: "Where Developer Time Goes",
|
|
3265
|
+
content: `Total: ${r.estimatedMaintenanceHoursPerMonth}h/month in maintenance overhead = ${costYr}/year at current state`,
|
|
3266
|
+
bullets: [
|
|
3267
|
+
`Import cycles \u2192 ${fmtK(r.breakdown.importCycles.cost, sym)}/mo (${r.breakdown.importCycles.hoursPerMonth}h debugging)`,
|
|
3268
|
+
`Doc drift \u2192 ${fmtK(r.breakdown.documentationDrift.cost, sym)}/mo (${r.breakdown.documentationDrift.hoursPerMonth}h searching context)`,
|
|
3269
|
+
`Churn overhead \u2192 ${fmtK(r.breakdown.highChurnFiles.cost, sym)}/mo (${r.breakdown.highChurnFiles.hoursPerMonth}h in review)`,
|
|
3270
|
+
`Orphaned code \u2192 ${fmtK(r.breakdown.orphanedCode.cost, sym)}/mo (${r.breakdown.orphanedCode.hoursPerMonth}h ownership gaps)`
|
|
3271
|
+
]
|
|
3272
|
+
},
|
|
3273
|
+
{
|
|
3274
|
+
type: "scenarios",
|
|
3275
|
+
title: "What Reaching Grade B Saves",
|
|
3276
|
+
content: `Moving from ${r.currentGrade} to ${r.targetGrade} cuts maintenance overhead by ~${Math.round(r.savedCostPerMonth / Math.max(r.maintenanceCostPerMonth, 1) * 100)}%.`,
|
|
3277
|
+
highlight: saveYr,
|
|
3278
|
+
highlightLabel: `Annual savings at grade ${r.targetGrade}`,
|
|
3279
|
+
bullets: [
|
|
3280
|
+
`Monthly savings: ${saveMo}/mo`,
|
|
3281
|
+
`ROI multiple: ${r.roiMultiple}\xD7 return on remediation investment`,
|
|
3282
|
+
`Break-even: ~${r.breakEvenMonths < 1 ? `${Math.round(r.breakEvenMonths * 30)} days` : `${r.breakEvenMonths} months`}`,
|
|
3283
|
+
`Remediation effort: ~${r.estimatedRemediationDays} engineering days`
|
|
3284
|
+
]
|
|
3285
|
+
},
|
|
3286
|
+
{
|
|
3287
|
+
type: "recommendation",
|
|
3288
|
+
title: "Recommended Remediation Path",
|
|
3289
|
+
content: r.recommendation,
|
|
3290
|
+
bullets: [
|
|
3291
|
+
`Step 1: Resolve ${r.breakdown.importCycles.count} import cycles (est. ${Math.round(r.estimatedRemediationDays * 0.4)} days)`,
|
|
3292
|
+
`Step 2: Fix ${r.breakdown.documentationDrift.count} drifted capability docs (est. ${Math.round(r.estimatedRemediationDays * 0.3)} days)`,
|
|
3293
|
+
`Step 3: Assign ownership for ${r.breakdown.orphanedCode.count} orphaned capabilities (est. ${Math.round(r.estimatedRemediationDays * 0.2)} days)`,
|
|
3294
|
+
`Step 4: Add coverage to top churn files (est. ${Math.round(r.estimatedRemediationDays * 0.1)} days)`
|
|
3295
|
+
]
|
|
3296
|
+
},
|
|
3297
|
+
{
|
|
3298
|
+
type: "cta",
|
|
3299
|
+
title: `Approve ${(/* @__PURE__ */ new Date()).toLocaleString("default", { month: "short" })} Refactoring Budget`,
|
|
3300
|
+
content: `Investment: ~${fmtK(r.estimatedRemediationDays * 8 * 150, sym)} (${r.estimatedRemediationDays} days of engineering effort)
|
|
3301
|
+
Return: ${saveYr}/year in recovered developer capacity`,
|
|
3302
|
+
highlight: `${r.roiMultiple}\xD7`,
|
|
3303
|
+
highlightLabel: "ROI multiple",
|
|
3304
|
+
bullets: [
|
|
3305
|
+
`${saveYr}/year recurring savings`,
|
|
3306
|
+
`Break-even in ${r.breakEvenMonths < 1 ? `${Math.round(r.breakEvenMonths * 30)} days` : `${r.breakEvenMonths} months`}`,
|
|
3307
|
+
`Measurable via PRISM architecture grade (${r.currentGrade} \u2192 ${r.targetGrade})`
|
|
3308
|
+
]
|
|
3309
|
+
}
|
|
3310
|
+
];
|
|
3311
|
+
const executiveSummary = [
|
|
3312
|
+
`\u2022 Current architecture grade ${r.currentGrade} (${r.currentScore}/100) costs ~${costYr}/year in maintenance overhead.`,
|
|
3313
|
+
`\u2022 Improving to grade ${r.targetGrade} saves ~${saveYr}/year \u2014 ${r.roiMultiple}\xD7 return on a ${r.estimatedRemediationDays}-day remediation effort.`,
|
|
3314
|
+
`\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.`
|
|
3315
|
+
].join("\n");
|
|
3316
|
+
const oneLinePitch = `Moving from ${r.currentGrade} to ${r.targetGrade} saves ${saveYr} annually \u2014 ${r.roiMultiple}\xD7 ROI on a ${r.estimatedRemediationDays}-day investment.`;
|
|
3317
|
+
return {
|
|
3318
|
+
title: `Technical Debt ROI \u2014 ${org}`,
|
|
3319
|
+
slides,
|
|
3320
|
+
executiveSummary,
|
|
3321
|
+
oneLinePitch
|
|
3322
|
+
};
|
|
3323
|
+
}
|
|
3324
|
+
function buildSystemPrompt16() {
|
|
3325
|
+
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.";
|
|
3326
|
+
}
|
|
3327
|
+
function buildUserPrompt16(opts) {
|
|
3328
|
+
const { roiEstimate: r, organizationName, currency } = opts;
|
|
3329
|
+
const sym = CURRENCY_SYMBOL[currency] ?? "\u20AC";
|
|
3330
|
+
const org = organizationName ?? "the organization";
|
|
3331
|
+
return [
|
|
3332
|
+
`Generate a 6-slide executive ROI presentation for ${org}.`,
|
|
3333
|
+
``,
|
|
3334
|
+
`## ROI Data`,
|
|
3335
|
+
`Current grade: ${r.currentGrade} (score ${r.currentScore}/100)`,
|
|
3336
|
+
`Target grade: ${r.targetGrade} (score ${r.targetScore}/100)`,
|
|
3337
|
+
`Monthly maintenance cost: ${sym}${r.maintenanceCostPerMonth.toLocaleString()}`,
|
|
3338
|
+
`Annual maintenance cost: ${sym}${r.maintenanceCostPerYear.toLocaleString()}`,
|
|
3339
|
+
`Monthly savings if improved: ${sym}${r.savedCostPerMonth.toLocaleString()}`,
|
|
3340
|
+
`Annual savings if improved: ${sym}${r.savedCostPerYear.toLocaleString()}`,
|
|
3341
|
+
`ROI multiple: ${r.roiMultiple}x`,
|
|
3342
|
+
`Break-even: ${r.breakEvenMonths} months`,
|
|
3343
|
+
`Remediation days: ${r.estimatedRemediationDays}`,
|
|
3344
|
+
``,
|
|
3345
|
+
`## Pain sources`,
|
|
3346
|
+
`Import cycles: ${r.breakdown.importCycles.count} cycles, ${r.breakdown.importCycles.hoursPerMonth}h/mo, ${sym}${r.breakdown.importCycles.cost.toLocaleString()}/mo`,
|
|
3347
|
+
`Doc drift: ${r.breakdown.documentationDrift.count} drifted, ${r.breakdown.documentationDrift.hoursPerMonth}h/mo, ${sym}${r.breakdown.documentationDrift.cost.toLocaleString()}/mo`,
|
|
3348
|
+
`High churn: ${r.breakdown.highChurnFiles.count} files, ${r.breakdown.highChurnFiles.hoursPerMonth}h/mo, ${sym}${r.breakdown.highChurnFiles.cost.toLocaleString()}/mo`,
|
|
3349
|
+
`Orphaned: ${r.breakdown.orphanedCode.count} capabilities, ${r.breakdown.orphanedCode.hoursPerMonth}h/mo, ${sym}${r.breakdown.orphanedCode.cost.toLocaleString()}/mo`,
|
|
3350
|
+
``,
|
|
3351
|
+
`## Output Format`,
|
|
3352
|
+
`Return a single JSON object with this exact shape:`,
|
|
3353
|
+
`{`,
|
|
3354
|
+
` "title": "<deck title>",`,
|
|
3355
|
+
` "slides": [`,
|
|
3356
|
+
` {`,
|
|
3357
|
+
` "type": "<title|problem|cost-breakdown|scenarios|recommendation|cta>",`,
|
|
3358
|
+
` "title": "<slide title>",`,
|
|
3359
|
+
` "content": "<1-2 sentences of slide body copy>",`,
|
|
3360
|
+
` "highlight": "<optional large callout \u2014 a number or grade>",`,
|
|
3361
|
+
` "highlightLabel": "<label for the highlight>",`,
|
|
3362
|
+
` "bullets": ["<bullet 1>", "<bullet 2>", "<bullet 3>"]`,
|
|
3363
|
+
` }`,
|
|
3364
|
+
` ],`,
|
|
3365
|
+
` "executiveSummary": "<3-bullet executive summary as a single string, bullets separated by \\n>",`,
|
|
3366
|
+
` "oneLinePitch": "<one sentence pitch for email subject line>"`,
|
|
3367
|
+
`}`,
|
|
3368
|
+
``,
|
|
3369
|
+
`Rules:`,
|
|
3370
|
+
`- Exactly 6 slides in order: title, problem, cost-breakdown, scenarios, recommendation, cta`,
|
|
3371
|
+
`- bullets: max 4 per slide, each \u2264 90 characters`,
|
|
3372
|
+
`- content: 1\u20132 sentences, specific numbers from the data above`,
|
|
3373
|
+
`- Use business language \u2014 avoid engineering jargon`,
|
|
3374
|
+
`- Return ONLY valid JSON. No markdown. No prose outside the JSON.`
|
|
3375
|
+
].join("\n");
|
|
3376
|
+
}
|
|
3377
|
+
function parseResponse(raw) {
|
|
3378
|
+
let text = raw.trim();
|
|
3379
|
+
if (text.startsWith("```")) {
|
|
3380
|
+
text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
3381
|
+
}
|
|
3382
|
+
try {
|
|
3383
|
+
const parsed = JSON.parse(text);
|
|
3384
|
+
const rawSlides = Array.isArray(parsed.slides) ? parsed.slides : [];
|
|
3385
|
+
if (rawSlides.length === 0) return null;
|
|
3386
|
+
const VALID_TYPES = ["title", "problem", "cost-breakdown", "scenarios", "recommendation", "cta"];
|
|
3387
|
+
const slides = rawSlides.map((s, i) => {
|
|
3388
|
+
const slide = s ?? {};
|
|
3389
|
+
const type = typeof slide.type === "string" && VALID_TYPES.includes(slide.type) ? slide.type : VALID_TYPES[i] ?? "recommendation";
|
|
3390
|
+
const bullets = Array.isArray(slide.bullets) ? slide.bullets.filter((b) => typeof b === "string").slice(0, 4) : void 0;
|
|
3391
|
+
return {
|
|
3392
|
+
type,
|
|
3393
|
+
title: typeof slide.title === "string" ? slide.title : `Slide ${i + 1}`,
|
|
3394
|
+
content: typeof slide.content === "string" ? slide.content : "",
|
|
3395
|
+
...typeof slide.highlight === "string" && slide.highlight ? { highlight: slide.highlight } : {},
|
|
3396
|
+
...typeof slide.highlightLabel === "string" && slide.highlightLabel ? { highlightLabel: slide.highlightLabel } : {},
|
|
3397
|
+
...bullets && bullets.length > 0 ? { bullets } : {}
|
|
3398
|
+
};
|
|
3399
|
+
});
|
|
3400
|
+
return {
|
|
3401
|
+
title: typeof parsed.title === "string" ? parsed.title : "Technical Debt ROI",
|
|
3402
|
+
slides,
|
|
3403
|
+
executiveSummary: typeof parsed.executiveSummary === "string" ? parsed.executiveSummary : "",
|
|
3404
|
+
oneLinePitch: typeof parsed.oneLinePitch === "string" ? parsed.oneLinePitch : ""
|
|
3405
|
+
};
|
|
3406
|
+
} catch {
|
|
3407
|
+
return null;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
async function generateRoiSlide(opts) {
|
|
3411
|
+
try {
|
|
3412
|
+
const response = await opts.llm.complete({
|
|
3413
|
+
systemPrompt: buildSystemPrompt16(),
|
|
3414
|
+
messages: [{ role: "user", content: buildUserPrompt16(opts) }],
|
|
3415
|
+
maxTokens: 3e3
|
|
3416
|
+
});
|
|
3417
|
+
const parsed = parseResponse(response.content);
|
|
3418
|
+
if (parsed) return parsed;
|
|
3419
|
+
} catch {
|
|
3420
|
+
}
|
|
3421
|
+
return buildFallback10(opts);
|
|
3422
|
+
}
|
|
3423
|
+
|
|
2847
3424
|
// src/forge/types.ts
|
|
2848
3425
|
var asAudienceId = (id) => id;
|
|
2849
3426
|
|
|
@@ -5368,7 +5945,7 @@ function getDispatchChannel(id) {
|
|
|
5368
5945
|
}
|
|
5369
5946
|
|
|
5370
5947
|
// src/forge/dispatch.ts
|
|
5371
|
-
function
|
|
5948
|
+
function buildSystemPrompt17(channel, audience, brand, blueprintContext, toneOffset) {
|
|
5372
5949
|
const lines = [
|
|
5373
5950
|
`You are a skilled content writer producing a ${channel.name} post.`,
|
|
5374
5951
|
"",
|
|
@@ -5419,7 +5996,7 @@ function truncate(content, maxLength) {
|
|
|
5419
5996
|
async function generateForChannel(ask, channel, provider, opts) {
|
|
5420
5997
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5421
5998
|
try {
|
|
5422
|
-
const system =
|
|
5999
|
+
const system = buildSystemPrompt17(
|
|
5423
6000
|
channel,
|
|
5424
6001
|
opts.audience,
|
|
5425
6002
|
opts.brand,
|
|
@@ -5564,7 +6141,7 @@ function nextVersionNumber(versions) {
|
|
|
5564
6141
|
}
|
|
5565
6142
|
|
|
5566
6143
|
// src/forge/refineAsset.ts
|
|
5567
|
-
function
|
|
6144
|
+
function buildSystemPrompt18(input) {
|
|
5568
6145
|
const parts = [
|
|
5569
6146
|
`You are a content refinement assistant for a developer-focused content tool (forge0x2B).`,
|
|
5570
6147
|
`You are refining an existing ${input.assetType.replace(/-/g, " ")} asset.`,
|
|
@@ -5603,7 +6180,7 @@ function parseRefinedResponse(raw) {
|
|
|
5603
6180
|
return { newContent, llmReply };
|
|
5604
6181
|
}
|
|
5605
6182
|
async function refineAsset(input, provider) {
|
|
5606
|
-
const systemPrompt =
|
|
6183
|
+
const systemPrompt = buildSystemPrompt18(input);
|
|
5607
6184
|
if (scanForSecrets(systemPrompt)) {
|
|
5608
6185
|
throw new Error("refineAsset: secret pattern detected in asset content. Refusing to send to LLM.");
|
|
5609
6186
|
}
|
|
@@ -5831,9 +6408,11 @@ exports.exportToBufferCsv = exportToBufferCsv;
|
|
|
5831
6408
|
exports.exportToHypefuryCsv = exportToHypefuryCsv;
|
|
5832
6409
|
exports.exportToICalendar = exportToICalendar;
|
|
5833
6410
|
exports.generateADR = generateADR;
|
|
6411
|
+
exports.generateApiChangelog = generateApiChangelog;
|
|
5834
6412
|
exports.generateArc42 = generateArc42;
|
|
5835
6413
|
exports.generateArchitectureWalkthrough = generateArchitectureWalkthrough;
|
|
5836
6414
|
exports.generateAskDrivenAsset = generateAskDrivenAsset;
|
|
6415
|
+
exports.generateChangeImpactBrief = generateChangeImpactBrief;
|
|
5837
6416
|
exports.generateChangesSince = generateChangesSince;
|
|
5838
6417
|
exports.generateComplianceDoc = generateComplianceDoc;
|
|
5839
6418
|
exports.generateKnowledgeCapture = generateKnowledgeCapture;
|
|
@@ -5843,6 +6422,7 @@ exports.generatePresentation = generatePresentation;
|
|
|
5843
6422
|
exports.generateRadio = generateRadio;
|
|
5844
6423
|
exports.generateRefactoringReport = generateRefactoringReport;
|
|
5845
6424
|
exports.generateReleaseNotes = generateReleaseNotes;
|
|
6425
|
+
exports.generateRoiSlide = generateRoiSlide;
|
|
5846
6426
|
exports.generateSprintRetro = generateSprintRetro;
|
|
5847
6427
|
exports.getDispatchChannel = getDispatchChannel;
|
|
5848
6428
|
exports.getPrismTemplate = getPrismTemplate;
|