@kb-labs/commit-entry 2.89.0 → 2.94.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/rest/handlers/files-handler.js +4 -6
- package/dist/rest/handlers/files-handler.js.map +1 -1
- package/dist/rest/handlers/status-handler.js.map +1 -1
- package/dist/widgets/mf-manifest.json +5 -5
- package/dist/widgets/mf-stats.json +5 -5
- package/dist/widgets/remoteEntry.js +2 -2
- package/dist/widgets/remoteEntry.js.map +1 -1
- package/package.json +5 -5
|
@@ -2,7 +2,7 @@ import { defineHandler, useConfig } from '@kb-labs/sdk';
|
|
|
2
2
|
import { getGitStatus } from '@kb-labs/commit-core/analyzer';
|
|
3
3
|
import { COMMIT_CACHE_PREFIX, resolveCommitConfig } from '@kb-labs/commit-contracts';
|
|
4
4
|
import * as path from 'path';
|
|
5
|
-
import {
|
|
5
|
+
import { execFile } from 'child_process';
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
|
|
8
8
|
// src/rest/handlers/files-handler.ts
|
|
@@ -11,7 +11,7 @@ function resolveScopePath(baseCwd, scopeId = "root", scopes) {
|
|
|
11
11
|
const relativePath = scopeDef?.path ?? (scopeId === "root" ? "." : scopeId);
|
|
12
12
|
return relativePath === "." ? baseCwd : path.join(baseCwd, relativePath);
|
|
13
13
|
}
|
|
14
|
-
var
|
|
14
|
+
var execFileAsync = promisify(execFile);
|
|
15
15
|
var FILES_CACHE_TTL = 5e3;
|
|
16
16
|
var files_handler_default = defineHandler({
|
|
17
17
|
async execute(ctx, input) {
|
|
@@ -92,9 +92,8 @@ async function getDiffStats(cwd, files) {
|
|
|
92
92
|
const batchSize = 100;
|
|
93
93
|
for (let i = 0; i < files.length; i += batchSize) {
|
|
94
94
|
const batch = files.slice(i, i + batchSize);
|
|
95
|
-
const escapedFiles = batch.map((f) => `"${f.replace(/"/g, '\\"')}"`).join(" ");
|
|
96
95
|
try {
|
|
97
|
-
const { stdout } = await
|
|
96
|
+
const { stdout } = await execFileAsync("git", ["diff", "--numstat", "HEAD", "--", ...batch], { cwd });
|
|
98
97
|
const lines = stdout.trim().split("\n");
|
|
99
98
|
for (const line of lines) {
|
|
100
99
|
if (!line) {
|
|
@@ -120,8 +119,7 @@ async function getDiffStats(cwd, files) {
|
|
|
120
119
|
for (const file of files) {
|
|
121
120
|
if (!stats.has(file)) {
|
|
122
121
|
try {
|
|
123
|
-
const
|
|
124
|
-
const { stdout: content } = await execAsync(`wc -l "${safeFile}"`, { cwd });
|
|
122
|
+
const { stdout: content } = await execFileAsync("wc", ["-l", file], { cwd });
|
|
125
123
|
const match = content.trim().match(/^\s*(\d+)/);
|
|
126
124
|
const lines = match && match[1] ? parseInt(match[1], 10) : 0;
|
|
127
125
|
stats.set(file, { additions: lines, deletions: 0 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/rest/handlers/scope-resolver.ts","../../../src/rest/handlers/files-handler.ts"],"names":["path"],"mappings":"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","file":"files-handler.js","sourcesContent":["import * as path from 'node:path';\nimport type { CommitScope } from '@kb-labs/commit-contracts';\n\n/**\n * Resolves a scope id to an absolute filesystem path.\n *\n * Looks up the scope in the provided scopes array by id.\n * Falls back to treating the id as a relative path from baseCwd (legacy compat).\n *\n * @param baseCwd - Workspace root (ctx.cwd)\n * @param scopeId - Scope identifier, e.g. \"root\", \"public/kb-labs\"\n * @param scopes - Configured scopes from CommitPluginConfig.scope.scopes\n */\nexport function resolveScopePath(\n baseCwd: string,\n scopeId: string = 'root',\n scopes?: CommitScope[],\n): string {\n const scopeDef = scopes?.find((s) => s.id === scopeId);\n const relativePath = scopeDef?.path ?? (scopeId === 'root' ? '.' : scopeId);\n return relativePath === '.' ? baseCwd : path.join(baseCwd, relativePath);\n}\n","import { defineHandler, useConfig, type RestInput, type PluginContextV3, type TableData, type TableRow } from '@kb-labs/sdk';\nimport { getGitStatus } from '@kb-labs/commit-core/analyzer';\nimport { COMMIT_CACHE_PREFIX, type CommitPluginConfig, resolveCommitConfig } from '@kb-labs/commit-contracts';\nimport { resolveScopePath } from './scope-resolver';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\nconst FILES_CACHE_TTL = 5000; // 5 seconds (same as status-handler)\n\n/**\n * File row for table display (GitHub/GitLab style)\n */\ninterface FileRow extends TableRow {\n path: string;\n filename: string;\n status: 'modified' | 'added' | 'deleted';\n additions: number;\n deletions: number;\n changes: string; // \"+45 -12\" formatted string\n}\n\n/**\n * GET /files handler\n *\n * Returns flat file list with diff statistics (GitHub/GitLab style).\n * Uses TableData format from studio-contracts.\n *\n * Response format: TableData with rows array\n */\nexport default defineHandler({\n async execute(ctx: PluginContextV3, input: RestInput<{ scope?: string }>): Promise<TableData> {\n const scope = input.query?.scope || 'root';\n\n // Check cache first\n const cacheKey = `${COMMIT_CACHE_PREFIX}files-list:${scope}`;\n const cached = await ctx.platform.cache.get(cacheKey);\n\n if (cached !== null && cached !== undefined) {\n return cached as TableData;\n }\n\n try {\n // Resolve scope to actual directory path\n const fileConfig = await useConfig<Partial<CommitPluginConfig>>();\n const config = resolveCommitConfig(fileConfig ?? {});\n const scopeCwd = resolveScopePath(ctx.cwd, scope, config.scope?.scopes);\n\n // Get git status (git runs FROM scopeCwd, no filtering)\n const gitStatus = await getGitStatus(scopeCwd);\n\n // Get diff stats for each file\n const allFiles = [\n ...gitStatus.staged,\n ...gitStatus.unstaged,\n ...gitStatus.untracked,\n ];\n\n const diffStats = await getDiffStats(scopeCwd, allFiles);\n\n // Build flat file list\n const rows: FileRow[] = [];\n\n // Process staged files\n for (const file of gitStatus.staged) {\n const stats = diffStats.get(file) ?? { additions: 0, deletions: 0 };\n const filename = file.split('/').pop() || file;\n\n rows.push({\n path: file,\n filename,\n status: stats.deletions > 0 && stats.additions === 0 ? 'deleted' : 'modified',\n additions: stats.additions,\n deletions: stats.deletions,\n changes: `+${stats.additions} -${stats.deletions}`,\n });\n }\n\n // Process unstaged files\n for (const file of gitStatus.unstaged) {\n if (!rows.find(r => r.path === file)) {\n const stats = diffStats.get(file) ?? { additions: 0, deletions: 0 };\n const filename = file.split('/').pop() || file;\n\n rows.push({\n path: file,\n filename,\n status: 'modified',\n additions: stats.additions,\n deletions: stats.deletions,\n changes: `+${stats.additions} -${stats.deletions}`,\n });\n }\n }\n\n // Process untracked files\n for (const file of gitStatus.untracked) {\n const stats = diffStats.get(file) ?? { additions: 0, deletions: 0 };\n const filename = file.split('/').pop() || file;\n\n rows.push({\n path: file,\n filename,\n status: 'added',\n additions: stats.additions,\n deletions: stats.deletions,\n changes: `+${stats.additions}`,\n });\n }\n\n // Sort by path\n rows.sort((a, b) => a.path.localeCompare(b.path));\n\n // Return TableData\n const result: TableData = {\n rows,\n total: rows.length,\n };\n\n // Store in cache with TTL\n await ctx.platform.cache.set(cacheKey, result, FILES_CACHE_TTL);\n\n return result;\n } catch (error) {\n // Return empty table on error\n return { rows: [], total: 0 };\n }\n },\n});\n\n/**\n * Get diff statistics for specific files only\n * Uses git diff --numstat with specific file paths to avoid timeout\n */\nasync function getDiffStats(\n cwd: string,\n files: string[]\n): Promise<Map<string, { additions: number; deletions: number }>> {\n const stats = new Map<string, { additions: number; deletions: number }>();\n\n if (files.length === 0) {\n return stats;\n }\n\n try {\n // Process files in batches to avoid \"argument list too long\"\n const batchSize = 100;\n for (let i = 0; i < files.length; i += batchSize) {\n const batch = files.slice(i, i + batchSize);\n\n // Escape file paths for shell\n const escapedFiles = batch.map(f => `\"${f.replace(/\"/g, '\\\\\"')}\"`).join(' ');\n\n // Run git diff --numstat only for these specific files\n try {\n const { stdout } = await execAsync(`git diff --numstat HEAD -- ${escapedFiles}`, { cwd });\n\n const lines = stdout.trim().split('\\n');\n for (const line of lines) {\n if (!line) {continue;}\n\n const parts = line.split('\\t');\n if (parts.length < 3 || !parts[2]) {continue;}\n\n const additions = parseInt(parts[0] || '0', 10);\n const deletions = parseInt(parts[1] || '0', 10);\n const path = parts[2];\n\n stats.set(path, { additions, deletions });\n }\n } catch {\n // If batch fails, mark files as zero\n for (const file of batch) {\n if (!stats.has(file)) {\n stats.set(file, { additions: 0, deletions: 0 });\n }\n }\n }\n }\n\n // For untracked files (not in git diff output), count lines\n for (const file of files) {\n if (!stats.has(file)) {\n try {\n const safeFile = file.replace(/\"/g, '\\\\\"');\n const { stdout: content } = await execAsync(`wc -l \"${safeFile}\"`, { cwd });\n const match = content.trim().match(/^\\s*(\\d+)/);\n const lines = match && match[1] ? parseInt(match[1], 10) : 0;\n stats.set(file, { additions: lines, deletions: 0 });\n } catch {\n stats.set(file, { additions: 0, deletions: 0 });\n }\n }\n }\n } catch {\n // If all fails, return zeros\n for (const file of files) {\n stats.set(file, { additions: 0, deletions: 0 });\n }\n }\n\n return stats;\n}\n\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/rest/handlers/scope-resolver.ts","../../../src/rest/handlers/files-handler.ts"],"names":["path"],"mappings":"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","file":"files-handler.js","sourcesContent":["import * as path from 'node:path';\nimport type { CommitScope } from '@kb-labs/commit-contracts';\n\n/**\n * Resolves a scope id to an absolute filesystem path.\n *\n * Looks up the scope in the provided scopes array by id.\n * Falls back to treating the id as a relative path from baseCwd (legacy compat).\n *\n * @param baseCwd - Workspace root (ctx.cwd)\n * @param scopeId - Scope identifier, e.g. \"root\", \"public/kb-labs\"\n * @param scopes - Configured scopes from CommitPluginConfig.scope.scopes\n */\nexport function resolveScopePath(\n baseCwd: string,\n scopeId: string = 'root',\n scopes?: CommitScope[],\n): string {\n const scopeDef = scopes?.find((s) => s.id === scopeId);\n const relativePath = scopeDef?.path ?? (scopeId === 'root' ? '.' : scopeId);\n return relativePath === '.' ? baseCwd : path.join(baseCwd, relativePath);\n}\n","import { defineHandler, useConfig, type RestInput, type PluginContextV3, type TableData, type TableRow } from '@kb-labs/sdk';\nimport { getGitStatus } from '@kb-labs/commit-core/analyzer';\nimport { COMMIT_CACHE_PREFIX, type CommitPluginConfig, resolveCommitConfig } from '@kb-labs/commit-contracts';\nimport { resolveScopePath } from './scope-resolver';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nconst FILES_CACHE_TTL = 5000; // 5 seconds (same as status-handler)\n\n/**\n * File row for table display (GitHub/GitLab style)\n */\ninterface FileRow extends TableRow {\n path: string;\n filename: string;\n status: 'modified' | 'added' | 'deleted';\n additions: number;\n deletions: number;\n changes: string; // \"+45 -12\" formatted string\n}\n\n/**\n * GET /files handler\n *\n * Returns flat file list with diff statistics (GitHub/GitLab style).\n * Uses TableData format from studio-contracts.\n *\n * Response format: TableData with rows array\n */\nexport default defineHandler({\n async execute(ctx: PluginContextV3, input: RestInput<{ scope?: string }>): Promise<TableData> {\n const scope = input.query?.scope || 'root';\n\n // Check cache first\n const cacheKey = `${COMMIT_CACHE_PREFIX}files-list:${scope}`;\n const cached = await ctx.platform.cache.get(cacheKey);\n\n if (cached !== null && cached !== undefined) {\n return cached as TableData;\n }\n\n try {\n // Resolve scope to actual directory path\n const fileConfig = await useConfig<Partial<CommitPluginConfig>>();\n const config = resolveCommitConfig(fileConfig ?? {});\n const scopeCwd = resolveScopePath(ctx.cwd, scope, config.scope?.scopes);\n\n // Get git status (git runs FROM scopeCwd, no filtering)\n const gitStatus = await getGitStatus(scopeCwd);\n\n // Get diff stats for each file\n const allFiles = [\n ...gitStatus.staged,\n ...gitStatus.unstaged,\n ...gitStatus.untracked,\n ];\n\n const diffStats = await getDiffStats(scopeCwd, allFiles);\n\n // Build flat file list\n const rows: FileRow[] = [];\n\n // Process staged files\n for (const file of gitStatus.staged) {\n const stats = diffStats.get(file) ?? { additions: 0, deletions: 0 };\n const filename = file.split('/').pop() || file;\n\n rows.push({\n path: file,\n filename,\n status: stats.deletions > 0 && stats.additions === 0 ? 'deleted' : 'modified',\n additions: stats.additions,\n deletions: stats.deletions,\n changes: `+${stats.additions} -${stats.deletions}`,\n });\n }\n\n // Process unstaged files\n for (const file of gitStatus.unstaged) {\n if (!rows.find(r => r.path === file)) {\n const stats = diffStats.get(file) ?? { additions: 0, deletions: 0 };\n const filename = file.split('/').pop() || file;\n\n rows.push({\n path: file,\n filename,\n status: 'modified',\n additions: stats.additions,\n deletions: stats.deletions,\n changes: `+${stats.additions} -${stats.deletions}`,\n });\n }\n }\n\n // Process untracked files\n for (const file of gitStatus.untracked) {\n const stats = diffStats.get(file) ?? { additions: 0, deletions: 0 };\n const filename = file.split('/').pop() || file;\n\n rows.push({\n path: file,\n filename,\n status: 'added',\n additions: stats.additions,\n deletions: stats.deletions,\n changes: `+${stats.additions}`,\n });\n }\n\n // Sort by path\n rows.sort((a, b) => a.path.localeCompare(b.path));\n\n // Return TableData\n const result: TableData = {\n rows,\n total: rows.length,\n };\n\n // Store in cache with TTL\n await ctx.platform.cache.set(cacheKey, result, FILES_CACHE_TTL);\n\n return result;\n } catch (error) {\n // Return empty table on error\n return { rows: [], total: 0 };\n }\n },\n});\n\n/**\n * Get diff statistics for specific files only\n * Uses git diff --numstat with specific file paths to avoid timeout\n */\nasync function getDiffStats(\n cwd: string,\n files: string[]\n): Promise<Map<string, { additions: number; deletions: number }>> {\n const stats = new Map<string, { additions: number; deletions: number }>();\n\n if (files.length === 0) {\n return stats;\n }\n\n try {\n // Process files in batches to avoid \"argument list too long\"\n const batchSize = 100;\n for (let i = 0; i < files.length; i += batchSize) {\n const batch = files.slice(i, i + batchSize);\n\n // Run git diff --numstat only for these specific files\n try {\n const { stdout } = await execFileAsync('git', ['diff', '--numstat', 'HEAD', '--', ...batch], { cwd });\n\n const lines = stdout.trim().split('\\n');\n for (const line of lines) {\n if (!line) {continue;}\n\n const parts = line.split('\\t');\n if (parts.length < 3 || !parts[2]) {continue;}\n\n const additions = parseInt(parts[0] || '0', 10);\n const deletions = parseInt(parts[1] || '0', 10);\n const path = parts[2];\n\n stats.set(path, { additions, deletions });\n }\n } catch {\n // If batch fails, mark files as zero\n for (const file of batch) {\n if (!stats.has(file)) {\n stats.set(file, { additions: 0, deletions: 0 });\n }\n }\n }\n }\n\n // For untracked files (not in git diff output), count lines\n for (const file of files) {\n if (!stats.has(file)) {\n try {\n const { stdout: content } = await execFileAsync('wc', ['-l', file], { cwd });\n const match = content.trim().match(/^\\s*(\\d+)/);\n const lines = match && match[1] ? parseInt(match[1], 10) : 0;\n stats.set(file, { additions: lines, deletions: 0 });\n } catch {\n stats.set(file, { additions: 0, deletions: 0 });\n }\n }\n }\n } catch {\n // If all fails, return zeros\n for (const file of files) {\n stats.set(file, { additions: 0, deletions: 0 });\n }\n }\n\n return stats;\n}\n\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/rest/handlers/scope-resolver.ts","../../../src/rest/handlers/status-handler.ts"],"names":[],"mappings":";;;;;;;AAaO,SAAS,gBAAA,CACd,OAAA,EACA,OAAA,GAAkB,MAAA,EAClB,MAAA,EACQ;AACR,EAAA,MAAM,WAAW,MAAA,EAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AACrD,EAAA,MAAM,YAAA,GAAe,QAAA,EAAU,IAAA,KAAS,OAAA,KAAY,SAAS,GAAA,GAAM,OAAA,CAAA;AACnE,EAAA,OAAO,YAAA,KAAiB,GAAA,GAAM,OAAA,GAAe,IAAA,CAAA,IAAA,CAAK,SAAS,YAAY,CAAA;AACzE;;;ACfA,IAAM,gBAAA,GAAmB,GAAA;AAQzB,IAAO,yBAAQ,aAAA,CAAc;AAAA,EAC3B,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA+D;AACjG,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,EAAO,KAAA,IAAS,MAAA;AAEpC,IAAA,GAAA,CAAI,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,CAAA,4CAAA,EAA+C,KAAK,CAAA,CAAE,CAAA;AAE/E,IAAA,IAAI;AAEF,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,GAAA,CAAI,KAAK,KAAK,CAAA;AAC1C,MAAA,GAAA,CAAI,SAAS,MAAA,CAAO,IAAA,CAAK,iCAAiC,CAAC,CAAC,IAAI,CAAA,CAAE,CAAA;AAGlE,MAAA,IAAI,YAAA,GAAe,CAAA;AACnB,MAAA,IAAI,SAAA,
|
|
1
|
+
{"version":3,"sources":["../../../src/rest/handlers/scope-resolver.ts","../../../src/rest/handlers/status-handler.ts"],"names":[],"mappings":"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","file":"status-handler.js","sourcesContent":["import * as path from 'node:path';\nimport type { CommitScope } from '@kb-labs/commit-contracts';\n\n/**\n * Resolves a scope id to an absolute filesystem path.\n *\n * Looks up the scope in the provided scopes array by id.\n * Falls back to treating the id as a relative path from baseCwd (legacy compat).\n *\n * @param baseCwd - Workspace root (ctx.cwd)\n * @param scopeId - Scope identifier, e.g. \"root\", \"public/kb-labs\"\n * @param scopes - Configured scopes from CommitPluginConfig.scope.scopes\n */\nexport function resolveScopePath(\n baseCwd: string,\n scopeId: string = 'root',\n scopes?: CommitScope[],\n): string {\n const scopeDef = scopes?.find((s) => s.id === scopeId);\n const relativePath = scopeDef?.path ?? (scopeId === 'root' ? '.' : scopeId);\n return relativePath === '.' ? baseCwd : path.join(baseCwd, relativePath);\n}\n","import { defineHandler, useConfig, type RestInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { loadPlan } from '@kb-labs/commit-core/storage';\nimport { getGitStatus } from '@kb-labs/commit-core/analyzer';\nimport { COMMIT_CACHE_PREFIX, type StatusResponse, type PlanStatus, type CommitPluginConfig, resolveCommitConfig } from '@kb-labs/commit-contracts';\nimport { resolveScopePath } from './scope-resolver';\n\nconst STATUS_CACHE_TTL = 5000; // 5 seconds\n\n/**\n * GET /status handler\n *\n * Returns current status for a scope according to StatusResponse contract.\n * Uses ctx.platform.cache for git status caching.\n */\nexport default defineHandler({\n async execute(ctx: PluginContextV3, input: RestInput<{ scope?: string }>): Promise<StatusResponse> {\n const scope = input.query?.scope || 'root';\n\n ctx.platform.logger.info(`[status-handler] Fetching status for scope: ${scope}`);\n\n try {\n // Load current plan\n const plan = await loadPlan(ctx.cwd, scope);\n ctx.platform.logger.info(`[status-handler] Plan loaded: ${!!plan}`);\n\n // Get git status (with platform cache)\n let filesChanged = 0;\n let gitStatus: { staged: string[]; unstaged: string[]; untracked: string[] } | null = null;\n const cacheKey = `${COMMIT_CACHE_PREFIX}git-status:${scope}`;\n ctx.platform.logger.info(`[status-handler] Cache key: ${cacheKey}`);\n\n // Try to get from cache\n const cached = await ctx.platform.cache.get(cacheKey);\n ctx.platform.logger.info(`[status-handler] Cache hit: ${!!cached}`);\n\n if (cached !== null && cached !== undefined) {\n // Use cached value\n const cachedData = cached as { count: number; status: { staged: string[]; unstaged: string[]; untracked: string[] } | null };\n filesChanged = cachedData.count;\n gitStatus = cachedData.status;\n } else {\n // Fetch fresh git status\n // Resolve scope to actual directory path (same as files-handler)\n const fileConfig = await useConfig<Partial<CommitPluginConfig>>();\n const config = resolveCommitConfig(fileConfig ?? {});\n const scopeCwd = resolveScopePath(ctx.cwd, scope, config.scope?.scopes);\n ctx.platform.logger.info(`[status-handler] Resolved scope CWD: ${scopeCwd}`);\n\n gitStatus = await getGitStatus(scopeCwd);\n ctx.platform.logger.info(`[status-handler] Git status fetched - staged: ${gitStatus.staged.length}, unstaged: ${gitStatus.unstaged.length}, untracked: ${gitStatus.untracked.length}`);\n\n filesChanged =\n gitStatus.staged.length +\n gitStatus.unstaged.length +\n gitStatus.untracked.length;\n\n ctx.platform.logger.info(`[status-handler] Total files changed: ${filesChanged}`);\n\n // Cache the result\n await ctx.platform.cache.set(\n cacheKey,\n { count: filesChanged, status: gitStatus },\n STATUS_CACHE_TTL\n );\n }\n\n // Determine plan status\n let planStatus: PlanStatus = 'idle';\n let commitsApplied = 0;\n\n if (plan) {\n // Check if commits were applied (stored in cache after apply)\n const appliedCacheKey = `${COMMIT_CACHE_PREFIX}plan-applied:${scope}`;\n const appliedData = await ctx.platform.cache.get(appliedCacheKey);\n\n if (appliedData) {\n const applied = appliedData as { commitsApplied: number; planCreatedAt?: string };\n // Only trust applied marker if it belongs to the current plan version.\n if (!applied.planCreatedAt || applied.planCreatedAt === plan.createdAt) {\n commitsApplied = applied.commitsApplied;\n planStatus = 'applied';\n } else {\n await ctx.platform.cache.delete(appliedCacheKey);\n planStatus = 'ready';\n }\n } else {\n planStatus = 'ready';\n }\n }\n\n return {\n scope,\n hasPlan: !!plan,\n planStatus,\n filesChanged,\n commitsInPlan: plan?.commits.length || 0,\n commitsApplied,\n planTimestamp: plan?.createdAt,\n gitStatus: gitStatus || undefined,\n };\n } catch (error) {\n return {\n scope,\n hasPlan: false,\n planStatus: 'idle',\n filesChanged: 0,\n commitsInPlan: 0,\n commitsApplied: 0,\n };\n }\n },\n});\n"]}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "commitPlugin",
|
|
6
6
|
"globalName": "commitPlugin",
|
|
7
7
|
"buildInfo": {
|
|
8
|
-
"buildVersion": "2.
|
|
8
|
+
"buildVersion": "2.93.0",
|
|
9
9
|
"buildName": "@kb-labs/commit-entry"
|
|
10
10
|
},
|
|
11
11
|
"publicPath": "auto",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
{
|
|
28
28
|
"id": "commitPlugin:@kb-labs/studio-event-bus",
|
|
29
29
|
"name": "@kb-labs/studio-event-bus",
|
|
30
|
-
"version": "2.
|
|
30
|
+
"version": "2.93.0",
|
|
31
31
|
"singleton": true,
|
|
32
32
|
"requiredVersion": "^0.1.0",
|
|
33
33
|
"assets": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
{
|
|
48
48
|
"id": "commitPlugin:@kb-labs/studio-ui-core",
|
|
49
49
|
"name": "@kb-labs/studio-ui-core",
|
|
50
|
-
"version": "2.
|
|
50
|
+
"version": "2.93.0",
|
|
51
51
|
"singleton": true,
|
|
52
52
|
"requiredVersion": "^0.1.0",
|
|
53
53
|
"assets": {
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
{
|
|
87
87
|
"id": "commitPlugin:@kb-labs/studio-hooks",
|
|
88
88
|
"name": "@kb-labs/studio-hooks",
|
|
89
|
-
"version": "2.
|
|
89
|
+
"version": "2.93.0",
|
|
90
90
|
"singleton": true,
|
|
91
91
|
"requiredVersion": "^0.1.0",
|
|
92
92
|
"assets": {
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
{
|
|
107
107
|
"id": "commitPlugin:@kb-labs/studio-ui-kit",
|
|
108
108
|
"name": "@kb-labs/studio-ui-kit",
|
|
109
|
-
"version": "2.
|
|
109
|
+
"version": "2.93.0",
|
|
110
110
|
"singleton": true,
|
|
111
111
|
"requiredVersion": "^0.1.0",
|
|
112
112
|
"assets": {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "commitPlugin",
|
|
6
6
|
"globalName": "commitPlugin",
|
|
7
7
|
"buildInfo": {
|
|
8
|
-
"buildVersion": "2.
|
|
8
|
+
"buildVersion": "2.93.0",
|
|
9
9
|
"buildName": "@kb-labs/commit-entry"
|
|
10
10
|
},
|
|
11
11
|
"publicPath": "auto",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
{
|
|
28
28
|
"id": "commitPlugin:@kb-labs/studio-event-bus",
|
|
29
29
|
"name": "@kb-labs/studio-event-bus",
|
|
30
|
-
"version": "2.
|
|
30
|
+
"version": "2.93.0",
|
|
31
31
|
"requiredVersion": "^0.1.0",
|
|
32
32
|
"singleton": true,
|
|
33
33
|
"assets": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
{
|
|
49
49
|
"id": "commitPlugin:@kb-labs/studio-ui-core",
|
|
50
50
|
"name": "@kb-labs/studio-ui-core",
|
|
51
|
-
"version": "2.
|
|
51
|
+
"version": "2.93.0",
|
|
52
52
|
"requiredVersion": "^0.1.0",
|
|
53
53
|
"singleton": true,
|
|
54
54
|
"assets": {
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
{
|
|
90
90
|
"id": "commitPlugin:@kb-labs/studio-hooks",
|
|
91
91
|
"name": "@kb-labs/studio-hooks",
|
|
92
|
-
"version": "2.
|
|
92
|
+
"version": "2.93.0",
|
|
93
93
|
"requiredVersion": "^0.1.0",
|
|
94
94
|
"singleton": true,
|
|
95
95
|
"assets": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
{
|
|
111
111
|
"id": "commitPlugin:@kb-labs/studio-ui-kit",
|
|
112
112
|
"name": "@kb-labs/studio-ui-kit",
|
|
113
|
-
"version": "2.
|
|
113
|
+
"version": "2.93.0",
|
|
114
114
|
"requiredVersion": "^0.1.0",
|
|
115
115
|
"singleton": true,
|
|
116
116
|
"assets": {
|