@kb-labs/release-manager-cli 2.82.0 → 2.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/build.d.ts +10 -0
- package/dist/cli/commands/build.js +87 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/changelog.js +65 -57
- package/dist/cli/commands/changelog.js.map +1 -1
- package/dist/cli/commands/checks.d.ts +10 -0
- package/dist/cli/commands/checks.js +93 -0
- package/dist/cli/commands/checks.js.map +1 -0
- package/dist/cli/commands/git.d.ts +13 -0
- package/dist/cli/commands/git.js +93 -0
- package/dist/cli/commands/git.js.map +1 -0
- package/dist/cli/commands/pack.d.ts +10 -0
- package/dist/cli/commands/pack.js +83 -0
- package/dist/cli/commands/pack.js.map +1 -0
- package/dist/cli/commands/plan.js +40 -41
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/publish.js +225 -194
- package/dist/cli/commands/publish.js.map +1 -1
- package/dist/cli/commands/report.js +28 -31
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/rollback.js +0 -3
- package/dist/cli/commands/rollback.js.map +1 -1
- package/dist/cli/commands/run.js +386 -300
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/verify.js +29 -28
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/commands/version.d.ts +12 -0
- package/dist/cli/commands/version.js +111 -0
- package/dist/cli/commands/version.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +146 -13
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +9 -0
- package/dist/manifest.js +131 -0
- package/dist/manifest.js.map +1 -1
- package/dist/rest/handlers/build-handler.js +22 -20
- package/dist/rest/handlers/build-handler.js.map +1 -1
- package/dist/rest/handlers/changelog-generate-handler.js +75 -88
- package/dist/rest/handlers/changelog-generate-handler.js.map +1 -1
- package/dist/rest/handlers/changelog-handler.js +1 -4
- package/dist/rest/handlers/changelog-handler.js.map +1 -1
- package/dist/rest/handlers/changelog-save-handler.js +0 -2
- package/dist/rest/handlers/changelog-save-handler.js.map +1 -1
- package/dist/rest/handlers/checklist-handler.js +113 -99
- package/dist/rest/handlers/checklist-handler.js.map +1 -1
- package/dist/rest/handlers/generate-handler.js +0 -3
- package/dist/rest/handlers/generate-handler.js.map +1 -1
- package/dist/rest/handlers/git-timeline-handler.js.map +1 -1
- package/dist/rest/handlers/history-changelog-handler.js +0 -1
- package/dist/rest/handlers/history-changelog-handler.js.map +1 -1
- package/dist/rest/handlers/history-handler.js +2 -3
- package/dist/rest/handlers/history-handler.js.map +1 -1
- package/dist/rest/handlers/history-plan-handler.js +0 -1
- package/dist/rest/handlers/history-plan-handler.js.map +1 -1
- package/dist/rest/handlers/history-report-handler.js +0 -1
- package/dist/rest/handlers/history-report-handler.js.map +1 -1
- package/dist/rest/handlers/plan-handler.js +0 -3
- package/dist/rest/handlers/plan-handler.js.map +1 -1
- package/dist/rest/handlers/preview-handler.js +0 -1
- package/dist/rest/handlers/preview-handler.js.map +1 -1
- package/dist/rest/handlers/report-handler.js +1 -1
- package/dist/rest/handlers/report-handler.js.map +1 -1
- package/dist/rest/handlers/reset-handler.js +0 -1
- package/dist/rest/handlers/reset-handler.js.map +1 -1
- package/dist/rest/handlers/run-checks-handler.js +0 -1
- package/dist/rest/handlers/run-checks-handler.js.map +1 -1
- package/dist/rest/handlers/run-handler.js +72 -52
- package/dist/rest/handlers/run-handler.js.map +1 -1
- package/dist/rest/handlers/status-handler.js +0 -2
- package/dist/rest/handlers/status-handler.js.map +1 -1
- package/dist/setup/handler.js.map +1 -1
- package/package.json +9 -8
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { defineHandler, findRepoRoot } from '@kb-labs/sdk';
|
|
2
2
|
import { generateSimpleChangelog, generateChangelog } from '@kb-labs/release-manager-changelog';
|
|
3
3
|
import { RELEASE_CACHE_PREFIX } from '@kb-labs/release-manager-contracts';
|
|
4
|
-
import 'path';
|
|
5
|
-
import 'fs/promises';
|
|
6
|
-
import 'globby';
|
|
7
4
|
|
|
8
5
|
// src/rest/handlers/changelog-generate-handler.ts
|
|
9
6
|
|
|
@@ -27,26 +24,81 @@ function scopeToDir(scope) {
|
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
// src/rest/handlers/changelog-generate-handler.ts
|
|
27
|
+
async function generateWithLLM(ctx, packages, repoRoot, gitCwd, locale, scope) {
|
|
28
|
+
try {
|
|
29
|
+
ctx.platform?.logger?.info?.("Starting LLM changelog generation", {
|
|
30
|
+
scope,
|
|
31
|
+
packagesCount: packages.length,
|
|
32
|
+
template: "corporate-ai"
|
|
33
|
+
});
|
|
34
|
+
const result = await generateChangelog({
|
|
35
|
+
repoRoot,
|
|
36
|
+
gitCwd,
|
|
37
|
+
packages,
|
|
38
|
+
range: { from: void 0, to: "HEAD" },
|
|
39
|
+
changelog: { template: "corporate-ai", locale },
|
|
40
|
+
platform: {
|
|
41
|
+
llm: ctx.platform.llm,
|
|
42
|
+
logger: ctx.platform.logger,
|
|
43
|
+
analytics: ctx.platform.analytics
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
ctx.platform?.logger?.info?.("LLM changelog generated", {
|
|
47
|
+
scope,
|
|
48
|
+
markdownLength: result.markdown.length,
|
|
49
|
+
linesCount: result.markdown.split("\n").length,
|
|
50
|
+
commitsCount: result.changes.length
|
|
51
|
+
});
|
|
52
|
+
return { markdown: result.markdown, commitsCount: result.changes.length, usedLLM: true };
|
|
53
|
+
} catch (err) {
|
|
54
|
+
ctx.platform?.logger?.error?.(
|
|
55
|
+
"Changelog generation failed, using simple fallback",
|
|
56
|
+
err instanceof Error ? err : void 0,
|
|
57
|
+
{ scope, packagesCount: packages.length }
|
|
58
|
+
);
|
|
59
|
+
return { markdown: generateSimpleChangelog(packages, "en"), commitsCount: 0, usedLLM: false };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function resolveMarkdown(ctx, packages, repoRoot, gitCwd, locale, useLLMFlag, scope) {
|
|
63
|
+
if (!useLLMFlag) {
|
|
64
|
+
ctx.platform?.logger?.info?.("Using simple changelog (LLM disabled by user)", { scope });
|
|
65
|
+
return { markdown: generateSimpleChangelog(packages, "en"), commitsCount: 0, usedLLM: false };
|
|
66
|
+
}
|
|
67
|
+
const hasLLM = !!ctx.platform?.llm;
|
|
68
|
+
ctx.platform?.logger?.info?.("Changelog generation mode", { scope, useLLM: useLLMFlag, hasLLMPlatform: hasLLM });
|
|
69
|
+
if (!hasLLM) {
|
|
70
|
+
ctx.platform?.logger?.warn?.("LLM service not available, falling back to simple changelog", { scope });
|
|
71
|
+
return { markdown: generateSimpleChangelog(packages, "en"), commitsCount: 0, usedLLM: false };
|
|
72
|
+
}
|
|
73
|
+
return generateWithLLM(ctx, packages, repoRoot, gitCwd, locale, scope);
|
|
74
|
+
}
|
|
75
|
+
async function resolveGitCwd(packages, repoRoot) {
|
|
76
|
+
if (!packages.length || !packages[0]) {
|
|
77
|
+
return repoRoot;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return await findRepoRoot(packages[0].path);
|
|
81
|
+
} catch {
|
|
82
|
+
return packages[0].path;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
30
85
|
var changelog_generate_handler_default = defineHandler({
|
|
31
86
|
async execute(ctx, input) {
|
|
32
87
|
const scope = input.body?.scope || "root";
|
|
33
88
|
const cwd = ctx.cwd ?? process.cwd();
|
|
34
89
|
const repoRoot = await findRepoRoot(cwd);
|
|
35
90
|
const startTime = Date.now();
|
|
36
|
-
ctx.platform?.analytics?.track?.(ANALYTICS_EVENTS.CHANGELOG_STARTED, {
|
|
37
|
-
scope,
|
|
38
|
-
actor: ANALYTICS_ACTOR
|
|
39
|
-
});
|
|
91
|
+
ctx.platform?.analytics?.track?.(ANALYTICS_EVENTS.CHANGELOG_STARTED, { scope, actor: ANALYTICS_ACTOR });
|
|
40
92
|
const scopeDirName = scopeToDir(scope);
|
|
41
93
|
const planPath = `${repoRoot}/.kb/release/plans/${scopeDirName}/current/plan.json`;
|
|
42
94
|
let plan;
|
|
43
95
|
try {
|
|
44
96
|
const planContent = await ctx.runtime.fs.readFile(planPath, "utf-8");
|
|
45
97
|
plan = JSON.parse(planContent);
|
|
46
|
-
} catch (
|
|
98
|
+
} catch (err) {
|
|
47
99
|
ctx.platform?.logger?.error?.(
|
|
48
100
|
"Failed to read release plan",
|
|
49
|
-
|
|
101
|
+
err instanceof Error ? err : void 0,
|
|
50
102
|
{ scope, planPath }
|
|
51
103
|
);
|
|
52
104
|
throw new Error(`Release plan not found for scope "${scope}". Generate plan first.`);
|
|
@@ -58,77 +110,18 @@ var changelog_generate_handler_default = defineHandler({
|
|
|
58
110
|
nextVersion: pkg.nextVersion,
|
|
59
111
|
bump: pkg.bump === "auto" ? "patch" : pkg.bump
|
|
60
112
|
}));
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const useLLM = input.body?.useLLM ?? true;
|
|
74
|
-
if (!useLLM) {
|
|
75
|
-
ctx.platform?.logger?.info?.("Using simple changelog (LLM disabled by user)", { scope });
|
|
76
|
-
markdown = generateSimpleChangelog(packages, "en");
|
|
77
|
-
} else {
|
|
78
|
-
const hasLLM = !!ctx.platform?.llm;
|
|
79
|
-
ctx.platform?.logger?.info?.("Changelog generation mode", {
|
|
80
|
-
scope,
|
|
81
|
-
useLLM,
|
|
82
|
-
hasLLMPlatform: hasLLM
|
|
83
|
-
});
|
|
84
|
-
if (!hasLLM) {
|
|
85
|
-
ctx.platform?.logger?.warn?.("LLM service not available, falling back to simple changelog", { scope });
|
|
86
|
-
markdown = generateSimpleChangelog(packages, "en");
|
|
87
|
-
} else {
|
|
88
|
-
try {
|
|
89
|
-
ctx.platform?.logger?.info?.("Starting LLM changelog generation", {
|
|
90
|
-
scope,
|
|
91
|
-
packagesCount: packages.length,
|
|
92
|
-
template: "corporate-ai"
|
|
93
|
-
});
|
|
94
|
-
const result = await generateChangelog({
|
|
95
|
-
repoRoot,
|
|
96
|
-
gitCwd,
|
|
97
|
-
packages,
|
|
98
|
-
range: {
|
|
99
|
-
from: void 0,
|
|
100
|
-
// Auto-detect from tags
|
|
101
|
-
to: "HEAD"
|
|
102
|
-
},
|
|
103
|
-
changelog: {
|
|
104
|
-
template: "corporate-ai",
|
|
105
|
-
locale: input.body?.locale || "en"
|
|
106
|
-
},
|
|
107
|
-
platform: {
|
|
108
|
-
llm: ctx.platform.llm,
|
|
109
|
-
logger: ctx.platform.logger,
|
|
110
|
-
analytics: ctx.platform.analytics
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
markdown = result.markdown;
|
|
114
|
-
commitsCount = result.changes.length;
|
|
115
|
-
usedLLM = true;
|
|
116
|
-
ctx.platform?.logger?.info?.("LLM changelog generated", {
|
|
117
|
-
scope,
|
|
118
|
-
markdownLength: markdown.length,
|
|
119
|
-
linesCount: markdown.split("\n").length,
|
|
120
|
-
commitsCount
|
|
121
|
-
});
|
|
122
|
-
} catch (error) {
|
|
123
|
-
ctx.platform?.logger?.error?.(
|
|
124
|
-
"Changelog generation failed, using simple fallback",
|
|
125
|
-
error instanceof Error ? error : void 0,
|
|
126
|
-
{ scope, packagesCount: packages.length }
|
|
127
|
-
);
|
|
128
|
-
markdown = generateSimpleChangelog(packages, "en");
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
113
|
+
const gitCwd = await resolveGitCwd(packages, repoRoot);
|
|
114
|
+
const localeRaw = input.body?.locale;
|
|
115
|
+
const locale = localeRaw === "ru" ? "ru" : "en";
|
|
116
|
+
const { markdown, commitsCount, usedLLM } = await resolveMarkdown(
|
|
117
|
+
ctx,
|
|
118
|
+
packages,
|
|
119
|
+
repoRoot,
|
|
120
|
+
gitCwd,
|
|
121
|
+
locale,
|
|
122
|
+
input.body?.useLLM ?? true,
|
|
123
|
+
scope
|
|
124
|
+
);
|
|
132
125
|
const scopeDir = `${repoRoot}/.kb/release/plans/${scopeDirName}/current`;
|
|
133
126
|
await ctx.runtime.fs.mkdir(scopeDir, { recursive: true });
|
|
134
127
|
const changelogPath = `${scopeDir}/changelog.md`;
|
|
@@ -136,6 +129,7 @@ var changelog_generate_handler_default = defineHandler({
|
|
|
136
129
|
const cacheKey = `${RELEASE_CACHE_PREFIX}changelog:${scope}`;
|
|
137
130
|
await ctx.platform?.cache?.delete(cacheKey);
|
|
138
131
|
const duration = Date.now() - startTime;
|
|
132
|
+
const tokensUsed = 0;
|
|
139
133
|
ctx.platform?.logger?.info?.("Changelog generated", {
|
|
140
134
|
scope,
|
|
141
135
|
path: changelogPath,
|
|
@@ -153,14 +147,7 @@ var changelog_generate_handler_default = defineHandler({
|
|
|
153
147
|
usedLLM,
|
|
154
148
|
actor: ANALYTICS_ACTOR
|
|
155
149
|
});
|
|
156
|
-
return {
|
|
157
|
-
scope,
|
|
158
|
-
markdown,
|
|
159
|
-
changelogPath,
|
|
160
|
-
tokensUsed,
|
|
161
|
-
usedLLM,
|
|
162
|
-
commitsCount
|
|
163
|
-
};
|
|
150
|
+
return { scope, markdown, changelogPath, tokensUsed, usedLLM, commitsCount };
|
|
164
151
|
}
|
|
165
152
|
});
|
|
166
153
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/analytics/events.ts","../../../src/shared/utils.ts","../../../src/rest/handlers/changelog-generate-handler.ts"],"names":["findRepoRoot"],"mappings":"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","file":"changelog-generate-handler.js","sourcesContent":["/**\n * Analytics event types for Release CLI\n * Centralized constants to prevent typos and enable type safety\n */\n\n/**\n * Event type prefixes by command\n */\nexport const ANALYTICS_PREFIX = {\n PLAN: 'release.plan',\n RUN: 'release.run',\n ROLLBACK: 'release.rollback',\n REPORT: 'release.report',\n CHANGELOG: 'release.changelog',\n PREVIEW: 'release.preview',\n VERIFY: 'release.verify',\n PUBLISH: 'release.publish',\n} as const;\n\n/**\n * Event lifecycle suffixes\n */\nexport const ANALYTICS_SUFFIX = {\n STARTED: 'started',\n FINISHED: 'finished',\n} as const;\n\n/**\n * Release analytics event types\n */\nexport const ANALYTICS_EVENTS = {\n // Plan events\n PLAN_STARTED: `${ANALYTICS_PREFIX.PLAN}.${ANALYTICS_SUFFIX.STARTED}`,\n PLAN_FINISHED: `${ANALYTICS_PREFIX.PLAN}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Run events\n RUN_STARTED: `${ANALYTICS_PREFIX.RUN}.${ANALYTICS_SUFFIX.STARTED}`,\n RUN_FINISHED: `${ANALYTICS_PREFIX.RUN}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Rollback events\n ROLLBACK_STARTED: `${ANALYTICS_PREFIX.ROLLBACK}.${ANALYTICS_SUFFIX.STARTED}`,\n ROLLBACK_FINISHED: `${ANALYTICS_PREFIX.ROLLBACK}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Report events\n REPORT_STARTED: `${ANALYTICS_PREFIX.REPORT}.${ANALYTICS_SUFFIX.STARTED}`,\n REPORT_FINISHED: `${ANALYTICS_PREFIX.REPORT}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Changelog events\n CHANGELOG_STARTED: `${ANALYTICS_PREFIX.CHANGELOG}.${ANALYTICS_SUFFIX.STARTED}`,\n CHANGELOG_FINISHED: `${ANALYTICS_PREFIX.CHANGELOG}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Preview events\n PREVIEW_STARTED: `${ANALYTICS_PREFIX.PREVIEW}.${ANALYTICS_SUFFIX.STARTED}`,\n PREVIEW_FINISHED: `${ANALYTICS_PREFIX.PREVIEW}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Verify events\n VERIFY_STARTED: `${ANALYTICS_PREFIX.VERIFY}.${ANALYTICS_SUFFIX.STARTED}`,\n VERIFY_FINISHED: `${ANALYTICS_PREFIX.VERIFY}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Publish events\n PUBLISH_STARTED: `${ANALYTICS_PREFIX.PUBLISH}.${ANALYTICS_SUFFIX.STARTED}`,\n PUBLISH_FINISHED: `${ANALYTICS_PREFIX.PUBLISH}.${ANALYTICS_SUFFIX.FINISHED}`,\n} as const;\n\n/**\n * Type helper for analytics event types\n */\nexport type AnalyticsEventType = typeof ANALYTICS_EVENTS[keyof typeof ANALYTICS_EVENTS];\n\n/**\n * Actor configuration for Release analytics\n */\nexport const ANALYTICS_ACTOR = {\n type: 'agent' as const,\n id: 'release-cli',\n} as const;\n\n","import { join } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport globby from 'globby';\n\nexport { findRepoRoot } from '@kb-labs/sdk';\n\n/**\n * Converts scope to safe directory name\n */\nexport function scopeToDir(scope: string): string {\n return scope\n .replace(/^@/, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '-')\n .replace(/\\*/g, '');\n}\n\n/**\n * Converts safe directory name back to scope\n */\nexport function dirToScope(dirName: string): string {\n if (dirName === 'root') {\n return 'root';\n }\n\n const parts = dirName.split('-');\n if (parts.length >= 2) {\n return '@' + parts[0] + '-' + parts[1] + '/' + parts.slice(2).join('-');\n }\n\n return dirName;\n}\n\n/**\n * Resolve scope name to absolute filesystem path.\n * Scans all package.json in repoRoot to find the matching package by name.\n */\nexport async function resolveScopePath(repoRoot: string, scope: string): Promise<string> {\n if (scope === 'root') {\n return repoRoot;\n }\n\n if (scope.startsWith('@')) {\n const packageJsonPaths = await globby('**/package.json', {\n cwd: repoRoot,\n absolute: true,\n onlyFiles: true,\n ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**', '**/.*/**'],\n });\n\n for (const pkgJsonPath of packageJsonPaths) {\n try {\n const pkg = JSON.parse(await readFile(pkgJsonPath, 'utf-8'));\n if (pkg.name === scope) {\n return join(pkgJsonPath, '..');\n }\n } catch { /* skip */ }\n }\n }\n\n // Direct path or fallback\n return join(repoRoot, scope);\n}\n","/**\n * Changelog generate handler - Generate changelog using LLM\n *\n * Writes: .kb/release/plans/{scope}/current/changelog.md\n */\n\nimport { defineHandler, findRepoRoot, type RestInput } from '@kb-labs/sdk';\nimport type {\n GenerateChangelogRequest,\n GenerateChangelogResponse,\n ReleasePlan,\n} from '@kb-labs/release-manager-contracts';\nimport {\n generateChangelog,\n generateSimpleChangelog,\n type ChangelogPackageInfo,\n} from '@kb-labs/release-manager-changelog';\nimport { ANALYTICS_EVENTS, ANALYTICS_ACTOR } from '../../infra/analytics/events';\nimport { RELEASE_CACHE_PREFIX } from '@kb-labs/release-manager-contracts';\nimport { scopeToDir } from '../../shared/utils';\n\nexport default defineHandler({\n async execute(ctx, input: RestInput<unknown, GenerateChangelogRequest>): Promise<GenerateChangelogResponse> {\n const scope = input.body?.scope || 'root';\n const cwd = ctx.cwd ?? process.cwd();\n const repoRoot = await findRepoRoot(cwd);\n const startTime = Date.now();\n\n // Track start\n ctx.platform?.analytics?.track?.(ANALYTICS_EVENTS.CHANGELOG_STARTED, {\n scope,\n actor: ANALYTICS_ACTOR,\n });\n\n // 1. Read release plan to get package info\n const scopeDirName = scopeToDir(scope);\n const planPath = `${repoRoot}/.kb/release/plans/${scopeDirName}/current/plan.json`;\n let plan: ReleasePlan;\n try {\n const planContent = await ctx.runtime.fs.readFile(planPath, 'utf-8');\n plan = JSON.parse(planContent);\n } catch (error) {\n ctx.platform?.logger?.error?.(\n 'Failed to read release plan',\n error instanceof Error ? error : undefined,\n { scope, planPath }\n );\n throw new Error(`Release plan not found for scope \"${scope}\". Generate plan first.`);\n }\n\n // 2. Convert plan packages to changelog format\n const packages: ChangelogPackageInfo[] = plan.packages.map(pkg => ({\n name: pkg.name,\n path: pkg.path,\n currentVersion: pkg.currentVersion,\n nextVersion: pkg.nextVersion,\n bump: pkg.bump === 'auto' ? 'patch' : pkg.bump,\n }));\n\n // 3. Determine git working directory (for submodule support)\n let gitCwd = repoRoot;\n if (packages.length > 0 && packages[0]) {\n try {\n gitCwd = await findRepoRoot(packages[0].path);\n } catch {\n gitCwd = packages[0].path;\n }\n }\n\n // 4. Generate changelog using real implementation\n let markdown: string;\n const tokensUsed = 0;\n let usedLLM = false;\n let commitsCount = 0;\n const useLLM = input.body?.useLLM ?? true;\n\n // Skip LLM if disabled - use simple changelog\n if (!useLLM) {\n ctx.platform?.logger?.info?.('Using simple changelog (LLM disabled by user)', { scope });\n markdown = generateSimpleChangelog(packages, 'en');\n } else {\n const hasLLM = !!ctx.platform?.llm;\n ctx.platform?.logger?.info?.('Changelog generation mode', {\n scope,\n useLLM,\n hasLLMPlatform: hasLLM,\n });\n\n if (!hasLLM) {\n ctx.platform?.logger?.warn?.('LLM service not available, falling back to simple changelog', { scope });\n markdown = generateSimpleChangelog(packages, 'en');\n } else {\n try {\n ctx.platform?.logger?.info?.('Starting LLM changelog generation', {\n scope,\n packagesCount: packages.length,\n template: 'corporate-ai',\n });\n\n const result = await generateChangelog({\n repoRoot,\n gitCwd,\n packages,\n range: {\n from: undefined, // Auto-detect from tags\n to: 'HEAD',\n },\n changelog: {\n template: 'corporate-ai',\n locale: input.body?.locale || 'en',\n },\n platform: {\n llm: ctx.platform.llm,\n logger: ctx.platform.logger,\n analytics: ctx.platform.analytics,\n },\n });\n\n markdown = result.markdown;\n commitsCount = result.changes.length;\n usedLLM = true;\n\n ctx.platform?.logger?.info?.('LLM changelog generated', {\n scope,\n markdownLength: markdown.length,\n linesCount: markdown.split('\\n').length,\n commitsCount,\n });\n } catch (error) {\n // Fallback to simple changelog if generation fails\n ctx.platform?.logger?.error?.(\n 'Changelog generation failed, using simple fallback',\n error instanceof Error ? error : undefined,\n { scope, packagesCount: packages.length }\n );\n markdown = generateSimpleChangelog(packages, 'en');\n }\n }\n }\n\n // 5. Ensure directory exists\n const scopeDir = `${repoRoot}/.kb/release/plans/${scopeDirName}/current`;\n await ctx.runtime.fs.mkdir(scopeDir, { recursive: true });\n\n // 6. Write changelog\n const changelogPath = `${scopeDir}/changelog.md`;\n await ctx.runtime.fs.writeFile(changelogPath, markdown, { encoding: 'utf-8' });\n\n // 7. Invalidate cache so next GET request fetches fresh data\n const cacheKey = `${RELEASE_CACHE_PREFIX}changelog:${scope}`;\n await ctx.platform?.cache?.delete(cacheKey);\n\n const duration = Date.now() - startTime;\n\n ctx.platform?.logger?.info?.('Changelog generated', {\n scope,\n path: changelogPath,\n packagesCount: packages.length,\n commitsCount,\n usedLLM,\n durationMs: duration,\n });\n\n // Track completion\n ctx.platform?.analytics?.track?.(ANALYTICS_EVENTS.CHANGELOG_FINISHED, {\n scope,\n packagesCount: packages.length,\n commitsCount,\n durationMs: duration,\n tokensUsed,\n usedLLM,\n actor: ANALYTICS_ACTOR,\n });\n\n return {\n scope,\n markdown,\n changelogPath,\n tokensUsed,\n usedLLM,\n commitsCount,\n };\n }\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/analytics/events.ts","../../../src/shared/utils.ts","../../../src/rest/handlers/changelog-generate-handler.ts"],"names":["findRepoRoot"],"mappings":";;;;;;;AAQO,IAAM,gBAAA,GAAmB;AAAA,EAK9B,SAAA,EAAW,mBAIb,CAAA;AAKO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,OAAA,EAAS,SAAA;AAAA,EACT,QAAA,EAAU;AACZ,CAAA;AAKO,IAAM,gBAAA,GAAmB;AAAA,EAe0C;AAAA,EAGxE,mBAAmB,CAAA,EAAG,gBAAA,CAAiB,SAAS,CAAA,CAAA,EAAI,iBAAiB,OAAO,CAAA,CAAA;AAAA,EAC5E,oBAAoB,CAAA,EAAG,gBAAA,CAAiB,SAAS,CAAA,CAAA,EAAI,iBAAiB,QAAQ,CAAA,CAahF,CAAA;AAUO,IAAM,eAAA,GAAkB;AAAA,EAC7B,IAAA,EAAM,OAAA;AAAA,EACN,EAAA,EAAI;AACN,CAAA;ACrEO,SAAS,WAAW,KAAA,EAAuB;AAChD,EAAA,OAAO,KAAA,CACJ,OAAA,CAAQ,IAAA,EAAM,EAAE,EAChB,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAClB,QAAQ,IAAA,EAAM,GAAG,CAAA,CACjB,OAAA,CAAQ,OAAO,EAAE,CAAA;AACtB;;;ACiBA,eAAe,gBACb,GAAA,EACA,QAAA,EACA,QAAA,EACA,MAAA,EACA,QACA,KAAA,EACyB;AACzB,EAAA,IAAI;AACF,IAAA,GAAA,CAAI,QAAA,EAAU,MAAA,EAAQ,IAAA,GAAO,mCAAA,EAAqC;AAAA,MAChE,KAAA;AAAA,MACA,eAAe,QAAA,CAAS,MAAA;AAAA,MACxB,QAAA,EAAU;AAAA,KACX,CAAA;AACD,IAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB;AAAA,MACrC,QAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,MACA,KAAA,EAAO,EAAE,IAAA,EAAM,KAAA,CAAA,EAAW,IAAI,MAAA,EAAO;AAAA,MACrC,SAAA,EAAW,EAAE,QAAA,EAAU,cAAA,EAAgB,MAAA,EAAO;AAAA,MAC9C,QAAA,EAAU;AAAA,QACR,GAAA,EAAK,IAAI,QAAA,CAAS,GAAA;AAAA,QAClB,MAAA,EAAQ,IAAI,QAAA,CAAS,MAAA;AAAA,QACrB,SAAA,EAAW,IAAI,QAAA,CAAS;AAAA;AAC1B,KACD,CAAA;AACD,IAAA,GAAA,CAAI,QAAA,EAAU,MAAA,EAAQ,IAAA,GAAO,yBAAA,EAA2B;AAAA,MACtD,KAAA;AAAA,MACA,cAAA,EAAgB,OAAO,QAAA,CAAS,MAAA;AAAA,MAChC,UAAA,EAAY,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,CAAE,MAAA;AAAA,MACxC,YAAA,EAAc,OAAO,OAAA,CAAQ;AAAA,KAC9B,CAAA;AACD,IAAA,OAAO,EAAE,UAAU,MAAA,CAAO,QAAA,EAAU,cAAc,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAK;AAAA,EACzF,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,UAAU,MAAA,EAAQ,KAAA;AAAA,MACpB,oDAAA;AAAA,MACA,GAAA,YAAe,QAAQ,GAAA,GAAM,MAAA;AAAA,MAC7B,EAAE,KAAA,EAAO,aAAA,EAAe,QAAA,CAAS,MAAA;AAAO,KAC1C;AACA,IAAA,OAAO,EAAE,UAAU,uBAAA,CAAwB,QAAA,EAAU,IAAI,CAAA,EAAG,YAAA,EAAc,CAAA,EAAG,OAAA,EAAS,KAAA,EAAM;AAAA,EAC9F;AACF;AAEA,eAAe,gBACb,GAAA,EACA,QAAA,EACA,UACA,MAAA,EACA,MAAA,EACA,YACA,KAAA,EACyB;AACzB,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,GAAA,CAAI,UAAU,MAAA,EAAQ,IAAA,GAAO,+CAAA,EAAiD,EAAE,OAAO,CAAA;AACvF,IAAA,OAAO,EAAE,UAAU,uBAAA,CAAwB,QAAA,EAAU,IAAI,CAAA,EAAG,YAAA,EAAc,CAAA,EAAG,OAAA,EAAS,KAAA,EAAM;AAAA,EAC9F;AACA,EAAA,MAAM,MAAA,GAAS,CAAC,CAAC,GAAA,CAAI,QAAA,EAAU,GAAA;AAC/B,EAAA,GAAA,CAAI,QAAA,EAAU,MAAA,EAAQ,IAAA,GAAO,2BAAA,EAA6B,EAAE,OAAO,MAAA,EAAQ,UAAA,EAAY,cAAA,EAAgB,MAAA,EAAQ,CAAA;AAC/G,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,GAAA,CAAI,UAAU,MAAA,EAAQ,IAAA,GAAO,6DAAA,EAA+D,EAAE,OAAO,CAAA;AACrG,IAAA,OAAO,EAAE,UAAU,uBAAA,CAAwB,QAAA,EAAU,IAAI,CAAA,EAAG,YAAA,EAAc,CAAA,EAAG,OAAA,EAAS,KAAA,EAAM;AAAA,EAC9F;AACA,EAAA,OAAO,gBAAgB,GAAA,EAAK,QAAA,EAAU,QAAA,EAAU,MAAA,EAAQ,QAAQ,KAAK,CAAA;AACvE;AAEA,eAAe,aAAA,CAAc,UAAkC,QAAA,EAAmC;AAChG,EAAA,IAAI,CAAC,QAAA,CAAS,MAAA,IAAU,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG;AAAE,IAAA,OAAO,QAAA;AAAA,EAAU;AACzD,EAAA,IAAI;AACF,IAAA,OAAO,MAAMA,YAAAA,CAAa,QAAA,CAAS,CAAC,EAAE,IAAI,CAAA;AAAA,EAC5C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,QAAA,CAAS,CAAC,CAAA,CAAE,IAAA;AAAA,EACrB;AACF;AAIA,IAAO,qCAAQ,aAAA,CAAc;AAAA,EAC3B,MAAM,OAAA,CAAQ,GAAA,EAAK,KAAA,EAAyF;AAC1G,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,EAAM,KAAA,IAAS,MAAA;AACnC,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AACnC,IAAA,MAAM,QAAA,GAAW,MAAMA,YAAAA,CAAa,GAAG,CAAA;AACvC,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,GAAA,CAAI,QAAA,EAAU,WAAW,KAAA,GAAQ,gBAAA,CAAiB,mBAAmB,EAAE,KAAA,EAAO,KAAA,EAAO,eAAA,EAAiB,CAAA;AAEtG,IAAA,MAAM,YAAA,GAAe,WAAW,KAAK,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,QAAQ,CAAA,mBAAA,EAAsB,YAAY,CAAA,kBAAA,CAAA;AAC9D,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAM,cAAc,MAAM,GAAA,CAAI,QAAQ,EAAA,CAAG,QAAA,CAAS,UAAU,OAAO,CAAA;AACnE,MAAA,IAAA,GAAO,IAAA,CAAK,MAAM,WAAW,CAAA;AAAA,IAC/B,SAAS,GAAA,EAAK;AACZ,MAAA,GAAA,CAAI,UAAU,MAAA,EAAQ,KAAA;AAAA,QACpB,6BAAA;AAAA,QACA,GAAA,YAAe,QAAQ,GAAA,GAAM,MAAA;AAAA,QAC7B,EAAE,OAAO,QAAA;AAAS,OACpB;AACA,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAK,CAAA,uBAAA,CAAyB,CAAA;AAAA,IACrF;AAEA,IAAA,MAAM,QAAA,GAAmC,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAA,GAAA,MAAQ;AAAA,MACjE,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,gBAAgB,GAAA,CAAI,cAAA;AAAA,MACpB,aAAa,GAAA,CAAI,WAAA;AAAA,MACjB,IAAA,EAAM,GAAA,CAAI,IAAA,KAAS,MAAA,GAAS,UAAU,GAAA,CAAI;AAAA,KAC5C,CAAE,CAAA;AAEF,IAAA,MAAM,MAAA,GAAS,MAAM,aAAA,CAAc,QAAA,EAAU,QAAQ,CAAA;AAErD,IAAA,MAAM,SAAA,GAAY,MAAM,IAAA,EAAM,MAAA;AAC9B,IAAA,MAAM,MAAA,GAAsB,SAAA,KAAc,IAAA,GAAO,IAAA,GAAO,IAAA;AAExD,IAAA,MAAM,EAAE,QAAA,EAAU,YAAA,EAAc,OAAA,KAAY,MAAM,eAAA;AAAA,MAChD,GAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA,CAAM,MAAM,MAAA,IAAU,IAAA;AAAA,MACtB;AAAA,KACF;AAEA,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,QAAQ,CAAA,mBAAA,EAAsB,YAAY,CAAA,QAAA,CAAA;AAC9D,IAAA,MAAM,GAAA,CAAI,QAAQ,EAAA,CAAG,KAAA,CAAM,UAAU,EAAE,SAAA,EAAW,MAAM,CAAA;AAExD,IAAA,MAAM,aAAA,GAAgB,GAAG,QAAQ,CAAA,aAAA,CAAA;AACjC,IAAA,MAAM,GAAA,CAAI,QAAQ,EAAA,CAAG,SAAA,CAAU,eAAe,QAAA,EAAU,EAAE,QAAA,EAAU,OAAA,EAAS,CAAA;AAE7E,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,oBAAoB,CAAA,UAAA,EAAa,KAAK,CAAA,CAAA;AAC1D,IAAA,MAAM,GAAA,CAAI,QAAA,EAAU,KAAA,EAAO,MAAA,CAAO,QAAQ,CAAA;AAE1C,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC9B,IAAA,MAAM,UAAA,GAAa,CAAA;AAEnB,IAAA,GAAA,CAAI,QAAA,EAAU,MAAA,EAAQ,IAAA,GAAO,qBAAA,EAAuB;AAAA,MAClD,KAAA;AAAA,MAAO,IAAA,EAAM,aAAA;AAAA,MAAe,eAAe,QAAA,CAAS,MAAA;AAAA,MACpD,YAAA;AAAA,MAAc,OAAA;AAAA,MAAS,UAAA,EAAY;AAAA,KACpC,CAAA;AAED,IAAA,GAAA,CAAI,QAAA,EAAU,SAAA,EAAW,KAAA,GAAQ,gBAAA,CAAiB,kBAAA,EAAoB;AAAA,MACpE,KAAA;AAAA,MAAO,eAAe,QAAA,CAAS,MAAA;AAAA,MAAQ,YAAA;AAAA,MACvC,UAAA,EAAY,QAAA;AAAA,MAAU,UAAA;AAAA,MAAY,OAAA;AAAA,MAAS,KAAA,EAAO;AAAA,KACnD,CAAA;AAED,IAAA,OAAO,EAAE,KAAA,EAAO,QAAA,EAAU,aAAA,EAAe,UAAA,EAAY,SAAS,YAAA,EAAa;AAAA,EAC7E;AACF,CAAC","file":"changelog-generate-handler.js","sourcesContent":["/**\n * Analytics event types for Release CLI\n * Centralized constants to prevent typos and enable type safety\n */\n\n/**\n * Event type prefixes by command\n */\nexport const ANALYTICS_PREFIX = {\n PLAN: 'release.plan',\n RUN: 'release.run',\n ROLLBACK: 'release.rollback',\n REPORT: 'release.report',\n CHANGELOG: 'release.changelog',\n PREVIEW: 'release.preview',\n VERIFY: 'release.verify',\n PUBLISH: 'release.publish',\n} as const;\n\n/**\n * Event lifecycle suffixes\n */\nexport const ANALYTICS_SUFFIX = {\n STARTED: 'started',\n FINISHED: 'finished',\n} as const;\n\n/**\n * Release analytics event types\n */\nexport const ANALYTICS_EVENTS = {\n // Plan events\n PLAN_STARTED: `${ANALYTICS_PREFIX.PLAN}.${ANALYTICS_SUFFIX.STARTED}`,\n PLAN_FINISHED: `${ANALYTICS_PREFIX.PLAN}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Run events\n RUN_STARTED: `${ANALYTICS_PREFIX.RUN}.${ANALYTICS_SUFFIX.STARTED}`,\n RUN_FINISHED: `${ANALYTICS_PREFIX.RUN}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Rollback events\n ROLLBACK_STARTED: `${ANALYTICS_PREFIX.ROLLBACK}.${ANALYTICS_SUFFIX.STARTED}`,\n ROLLBACK_FINISHED: `${ANALYTICS_PREFIX.ROLLBACK}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Report events\n REPORT_STARTED: `${ANALYTICS_PREFIX.REPORT}.${ANALYTICS_SUFFIX.STARTED}`,\n REPORT_FINISHED: `${ANALYTICS_PREFIX.REPORT}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Changelog events\n CHANGELOG_STARTED: `${ANALYTICS_PREFIX.CHANGELOG}.${ANALYTICS_SUFFIX.STARTED}`,\n CHANGELOG_FINISHED: `${ANALYTICS_PREFIX.CHANGELOG}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Preview events\n PREVIEW_STARTED: `${ANALYTICS_PREFIX.PREVIEW}.${ANALYTICS_SUFFIX.STARTED}`,\n PREVIEW_FINISHED: `${ANALYTICS_PREFIX.PREVIEW}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Verify events\n VERIFY_STARTED: `${ANALYTICS_PREFIX.VERIFY}.${ANALYTICS_SUFFIX.STARTED}`,\n VERIFY_FINISHED: `${ANALYTICS_PREFIX.VERIFY}.${ANALYTICS_SUFFIX.FINISHED}`,\n\n // Publish events\n PUBLISH_STARTED: `${ANALYTICS_PREFIX.PUBLISH}.${ANALYTICS_SUFFIX.STARTED}`,\n PUBLISH_FINISHED: `${ANALYTICS_PREFIX.PUBLISH}.${ANALYTICS_SUFFIX.FINISHED}`,\n} as const;\n\n/**\n * Type helper for analytics event types\n */\nexport type AnalyticsEventType = typeof ANALYTICS_EVENTS[keyof typeof ANALYTICS_EVENTS];\n\n/**\n * Actor configuration for Release analytics\n */\nexport const ANALYTICS_ACTOR = {\n type: 'agent' as const,\n id: 'release-cli',\n} as const;\n\n","export { findRepoRoot } from '@kb-labs/sdk';\nexport { resolveScopePath } from './resolve-scope';\n\n/**\n * Converts scope to safe directory name\n */\nexport function scopeToDir(scope: string): string {\n return scope\n .replace(/^@/, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '-')\n .replace(/\\*/g, '');\n}\n\n/**\n * Converts safe directory name back to scope\n */\nexport function dirToScope(dirName: string): string {\n if (dirName === 'root') {\n return 'root';\n }\n\n const parts = dirName.split('-');\n if (parts.length >= 2) {\n return '@' + parts[0] + '-' + parts[1] + '/' + parts.slice(2).join('-');\n }\n\n return dirName;\n}\n","/**\n * Changelog generate handler - Generate changelog using LLM\n *\n * Writes: .kb/release/plans/{scope}/current/changelog.md\n */\n\nimport { defineHandler, findRepoRoot, type RestInput } from '@kb-labs/sdk';\nimport type {\n GenerateChangelogRequest,\n GenerateChangelogResponse,\n ReleasePlan,\n} from '@kb-labs/release-manager-contracts';\nimport {\n generateChangelog,\n generateSimpleChangelog,\n type ChangelogPackageInfo,\n} from '@kb-labs/release-manager-changelog';\nimport { ANALYTICS_EVENTS, ANALYTICS_ACTOR } from '../../infra/analytics/events';\nimport { RELEASE_CACHE_PREFIX } from '@kb-labs/release-manager-contracts';\nimport { scopeToDir } from '../../shared/utils';\n\n// ── helpers ────────────────────────────────────────────────────────────────\n\ninterface GenerateResult {\n markdown: string;\n commitsCount: number;\n usedLLM: boolean;\n}\n\nasync function generateWithLLM(\n ctx: Parameters<typeof defineHandler>[0] extends { execute(ctx: infer C, ...args: any[]): any } ? C : any,\n packages: ChangelogPackageInfo[],\n repoRoot: string,\n gitCwd: string,\n locale: 'en' | 'ru',\n scope: string,\n): Promise<GenerateResult> {\n try {\n ctx.platform?.logger?.info?.('Starting LLM changelog generation', {\n scope,\n packagesCount: packages.length,\n template: 'corporate-ai',\n });\n const result = await generateChangelog({\n repoRoot,\n gitCwd,\n packages,\n range: { from: undefined, to: 'HEAD' },\n changelog: { template: 'corporate-ai', locale },\n platform: {\n llm: ctx.platform.llm,\n logger: ctx.platform.logger,\n analytics: ctx.platform.analytics,\n },\n });\n ctx.platform?.logger?.info?.('LLM changelog generated', {\n scope,\n markdownLength: result.markdown.length,\n linesCount: result.markdown.split('\\n').length,\n commitsCount: result.changes.length,\n });\n return { markdown: result.markdown, commitsCount: result.changes.length, usedLLM: true };\n } catch (err) {\n ctx.platform?.logger?.error?.(\n 'Changelog generation failed, using simple fallback',\n err instanceof Error ? err : undefined,\n { scope, packagesCount: packages.length },\n );\n return { markdown: generateSimpleChangelog(packages, 'en'), commitsCount: 0, usedLLM: false };\n }\n}\n\nasync function resolveMarkdown(\n ctx: any,\n packages: ChangelogPackageInfo[],\n repoRoot: string,\n gitCwd: string,\n locale: 'en' | 'ru',\n useLLMFlag: boolean,\n scope: string,\n): Promise<GenerateResult> {\n if (!useLLMFlag) {\n ctx.platform?.logger?.info?.('Using simple changelog (LLM disabled by user)', { scope });\n return { markdown: generateSimpleChangelog(packages, 'en'), commitsCount: 0, usedLLM: false };\n }\n const hasLLM = !!ctx.platform?.llm;\n ctx.platform?.logger?.info?.('Changelog generation mode', { scope, useLLM: useLLMFlag, hasLLMPlatform: hasLLM });\n if (!hasLLM) {\n ctx.platform?.logger?.warn?.('LLM service not available, falling back to simple changelog', { scope });\n return { markdown: generateSimpleChangelog(packages, 'en'), commitsCount: 0, usedLLM: false };\n }\n return generateWithLLM(ctx, packages, repoRoot, gitCwd, locale, scope);\n}\n\nasync function resolveGitCwd(packages: ChangelogPackageInfo[], repoRoot: string): Promise<string> {\n if (!packages.length || !packages[0]) { return repoRoot; }\n try {\n return await findRepoRoot(packages[0].path);\n } catch {\n return packages[0].path;\n }\n}\n\n// ── handler ────────────────────────────────────────────────────────────────\n\nexport default defineHandler({\n async execute(ctx, input: RestInput<unknown, GenerateChangelogRequest>): Promise<GenerateChangelogResponse> {\n const scope = input.body?.scope || 'root';\n const cwd = ctx.cwd ?? process.cwd();\n const repoRoot = await findRepoRoot(cwd);\n const startTime = Date.now();\n\n ctx.platform?.analytics?.track?.(ANALYTICS_EVENTS.CHANGELOG_STARTED, { scope, actor: ANALYTICS_ACTOR });\n\n const scopeDirName = scopeToDir(scope);\n const planPath = `${repoRoot}/.kb/release/plans/${scopeDirName}/current/plan.json`;\n let plan: ReleasePlan;\n try {\n const planContent = await ctx.runtime.fs.readFile(planPath, 'utf-8');\n plan = JSON.parse(planContent);\n } catch (err) {\n ctx.platform?.logger?.error?.(\n 'Failed to read release plan',\n err instanceof Error ? err : undefined,\n { scope, planPath },\n );\n throw new Error(`Release plan not found for scope \"${scope}\". Generate plan first.`);\n }\n\n const packages: ChangelogPackageInfo[] = plan.packages.map(pkg => ({\n name: pkg.name,\n path: pkg.path,\n currentVersion: pkg.currentVersion,\n nextVersion: pkg.nextVersion,\n bump: pkg.bump === 'auto' ? 'patch' : pkg.bump,\n }));\n\n const gitCwd = await resolveGitCwd(packages, repoRoot);\n\n const localeRaw = input.body?.locale;\n const locale: 'en' | 'ru' = localeRaw === 'ru' ? 'ru' : 'en';\n\n const { markdown, commitsCount, usedLLM } = await resolveMarkdown(\n ctx,\n packages,\n repoRoot,\n gitCwd,\n locale,\n input.body?.useLLM ?? true,\n scope,\n );\n\n const scopeDir = `${repoRoot}/.kb/release/plans/${scopeDirName}/current`;\n await ctx.runtime.fs.mkdir(scopeDir, { recursive: true });\n\n const changelogPath = `${scopeDir}/changelog.md`;\n await ctx.runtime.fs.writeFile(changelogPath, markdown, { encoding: 'utf-8' });\n\n const cacheKey = `${RELEASE_CACHE_PREFIX}changelog:${scope}`;\n await ctx.platform?.cache?.delete(cacheKey);\n\n const duration = Date.now() - startTime;\n const tokensUsed = 0;\n\n ctx.platform?.logger?.info?.('Changelog generated', {\n scope, path: changelogPath, packagesCount: packages.length,\n commitsCount, usedLLM, durationMs: duration,\n });\n\n ctx.platform?.analytics?.track?.(ANALYTICS_EVENTS.CHANGELOG_FINISHED, {\n scope, packagesCount: packages.length, commitsCount,\n durationMs: duration, tokensUsed, usedLLM, actor: ANALYTICS_ACTOR,\n });\n\n return { scope, markdown, changelogPath, tokensUsed, usedLLM, commitsCount };\n }\n});\n"]}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { defineHandler, findRepoRoot } from '@kb-labs/sdk';
|
|
2
2
|
import { RELEASE_CACHE_PREFIX } from '@kb-labs/release-manager-contracts';
|
|
3
|
-
import 'path';
|
|
4
|
-
import 'fs/promises';
|
|
5
|
-
import 'globby';
|
|
6
3
|
|
|
7
4
|
// src/rest/handlers/changelog-handler.ts
|
|
8
5
|
function scopeToDir(scope) {
|
|
@@ -34,7 +31,7 @@ var changelog_handler_default = defineHandler({
|
|
|
34
31
|
if (markdown !== void 0) {
|
|
35
32
|
await ctx.platform?.cache?.set(cacheKey, markdown, CACHE_TTL_MS);
|
|
36
33
|
}
|
|
37
|
-
} catch
|
|
34
|
+
} catch {
|
|
38
35
|
}
|
|
39
36
|
return {
|
|
40
37
|
scope,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/shared/utils.ts","../../../src/rest/handlers/changelog-handler.ts"],"names":["findRepoRoot"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/shared/utils.ts","../../../src/rest/handlers/changelog-handler.ts"],"names":["findRepoRoot"],"mappings":";;;;AAMO,SAAS,WAAW,KAAA,EAAuB;AAChD,EAAA,OAAO,KAAA,CACJ,OAAA,CAAQ,IAAA,EAAM,EAAE,EAChB,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAClB,QAAQ,IAAA,EAAM,GAAG,CAAA,CACjB,OAAA,CAAQ,OAAO,EAAE,CAAA;AACtB;;;ACAA,IAAM,YAAA,GAAe,IAAA;AAErB,IAAO,4BAAQ,aAAA,CAAc;AAAA,EAC3B,MAAM,OAAA,CAAQ,GAAA,EAAK,KAAA,EAA8D;AAC/E,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,EAAO,KAAA,IAAS,MAAA;AACpC,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AACnC,IAAA,MAAM,QAAA,GAAW,MAAMA,YAAAA,CAAa,GAAG,CAAA;AAEvC,IAAA,MAAM,YAAA,GAAe,WAAW,KAAK,CAAA;AACrC,IAAA,MAAM,aAAA,GAAgB,CAAA,EAAG,QAAQ,CAAA,mBAAA,EAAsB,YAAY,CAAA,qBAAA,CAAA;AACnE,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,oBAAoB,CAAA,UAAA,EAAa,KAAK,CAAA,CAAA;AAG1D,IAAA,MAAM,SAAS,MAAM,GAAA,CAAI,QAAA,EAAU,KAAA,EAAO,IAAI,QAAQ,CAAA;AACtD,IAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,KAAW,IAAA,EAAM;AAC3C,MAAA,OAAO;AAAA,QACL,KAAA;AAAA,QACA,QAAA,EAAU,MAAA;AAAA,QACV,IAAA,EAAM,MAAM,KAAA,EAAO,IAAA;AAAA,QACnB,EAAA,EAAI,MAAM,KAAA,EAAO;AAAA,OACnB;AAAA,IACF;AAGA,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAM,GAAA,CAAI,OAAA,CAAQ,EAAA,CAAG,QAAA,CAAS,eAAe,OAAO,CAAA;AAG/D,MAAA,IAAI,aAAa,KAAA,CAAA,EAAW;AAC1B,QAAA,MAAM,IAAI,QAAA,EAAU,KAAA,EAAO,GAAA,CAAI,QAAA,EAAU,UAAU,YAAY,CAAA;AAAA,MACjE;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAEA,IAAA,OAAO;AAAA,MACL,KAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA,EAAM,MAAM,KAAA,EAAO,IAAA;AAAA,MACnB,EAAA,EAAI,MAAM,KAAA,EAAO;AAAA,KACnB;AAAA,EACF;AACF,CAAC","file":"changelog-handler.js","sourcesContent":["export { findRepoRoot } from '@kb-labs/sdk';\nexport { resolveScopePath } from './resolve-scope';\n\n/**\n * Converts scope to safe directory name\n */\nexport function scopeToDir(scope: string): string {\n return scope\n .replace(/^@/, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '-')\n .replace(/\\*/g, '');\n}\n\n/**\n * Converts safe directory name back to scope\n */\nexport function dirToScope(dirName: string): string {\n if (dirName === 'root') {\n return 'root';\n }\n\n const parts = dirName.split('-');\n if (parts.length >= 2) {\n return '@' + parts[0] + '-' + parts[1] + '/' + parts.slice(2).join('-');\n }\n\n return dirName;\n}\n","/**\n * Changelog handler - Get changelog for a scope\n *\n * Reads: .kb/release/plans/{scope}/current/changelog.md\n * Cache: 15s TTL to avoid repeated file reads\n */\n\nimport { defineHandler, findRepoRoot, type RestInput } from '@kb-labs/sdk';\nimport type { ChangelogResponse, ChangelogInput } from '@kb-labs/release-manager-contracts';\nimport { RELEASE_CACHE_PREFIX } from '@kb-labs/release-manager-contracts';\nimport { scopeToDir } from '../../shared/utils';\n\nconst CACHE_TTL_MS = 15000; // 15 seconds\n\nexport default defineHandler({\n async execute(ctx, input: RestInput<ChangelogInput>): Promise<ChangelogResponse> {\n const scope = input.query?.scope || 'root';\n const cwd = ctx.cwd ?? process.cwd();\n const repoRoot = await findRepoRoot(cwd);\n\n const scopeDirName = scopeToDir(scope);\n const changelogPath = `${repoRoot}/.kb/release/plans/${scopeDirName}/current/changelog.md`;\n const cacheKey = `${RELEASE_CACHE_PREFIX}changelog:${scope}`;\n\n // Try cache first\n const cached = await ctx.platform?.cache?.get(cacheKey);\n if (cached !== undefined && cached !== null) {\n return {\n scope,\n markdown: cached as string,\n from: input.query?.from,\n to: input.query?.to,\n };\n }\n\n // Cache miss - read from file\n let markdown: string | undefined;\n try {\n markdown = await ctx.runtime.fs.readFile(changelogPath, 'utf-8');\n\n // Cache the result (only if file exists)\n if (markdown !== undefined) {\n await ctx.platform?.cache?.set(cacheKey, markdown, CACHE_TTL_MS);\n }\n } catch {\n // No changelog found - markdown will be undefined\n }\n\n return {\n scope,\n markdown,\n from: input.query?.from,\n to: input.query?.to,\n };\n }\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/shared/utils.ts","../../../src/rest/handlers/changelog-save-handler.ts"],"names":["findRepoRoot"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/shared/utils.ts","../../../src/rest/handlers/changelog-save-handler.ts"],"names":["findRepoRoot"],"mappings":";;;;AAMO,SAAS,WAAW,KAAA,EAAuB;AAChD,EAAA,OAAO,KAAA,CACJ,OAAA,CAAQ,IAAA,EAAM,EAAE,EAChB,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAClB,QAAQ,IAAA,EAAM,GAAG,CAAA,CACjB,OAAA,CAAQ,OAAO,EAAE,CAAA;AACtB;;;ACEA,IAAO,iCAAQ,aAAA,CAAc;AAAA,EAC3B,MAAM,OAAA,CAAQ,GAAA,EAAK,KAAA,EAAiF;AAClG,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,EAAM,KAAA,IAAS,MAAA;AACnC,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AACnC,IAAA,MAAM,QAAA,GAAW,MAAMA,YAAAA,CAAa,GAAG,CAAA;AAEvC,IAAA,MAAM,YAAA,GAAe,WAAW,KAAK,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,QAAQ,CAAA,mBAAA,EAAsB,YAAY,CAAA,QAAA,CAAA;AAC9D,IAAA,MAAM,aAAA,GAAgB,GAAG,QAAQ,CAAA,aAAA,CAAA;AAEjC,IAAA,IAAI;AAEF,MAAA,MAAM,KAAA,CAAM,QAAA,EAAU,EAAE,SAAA,EAAW,MAAM,CAAA;AAGzC,MAAA,MAAM,GAAA,CAAI,OAAA,CAAQ,EAAA,CAAG,SAAA,CAAU,aAAA,EAAe,KAAA,CAAM,IAAA,EAAM,QAAA,IAAY,EAAA,EAAI,EAAE,QAAA,EAAU,OAAA,EAAS,CAAA;AAE/F,MAAA,GAAA,CAAI,QAAA,EAAU,QAAQ,IAAA,GAAO,iBAAA,EAAmB,EAAE,KAAA,EAAO,IAAA,EAAM,eAAe,CAAA;AAE9E,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,IAAA;AAAA,QACT,KAAA;AAAA,QACA,IAAA,EAAM;AAAA,OACR;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,GAAA,CAAI,UAAU,MAAA,EAAQ,KAAA;AAAA,QACpB,0BAAA;AAAA,QACA,KAAA,YAAiB,QAAQ,KAAA,GAAQ,MAAA;AAAA,QACjC,EAAE,KAAA;AAAM,OACV;AAEA,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IACvG;AAAA,EACF;AACF,CAAC","file":"changelog-save-handler.js","sourcesContent":["export { findRepoRoot } from '@kb-labs/sdk';\nexport { resolveScopePath } from './resolve-scope';\n\n/**\n * Converts scope to safe directory name\n */\nexport function scopeToDir(scope: string): string {\n return scope\n .replace(/^@/, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '-')\n .replace(/\\*/g, '');\n}\n\n/**\n * Converts safe directory name back to scope\n */\nexport function dirToScope(dirName: string): string {\n if (dirName === 'root') {\n return 'root';\n }\n\n const parts = dirName.split('-');\n if (parts.length >= 2) {\n return '@' + parts[0] + '-' + parts[1] + '/' + parts.slice(2).join('-');\n }\n\n return dirName;\n}\n","/**\n * Changelog save handler - Save edited changelog for a scope\n *\n * Writes to: .kb/release/plans/{scope}/current/changelog.md\n */\n\nimport { defineHandler, findRepoRoot, type RestInput } from '@kb-labs/sdk';\nimport type {\n SaveChangelogRequest,\n SaveChangelogResponse,\n} from '@kb-labs/release-manager-contracts';\nimport { mkdir } from 'node:fs/promises';\nimport { scopeToDir } from '../../shared/utils';\n\nexport default defineHandler({\n async execute(ctx, input: RestInput<unknown, SaveChangelogRequest>): Promise<SaveChangelogResponse> {\n const scope = input.body?.scope || 'root';\n const cwd = ctx.cwd ?? process.cwd();\n const repoRoot = await findRepoRoot(cwd);\n\n const scopeDirName = scopeToDir(scope);\n const scopeDir = `${repoRoot}/.kb/release/plans/${scopeDirName}/current`;\n const changelogPath = `${scopeDir}/changelog.md`;\n\n try {\n // Ensure directory exists\n await mkdir(scopeDir, { recursive: true });\n\n // Write changelog\n await ctx.runtime.fs.writeFile(changelogPath, input.body?.markdown || '', { encoding: 'utf-8' });\n\n ctx.platform?.logger?.info?.('Changelog saved', { scope, path: changelogPath });\n\n return {\n success: true,\n scope,\n path: changelogPath,\n };\n } catch (error) {\n ctx.platform?.logger?.error?.(\n 'Failed to save changelog',\n error instanceof Error ? error : undefined,\n { scope }\n );\n\n throw new Error(`Failed to save changelog: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n});\n"]}
|
|
@@ -1,12 +1,120 @@
|
|
|
1
1
|
import { defineHandler, findRepoRoot, useEnv } from '@kb-labs/sdk';
|
|
2
2
|
import { readFile, access, readdir, stat } from 'fs/promises';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import 'globby';
|
|
5
4
|
|
|
6
5
|
// src/rest/handlers/checklist-handler.ts
|
|
7
6
|
function scopeToDir(scope) {
|
|
8
7
|
return scope.replace(/^@/, "").replace(/\//g, "-").replace(/:/g, "-").replace(/\*/g, "");
|
|
9
8
|
}
|
|
9
|
+
async function countFiles(dir) {
|
|
10
|
+
let count = 0;
|
|
11
|
+
let size = 0;
|
|
12
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const fullPath = join(dir, entry.name);
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
const sub = await countFiles(fullPath);
|
|
17
|
+
count += sub.count;
|
|
18
|
+
size += sub.size;
|
|
19
|
+
} else {
|
|
20
|
+
count++;
|
|
21
|
+
const fileStat = await stat(fullPath);
|
|
22
|
+
size += fileStat.size;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { count, size };
|
|
26
|
+
}
|
|
27
|
+
async function checkPlanStatus(basePath) {
|
|
28
|
+
try {
|
|
29
|
+
const planRaw = await readFile(join(basePath, "plan.json"), "utf-8");
|
|
30
|
+
const parsedPlan = JSON.parse(planRaw);
|
|
31
|
+
const packagesCount = parsedPlan.packages.length;
|
|
32
|
+
const bump = parsedPlan.packages[0]?.bump;
|
|
33
|
+
return {
|
|
34
|
+
planStatus: "ready",
|
|
35
|
+
planMessage: `${packagesCount} package${packagesCount !== 1 ? "s" : ""}, ${bump} bump`,
|
|
36
|
+
packagesCount,
|
|
37
|
+
bump,
|
|
38
|
+
plan: parsedPlan
|
|
39
|
+
};
|
|
40
|
+
} catch {
|
|
41
|
+
return { planStatus: "pending", planMessage: "No release plan found", packagesCount: 0, bump: void 0, plan: void 0 };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function checkChangelogStatus(basePath, planStatus) {
|
|
45
|
+
try {
|
|
46
|
+
const changelogPath = join(basePath, "CHANGELOG.md");
|
|
47
|
+
await access(changelogPath);
|
|
48
|
+
const changelog = await readFile(changelogPath, "utf-8");
|
|
49
|
+
const commitMatches = changelog.match(/^- /gm);
|
|
50
|
+
const commitsCount = commitMatches?.length || 0;
|
|
51
|
+
return {
|
|
52
|
+
changelogStatus: "ready",
|
|
53
|
+
changelogMessage: `${commitsCount} change${commitsCount !== 1 ? "s" : ""} documented`,
|
|
54
|
+
commitsCount
|
|
55
|
+
};
|
|
56
|
+
} catch {
|
|
57
|
+
const changelogMessage = planStatus === "ready" ? "Generate changelog to continue" : "Changelog not generated";
|
|
58
|
+
return { changelogStatus: "pending", changelogMessage, commitsCount: void 0 };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function checkBuildStatus(plan, repoRoot) {
|
|
62
|
+
if (!plan) {
|
|
63
|
+
return { buildStatus: "pending", buildMessage: "Build required", builtCount: 0, totalCount: 0 };
|
|
64
|
+
}
|
|
65
|
+
const totalCount = plan.packages.length;
|
|
66
|
+
let builtCount = 0;
|
|
67
|
+
for (const pkg of plan.packages) {
|
|
68
|
+
const packagePath = pkg.path.startsWith("/") ? pkg.path : join(repoRoot, pkg.path);
|
|
69
|
+
try {
|
|
70
|
+
await access(join(packagePath, "dist"));
|
|
71
|
+
builtCount++;
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (builtCount === totalCount) {
|
|
76
|
+
return {
|
|
77
|
+
buildStatus: "ready",
|
|
78
|
+
buildMessage: `All ${totalCount} package${totalCount !== 1 ? "s" : ""} built`,
|
|
79
|
+
builtCount,
|
|
80
|
+
totalCount
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (builtCount > 0) {
|
|
84
|
+
return { buildStatus: "warning", buildMessage: `${builtCount}/${totalCount} packages built`, builtCount, totalCount };
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
buildStatus: "pending",
|
|
88
|
+
buildMessage: `${totalCount} package${totalCount !== 1 ? "s" : ""} need build`,
|
|
89
|
+
builtCount,
|
|
90
|
+
totalCount
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function checkPreviewStatus(plan, repoRoot, buildStatus) {
|
|
94
|
+
if (buildStatus !== "ready" || !plan) {
|
|
95
|
+
return { previewStatus: "pending", previewMessage: "Waiting for build", filesCount: void 0, totalSize: void 0 };
|
|
96
|
+
}
|
|
97
|
+
let filesCount = 0;
|
|
98
|
+
let totalSize = 0;
|
|
99
|
+
for (const pkg of plan.packages) {
|
|
100
|
+
const packagePath = pkg.path.startsWith("/") ? pkg.path : join(repoRoot, pkg.path);
|
|
101
|
+
try {
|
|
102
|
+
const result = await countFiles(join(packagePath, "dist"));
|
|
103
|
+
filesCount += result.count;
|
|
104
|
+
totalSize += result.size;
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (filesCount > 0) {
|
|
109
|
+
return {
|
|
110
|
+
previewStatus: "ready",
|
|
111
|
+
previewMessage: `${filesCount} file${filesCount !== 1 ? "s" : ""} ready to publish`,
|
|
112
|
+
filesCount,
|
|
113
|
+
totalSize
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return { previewStatus: "warning", previewMessage: "No files found to publish", filesCount, totalSize };
|
|
117
|
+
}
|
|
10
118
|
var checklist_handler_default = defineHandler({
|
|
11
119
|
async execute(ctx, input) {
|
|
12
120
|
const scope = input.query?.scope || "root";
|
|
@@ -14,104 +122,10 @@ var checklist_handler_default = defineHandler({
|
|
|
14
122
|
const repoRoot = await findRepoRoot(cwd);
|
|
15
123
|
const scopeDir = scopeToDir(scope);
|
|
16
124
|
const basePath = join(repoRoot, ".kb/release/plans", scopeDir, "current");
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let plan;
|
|
22
|
-
try {
|
|
23
|
-
const planRaw = await readFile(join(basePath, "plan.json"), "utf-8");
|
|
24
|
-
const parsedPlan = JSON.parse(planRaw);
|
|
25
|
-
plan = parsedPlan;
|
|
26
|
-
packagesCount = parsedPlan.packages.length;
|
|
27
|
-
bump = parsedPlan.packages[0]?.bump;
|
|
28
|
-
planStatus = "ready";
|
|
29
|
-
planMessage = `${packagesCount} package${packagesCount !== 1 ? "s" : ""}, ${bump} bump`;
|
|
30
|
-
} catch {
|
|
31
|
-
}
|
|
32
|
-
let changelogStatus = "pending";
|
|
33
|
-
let changelogMessage = "Changelog not generated";
|
|
34
|
-
let commitsCount;
|
|
35
|
-
try {
|
|
36
|
-
const changelogPath = join(basePath, "CHANGELOG.md");
|
|
37
|
-
await access(changelogPath);
|
|
38
|
-
const changelog = await readFile(changelogPath, "utf-8");
|
|
39
|
-
const commitMatches = changelog.match(/^- /gm);
|
|
40
|
-
commitsCount = commitMatches?.length || 0;
|
|
41
|
-
changelogStatus = "ready";
|
|
42
|
-
changelogMessage = `${commitsCount} change${commitsCount !== 1 ? "s" : ""} documented`;
|
|
43
|
-
} catch {
|
|
44
|
-
if (planStatus === "ready") {
|
|
45
|
-
changelogMessage = "Generate changelog to continue";
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
let buildStatus = "pending";
|
|
49
|
-
let buildMessage = "Build required";
|
|
50
|
-
let builtCount = 0;
|
|
51
|
-
let totalCount = 0;
|
|
52
|
-
if (plan) {
|
|
53
|
-
totalCount = plan.packages.length;
|
|
54
|
-
for (const pkg of plan.packages) {
|
|
55
|
-
const packagePath = pkg.path.startsWith("/") ? pkg.path : join(repoRoot, pkg.path);
|
|
56
|
-
try {
|
|
57
|
-
await access(join(packagePath, "dist"));
|
|
58
|
-
builtCount++;
|
|
59
|
-
} catch {
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (builtCount === totalCount) {
|
|
63
|
-
buildStatus = "ready";
|
|
64
|
-
buildMessage = `All ${totalCount} package${totalCount !== 1 ? "s" : ""} built`;
|
|
65
|
-
} else if (builtCount > 0) {
|
|
66
|
-
buildStatus = "warning";
|
|
67
|
-
buildMessage = `${builtCount}/${totalCount} packages built`;
|
|
68
|
-
} else {
|
|
69
|
-
buildMessage = `${totalCount} package${totalCount !== 1 ? "s" : ""} need build`;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
let previewStatus = "pending";
|
|
73
|
-
let previewMessage = "Waiting for build";
|
|
74
|
-
let filesCount;
|
|
75
|
-
let totalSize;
|
|
76
|
-
if (buildStatus === "ready" && plan) {
|
|
77
|
-
filesCount = 0;
|
|
78
|
-
totalSize = 0;
|
|
79
|
-
for (const pkg of plan.packages) {
|
|
80
|
-
const packagePath = pkg.path.startsWith("/") ? pkg.path : join(repoRoot, pkg.path);
|
|
81
|
-
try {
|
|
82
|
-
const distPath = join(packagePath, "dist");
|
|
83
|
-
const countFiles = async (dir) => {
|
|
84
|
-
let count = 0;
|
|
85
|
-
let size = 0;
|
|
86
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
87
|
-
for (const entry of entries) {
|
|
88
|
-
const fullPath = join(dir, entry.name);
|
|
89
|
-
if (entry.isDirectory()) {
|
|
90
|
-
const sub = await countFiles(fullPath);
|
|
91
|
-
count += sub.count;
|
|
92
|
-
size += sub.size;
|
|
93
|
-
} else {
|
|
94
|
-
count++;
|
|
95
|
-
const fileStat = await stat(fullPath);
|
|
96
|
-
size += fileStat.size;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return { count, size };
|
|
100
|
-
};
|
|
101
|
-
const result = await countFiles(distPath);
|
|
102
|
-
filesCount += result.count;
|
|
103
|
-
totalSize += result.size;
|
|
104
|
-
} catch {
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (filesCount > 0) {
|
|
108
|
-
previewStatus = "ready";
|
|
109
|
-
previewMessage = `${filesCount} file${filesCount !== 1 ? "s" : ""} ready to publish`;
|
|
110
|
-
} else {
|
|
111
|
-
previewStatus = "warning";
|
|
112
|
-
previewMessage = "No files found to publish";
|
|
113
|
-
}
|
|
114
|
-
}
|
|
125
|
+
const { planStatus, planMessage, packagesCount, bump, plan } = await checkPlanStatus(basePath);
|
|
126
|
+
const { changelogStatus, changelogMessage, commitsCount } = await checkChangelogStatus(basePath, planStatus);
|
|
127
|
+
const { buildStatus, buildMessage, builtCount, totalCount } = await checkBuildStatus(plan, repoRoot);
|
|
128
|
+
const { previewStatus, previewMessage, filesCount, totalSize } = await checkPreviewStatus(plan, repoRoot, buildStatus);
|
|
115
129
|
const hasNpmToken = !!(useEnv("NPM_TOKEN") ?? useEnv("NODE_AUTH_TOKEN"));
|
|
116
130
|
const npmStatus = hasNpmToken ? "ready" : "error";
|
|
117
131
|
const npmMessage = hasNpmToken ? "npm token configured" : "Set NPM_TOKEN (granular access token) in environment";
|