@kb-labs/policy-core 0.5.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/README.md +120 -0
- package/dist/cli/commands/check.d.ts +9 -0
- package/dist/cli/commands/check.js +646 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/detect.d.ts +9 -0
- package/dist/cli/commands/detect.js +103 -0
- package/dist/cli/commands/detect.js.map +1 -0
- package/dist/cli/commands/rules.d.ts +8 -0
- package/dist/cli/commands/rules.js +49 -0
- package/dist/cli/commands/rules.js.map +1 -0
- package/dist/cli/commands/snapshot.d.ts +8 -0
- package/dist/cli/commands/snapshot.js +167 -0
- package/dist/cli/commands/snapshot.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +652 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.v3.d.ts +53 -0
- package/dist/manifest.v3.js +111 -0
- package/dist/manifest.v3.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/core/category-resolver.ts","../../../src/cli/commands/check.ts","../../../src/core/workspace-scanner.ts","../../../src/checks/sdk-only-deps.ts","../../../src/checks/boundary-check.ts","../../../src/checks/symbol-extractor.ts","../../../src/checks/api-compat-check.ts","../../../src/checks/no-rollback.ts","../../../src/core/policy-runner.ts"],"names":["path","fs","detectCategory","findPackageJsonPaths","passed"],"mappings":"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","file":"check.js","sourcesContent":["import type { CategoryResult, PolicyConfig } from '@kb-labs/policy-contracts';\n\n/**\n * Checks if a repo path matches a glob-like category path pattern.\n * Supports simple wildcards: \"plugins/*\" matches \"plugins/kb-labs-mind\".\n */\nfunction matchesPattern(repoPath: string, pattern: string): boolean {\n // Normalize trailing slashes\n const normalizedPath = repoPath.replace(/\\/$/, '');\n const normalizedPattern = pattern.replace(/\\/$/, '');\n\n if (normalizedPattern === normalizedPath) {return true;}\n\n // Handle wildcard: \"plugins/*\" → matches \"plugins/anything\"\n if (normalizedPattern.endsWith('/*')) {\n const prefix = normalizedPattern.slice(0, -2); // remove /*\n const pathPrefix = normalizedPath.split('/').slice(0, prefix.split('/').length).join('/');\n return pathPrefix === prefix;\n }\n\n // Exact prefix match with single segment after\n if (normalizedPattern.includes('*')) {\n const regexStr = normalizedPattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '[^/]+');\n return new RegExp(`^${regexStr}$`).test(normalizedPath);\n }\n\n return false;\n}\n\n/**\n * Detects the category for a given repo path based on the policies config.\n * Returns first matching category. If no match, returns category: null.\n */\nexport function detectCategory(repoPath: string, config: PolicyConfig): CategoryResult {\n for (const [categoryName, categoryConfig] of Object.entries(config.categories)) {\n for (const pattern of categoryConfig.paths) {\n if (matchesPattern(repoPath, pattern)) {\n return {\n path: repoPath,\n category: categoryName,\n rules: categoryConfig.rules,\n };\n }\n }\n }\n\n return {\n path: repoPath,\n category: null,\n rules: ['boundary-check'], // default fallback rule\n };\n}\n\n/**\n * Detects categories for multiple repo paths.\n */\nexport function detectCategories(repoPaths: string[], config: PolicyConfig): CategoryResult[] {\n return repoPaths.map((p) => detectCategory(p, config));\n}\n","import { defineCommand, useConfig, findRepoRoot, type PluginContextV3 } from '@kb-labs/sdk';\nimport { execSync } from 'node:child_process';\nimport type { PolicyConfig, CheckReport } from '@kb-labs/policy-contracts';\nimport { detectCategory } from '../../core/category-resolver.js';\nimport { runChecks } from '../../core/policy-runner.js';\n\ntype CheckInput = {\n path?: string;\n json?: boolean;\n};\n\ntype CheckResult = {\n exitCode: number;\n report: CheckReport;\n};\n\nexport default defineCommand({\n id: 'policy:check',\n description: 'Run policy checks for changed repos or a specific path. Exits with code 1 on violations.',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CheckInput): Promise<CheckResult> {\n const flags = (input as { flags?: CheckInput }).flags ?? input;\n const workspaceRoot = (await findRepoRoot(ctx.cwd)) ?? ctx.cwd;\n const policyConfig = await useConfig<PolicyConfig>();\n\n if (!policyConfig?.categories) {\n ctx.ui.error('No policies config found in .kb/kb.config.json (expected \"policies\" key)');\n const emptyReport: CheckReport = {\n passed: false,\n repos: [],\n summary: { total: 0, passed: 0, failed: 0, violations: 0 },\n };\n if (flags.json) {ctx.ui.json?.({ passed: false, error: 'No policies config' });}\n return { exitCode: 1, report: emptyReport };\n }\n\n const repoPaths = flags.path\n ? [flags.path]\n : detectChangedRepos(workspaceRoot);\n\n const repos = repoPaths.map((p) => detectCategory(p, policyConfig));\n\n // Warn about repos with no category\n for (const r of repos) {\n if (!r.category) {\n ctx.ui.warn?.(`Repo ${r.path} has no category — applying default rules: ${r.rules.join(', ')}`);\n }\n }\n\n const report = await runChecks(repos, policyConfig, workspaceRoot);\n\n if (flags.json) {\n ctx.ui.json?.(report);\n } else {\n renderHumanReport(ctx, report);\n }\n\n return { exitCode: report.passed ? 0 : 1, report };\n },\n },\n});\n\nfunction renderHumanReport(ctx: PluginContextV3, report: CheckReport): void {\n const lines: string[] = [];\n\n for (const repo of report.repos) {\n const cat = repo.category ?? '(no category)';\n lines.push(`\\n${repo.path} (category: ${cat})`);\n\n for (const violation of repo.violations) {\n lines.push(` ❌ ${violation.rule}`);\n lines.push(` ${violation.message}`);\n if (violation.detail) {lines.push(` → ${violation.detail}`);}\n }\n for (const passed of repo.passed) {\n lines.push(` ✅ ${passed}`);\n }\n }\n\n const { total, passed, failed, violations } = report.summary;\n const summaryLine = report.passed\n ? `✅ All ${total} repo(s) passed`\n : `❌ ${violations} violation(s) found in ${failed}/${total} repo(s) — pipeline blocked`;\n\n if (report.passed) {\n ctx.ui.success?.('Policy Check', {\n sections: [\n { header: 'Results', items: lines },\n { header: 'Summary', items: [`${passed}/${total} passed`] },\n ],\n });\n } else {\n ctx.ui.error(`Policy Check Failed\\n${lines.join('\\n')}\\n\\n${summaryLine}`);\n }\n}\n\nfunction detectChangedRepos(workspaceRoot: string): string[] {\n try {\n const output = execSync('git diff --name-only HEAD 2>/dev/null || git diff --name-only', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n timeout: 10000,\n });\n\n const repoSet = new Set<string>();\n for (const file of output.trim().split('\\n').filter(Boolean)) {\n const parts = file.split('/');\n if (parts.length >= 2) {\n const topDir = parts[0]!;\n const repoDir = parts[1]!;\n if (['platform', 'plugins', 'infra', 'templates', 'installer', 'sites'].includes(topDir)) {\n repoSet.add(`${topDir}/${repoDir}`);\n }\n }\n }\n return Array.from(repoSet);\n } catch {\n return [];\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { PolicyConfig } from '@kb-labs/policy-contracts';\nimport { detectCategory } from './category-resolver.js';\n\ninterface PackageInfo {\n name: string;\n repoPath: string;\n category: string | null;\n packageJsonPath: string;\n}\n\n/**\n * Scans all packages in the workspace and returns a map of packageName → category.\n * Also returns full PackageInfo for more detailed lookups.\n */\nexport function buildPackageMap(\n workspaceRoot: string,\n config: PolicyConfig,\n): Map<string, string | null> {\n const packages = scanAllPackages(workspaceRoot, config);\n const map = new Map<string, string | null>();\n for (const pkg of packages) {\n map.set(pkg.name, pkg.category);\n }\n return map;\n}\n\n/**\n * Returns all packages in a specific repo (by repo path relative to workspaceRoot).\n */\nexport function getRepoPackageNames(workspaceRoot: string, repoPath: string): string[] {\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n const names: string[] = [];\n\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(absRepoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n\n for (const entry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, entry, 'package.json');\n if (!fs.existsSync(pkgJsonPath)) {continue;}\n try {\n const json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n if (json.name) {names.push(json.name);}\n } catch {\n // ignore invalid package.json\n }\n }\n }\n\n return names;\n}\n\nfunction scanAllPackages(workspaceRoot: string, config: PolicyConfig): PackageInfo[] {\n const results: PackageInfo[] = [];\n const topLevelDirs = ['platform', 'plugins', 'infra', 'templates', 'installer', 'sites'];\n\n for (const topDir of topLevelDirs) {\n const topDirPath = path.join(workspaceRoot, topDir);\n if (!fs.existsSync(topDirPath)) {continue;}\n\n for (const repoEntry of fs.readdirSync(topDirPath)) {\n const repoPath = path.join(topDirPath, repoEntry);\n const repoRelPath = `${topDir}/${repoEntry}`;\n\n // FIX 4 (MEDIUM): statSync can throw on broken symlinks, permission errors,\n // or race conditions where an entry disappears between readdirSync and statSync.\n // Skip the entry rather than letting the error propagate and abort the scan.\n let isDir: boolean;\n try {\n isDir = fs.statSync(repoPath).isDirectory();\n } catch {\n continue;\n }\n if (!isDir) {continue;}\n\n const categoryResult = detectCategory(repoRelPath, config);\n\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(repoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n\n for (const pkgEntry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, pkgEntry, 'package.json');\n if (!fs.existsSync(pkgJsonPath)) {continue;}\n\n try {\n const json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n if (json.name) {\n results.push({\n name: json.name,\n repoPath: repoRelPath,\n category: categoryResult.category,\n packageJsonPath: pkgJsonPath,\n });\n }\n } catch {\n // ignore\n }\n }\n }\n }\n }\n\n return results;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { PolicyConfig, PolicyViolation } from '@kb-labs/policy-contracts';\nimport { getRepoPackageNames } from '../core/workspace-scanner.js';\n\n/**\n * Checks that all packages in the repo only depend on @kb-labs/sdk\n * and their own internal packages (within the same repo).\n */\nexport async function checkSdkOnlyDeps(\n repoPath: string,\n _config: PolicyConfig,\n workspaceRoot: string,\n): Promise<PolicyViolation[]> {\n const violations: PolicyViolation[] = [];\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n const internalPackageNames = new Set(getRepoPackageNames(workspaceRoot, repoPath));\n\n const packageJsonPaths = findPackageJsonPaths(absRepoPath);\n\n for (const pkgJsonPath of packageJsonPaths) {\n let json: { name?: string; dependencies?: Record<string, string> };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n const deps = Object.keys(json.dependencies ?? {});\n const packageName = json.name ?? path.basename(path.dirname(pkgJsonPath));\n const relPath = path.relative(workspaceRoot, pkgJsonPath);\n\n for (const dep of deps) {\n if (!dep.startsWith('@kb-labs/')) {continue;}\n if (dep === '@kb-labs/sdk') {continue;}\n if (internalPackageNames.has(dep)) {continue;}\n\n violations.push({\n rule: 'sdk-only-deps',\n severity: 'error',\n message: `${packageName} imports ${dep} directly`,\n package: packageName,\n detail: `Plugins must depend only on @kb-labs/sdk. Move needed types to SDK or use SDK re-exports.`,\n file: relPath,\n });\n }\n }\n\n return violations;\n}\n\nfunction findPackageJsonPaths(absRepoPath: string): string[] {\n const results: string[] = [];\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(absRepoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n for (const entry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, entry, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {results.push(pkgJsonPath);}\n }\n }\n return results;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { PolicyConfig, PolicyViolation } from '@kb-labs/policy-contracts';\nimport { buildPackageMap, getRepoPackageNames } from '../core/workspace-scanner.js';\nimport { checkSdkOnlyDeps } from './sdk-only-deps.js';\n\n/**\n * Checks that packages only depend on packages from allowed categories.\n * If allowed contains \"sdk-only\", delegates to sdk-only-deps logic.\n */\nexport async function checkBoundary(\n repoPath: string,\n config: PolicyConfig,\n workspaceRoot: string,\n): Promise<PolicyViolation[]> {\n const violations: PolicyViolation[] = [];\n\n // Find the category for this repo\n const { detectCategory } = await import('../core/category-resolver.js');\n const categoryResult = detectCategory(repoPath, config);\n const category = categoryResult.category;\n\n if (!category) {return violations;} // no category = no boundary config\n\n const boundaryRuleConfig = config.rules['boundary-check']?.config as\n | { allowed?: Record<string, string[]> }\n | undefined;\n const allowedCategories = boundaryRuleConfig?.allowed?.[category] ?? [];\n\n // If \"sdk-only\" is in allowed, delegate to sdk-only-deps\n if (allowedCategories.includes('sdk-only')) {\n return checkSdkOnlyDeps(repoPath, config, workspaceRoot);\n }\n\n const packageMap = buildPackageMap(workspaceRoot, config);\n const internalPackageNames = new Set(getRepoPackageNames(workspaceRoot, repoPath));\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n\n for (const pkgJsonPath of findPackageJsonPaths(absRepoPath)) {\n let json: { name?: string; dependencies?: Record<string, string> };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n const deps = Object.keys(json.dependencies ?? {});\n const packageName = json.name ?? path.basename(path.dirname(pkgJsonPath));\n const relPath = path.relative(workspaceRoot, pkgJsonPath);\n\n for (const dep of deps) {\n if (!dep.startsWith('@kb-labs/')) {continue;}\n if (internalPackageNames.has(dep)) {continue;} // own package = always ok\n\n const depCategory = packageMap.get(dep);\n if (depCategory === undefined || depCategory === null) {continue;} // unknown package, skip\n\n if (!allowedCategories.includes(depCategory)) {\n violations.push({\n rule: 'boundary-check',\n severity: 'error',\n message: `${packageName} depends on ${dep} (category: ${depCategory ?? 'unknown'})`,\n package: packageName,\n detail: `Category \"${category}\" may only depend on: ${allowedCategories.join(', ')}`,\n file: relPath,\n });\n }\n }\n }\n\n return violations;\n}\n\nfunction findPackageJsonPaths(absRepoPath: string): string[] {\n const results: string[] = [];\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(absRepoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n for (const entry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, entry, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {results.push(pkgJsonPath);}\n }\n }\n return results;\n}\n","export interface SymbolExtractor {\n extract(dtsContent: string): Set<string>;\n}\n\n/**\n * Regex-based symbol extractor for .d.ts files.\n * Handles common export patterns. Interface allows future replacement with TS Compiler API.\n */\nexport class RegexSymbolExtractor implements SymbolExtractor {\n extract(dtsContent: string): Set<string> {\n const symbols = new Set<string>();\n\n // export function foo / export async function foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:async\\s+)?function\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export class Foo / export abstract class Foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:abstract\\s+)?class\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export type Foo / export interface Foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:type\\s+|interface\\s+)(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export const foo / export let foo / export var foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:const|let|var)\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export enum Foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:const\\s+)?enum\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export { foo, bar as baz }\n for (const m of dtsContent.matchAll(/^export\\s+\\{([^}]+)\\}/gm)) {\n const entries = m[1]!.split(',').map((s) => s.trim());\n for (const entry of entries) {\n // Handle \"foo as bar\" — the exported name is \"bar\"\n const asMatch = entry.match(/\\w+\\s+as\\s+(\\w+)/);\n if (asMatch) {\n symbols.add(asMatch[1]!);\n } else {\n const nameMatch = entry.match(/^(\\w+)/);\n if (nameMatch) {symbols.add(nameMatch[1]!);}\n }\n }\n }\n\n // export default\n if (/^export\\s+default\\s+/m.test(dtsContent)) {\n symbols.add('default');\n }\n\n return symbols;\n }\n}\n\nexport const defaultSymbolExtractor: SymbolExtractor = new RegexSymbolExtractor();\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { PolicyConfig, PolicyViolation, ApiSnapshot } from '@kb-labs/policy-contracts';\nimport { defaultSymbolExtractor } from './symbol-extractor.js';\n\nconst SNAPSHOTS_DIR = '.kb/api-snapshots';\n\n/**\n * Checks API backward compatibility by comparing exported symbols against a stored snapshot.\n * Also handles \"no-breaking-without-major\" rule (both rules map to this check).\n *\n * First run (no snapshot): warns and skips — does NOT auto-create a snapshot.\n * Use updateSnapshots() to create/refresh snapshots explicitly.\n */\nexport async function checkApiCompat(\n repoPath: string,\n _config: PolicyConfig,\n workspaceRoot: string,\n): Promise<PolicyViolation[]> {\n const violations: PolicyViolation[] = [];\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n\n const packageJsonPaths = findPackageJsonPaths(absRepoPath);\n\n for (const pkgJsonPath of packageJsonPaths) {\n let json: { name?: string; version?: string };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n if (!json.name || !json.version) {continue;}\n\n const pkgName = json.name;\n const currentVersion = json.version;\n const snapshotPath = getSnapshotPath(workspaceRoot, pkgName);\n\n // Gather current exported symbols from dist/*.d.ts\n const pkgDir = path.dirname(pkgJsonPath);\n const currentSymbols = extractSymbolsFromDist(pkgDir);\n\n if (!fs.existsSync(snapshotPath)) {\n // FIX 2 (CRITICAL): removed the auto-saveSnapshot() call that was here.\n // checkApiCompat is a read-only check function; writing files as a side-effect\n // inside it violated the read/write separation and caused unexpected mutations\n // during dry-run / CI read-only policy checks.\n // Snapshots must be created explicitly via updateSnapshots().\n console.warn(\n `[policy] api-compat: No snapshot for ${pkgName} — run 'policy update-snapshots' to create one.`,\n );\n continue;\n }\n\n // Load snapshot and compare\n let snapshot: ApiSnapshot;\n try {\n snapshot = JSON.parse(fs.readFileSync(snapshotPath, 'utf-8'));\n } catch {\n console.warn(`[policy] api-compat: Could not read snapshot for ${pkgName}, skipping.`);\n continue;\n }\n\n const snapshotSymbols = new Set(snapshot.symbols);\n const relPath = path.relative(workspaceRoot, pkgJsonPath);\n\n const removed: string[] = [];\n for (const sym of snapshotSymbols) {\n if (!currentSymbols.has(sym)) {removed.push(sym);}\n }\n\n if (removed.length > 0) {\n // Check if major version bumped\n const currentMajor = parseMajor(currentVersion);\n const snapshotMajor = parseMajor(snapshot.version);\n\n if (currentMajor <= snapshotMajor) {\n violations.push({\n rule: 'api-compat-check',\n severity: 'error',\n message: `${pkgName} removed exported symbols without major version bump`,\n package: pkgName,\n detail: `Removed: ${removed.join(', ')}. Bump major version (current: ${currentVersion}, snapshot: ${snapshot.version}) or restore symbols.`,\n file: relPath,\n });\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Creates or updates the API snapshot for all packages in a repo.\n */\nexport function updateSnapshots(repoPath: string, workspaceRoot: string): void {\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n const packageJsonPaths = findPackageJsonPaths(absRepoPath);\n\n for (const pkgJsonPath of packageJsonPaths) {\n let json: { name?: string; version?: string };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n if (!json.name || !json.version) {continue;}\n\n const pkgDir = path.dirname(pkgJsonPath);\n const symbols = extractSymbolsFromDist(pkgDir);\n const snapshotPath = getSnapshotPath(workspaceRoot, json.name);\n saveSnapshot(snapshotPath, json.name, json.version, symbols);\n console.log(`[policy] Saved snapshot for ${json.name} @ ${json.version} (${symbols.size} symbols)`);\n }\n}\n\nfunction extractSymbolsFromDist(pkgDir: string): Set<string> {\n const distDir = path.join(pkgDir, 'dist');\n const symbols = new Set<string>();\n\n if (!fs.existsSync(distDir)) {return symbols;}\n\n const dtsFiles = findDtsFiles(distDir);\n for (const dtsFile of dtsFiles) {\n const content = fs.readFileSync(dtsFile, 'utf-8');\n for (const sym of defaultSymbolExtractor.extract(content)) {\n symbols.add(sym);\n }\n }\n\n return symbols;\n}\n\nfunction findDtsFiles(dir: string): string[] {\n const results: string[] = [];\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...findDtsFiles(fullPath));\n } else if (entry.name.endsWith('.d.ts')) {\n results.push(fullPath);\n }\n }\n return results;\n}\n\nfunction getSnapshotPath(workspaceRoot: string, packageName: string): string {\n const safeName = packageName.replace(/\\//g, '__').replace(/@/g, '');\n const snapshotsDir = path.join(workspaceRoot, SNAPSHOTS_DIR);\n if (!fs.existsSync(snapshotsDir)) {\n fs.mkdirSync(snapshotsDir, { recursive: true });\n }\n return path.join(snapshotsDir, `${safeName}.json`);\n}\n\nfunction saveSnapshot(snapshotPath: string, packageName: string, version: string, symbols: Set<string>): void {\n const snapshot: ApiSnapshot = {\n packageName,\n version,\n symbols: Array.from(symbols).sort(),\n extractedAt: new Date().toISOString(),\n };\n // FIX 5 (MEDIUM): guarded writeFileSync — a permission error or a full disk must\n // not crash the entire update run; log a warning and continue instead.\n try {\n fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));\n } catch (err) {\n console.warn(`[policy] api-compat: Failed to write snapshot to ${snapshotPath}: ${(err as Error).message}`);\n }\n}\n\nfunction parseMajor(version: string): number {\n return parseInt(version.split('.')[0] ?? '0', 10);\n}\n\nfunction findPackageJsonPaths(absRepoPath: string): string[] {\n const results: string[] = [];\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(absRepoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n for (const entry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, entry, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {results.push(pkgJsonPath);}\n }\n }\n return results;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n// FIX 1 (CRITICAL): replaced execSync with spawnSync so packageName is passed as\n// a literal argument — never interpolated into a shell command string.\n// execSync with a template literal was vulnerable to shell injection if packageName\n// contained shell metacharacters (e.g. `$(cmd)`, backticks, semicolons).\nimport { spawnSync } from 'node:child_process';\nimport type { PolicyConfig, PolicyViolation } from '@kb-labs/policy-contracts';\nimport semver from 'semver';\n\n/**\n * Checks that the current version in package.json is not less than the published npm version.\n */\nexport async function checkNoRollback(\n repoPath: string,\n _config: PolicyConfig,\n workspaceRoot: string,\n): Promise<PolicyViolation[]> {\n const violations: PolicyViolation[] = [];\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n const packageJsonPaths = findPackageJsonPaths(absRepoPath);\n\n for (const pkgJsonPath of packageJsonPaths) {\n let json: { name?: string; version?: string; private?: boolean };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n if (!json.name || !json.version) {continue;}\n if (json.private) {continue;} // private packages are not published\n\n const packageName = json.name;\n const currentVersion = json.version;\n const relPath = path.relative(workspaceRoot, pkgJsonPath);\n\n const publishedVersion = getPublishedVersion(packageName);\n if (publishedVersion === null) {\n // Not published or npm unavailable — skip\n continue;\n }\n\n if (!semver.gte(currentVersion, publishedVersion)) {\n violations.push({\n rule: 'no-rollback',\n severity: 'error',\n message: `${packageName} version ${currentVersion} is less than published ${publishedVersion}`,\n package: packageName,\n detail: `Cannot decrease version once published to npm. Restore to ${publishedVersion} or higher.`,\n file: relPath,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Returns the published npm version for a package, or null if not published / offline.\n */\nfunction getPublishedVersion(packageName: string): string | null {\n // spawnSync receives packageName as a discrete argv element — the OS never\n // passes it through a shell, so metacharacters cannot be interpreted.\n const result = spawnSync('npm', ['show', packageName, 'version', '--silent'], {\n timeout: 10000,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n if (result.error || result.status !== 0) {return null;}\n return semver.valid(result.stdout.trim()) ?? null;\n}\n\nfunction findPackageJsonPaths(absRepoPath: string): string[] {\n const results: string[] = [];\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(absRepoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n for (const entry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, entry, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {results.push(pkgJsonPath);}\n }\n }\n return results;\n}\n","import type { CategoryResult, CheckReport, PolicyConfig, RepoCheckResult } from '@kb-labs/policy-contracts';\nimport { checkSdkOnlyDeps } from '../checks/sdk-only-deps.js';\nimport { checkBoundary } from '../checks/boundary-check.js';\nimport { checkApiCompat } from '../checks/api-compat-check.js';\nimport { checkNoRollback } from '../checks/no-rollback.js';\n\ntype CheckFn = (repoPath: string, config: PolicyConfig, workspaceRoot: string) => Promise<import('@kb-labs/policy-contracts').PolicyViolation[]>;\n\nconst RULE_CHECKS: Record<string, CheckFn> = {\n 'sdk-only-deps': checkSdkOnlyDeps,\n 'boundary-check': checkBoundary,\n 'no-breaking-without-major': checkApiCompat,\n 'no-rollback': checkNoRollback,\n 'api-compat-check': checkApiCompat,\n};\n\nexport async function runChecks(\n repos: CategoryResult[],\n config: PolicyConfig,\n workspaceRoot: string,\n): Promise<CheckReport> {\n const repoResults: RepoCheckResult[] = [];\n\n for (const repo of repos) {\n const violations = [];\n const passed: string[] = [];\n const rulesToRun = repo.rules;\n\n for (const rule of rulesToRun) {\n const checkFn = RULE_CHECKS[rule];\n if (!checkFn) {\n // Unknown rule — skip with warning\n console.warn(`[policy] Unknown rule: ${rule} (skipping)`);\n continue;\n }\n\n // FIX 3 (CRITICAL): wrap each rule execution individually so that an\n // unexpected throw from one check does not abort the remaining rules or\n // prevent the report from being built for this (and subsequent) repos.\n let ruleViolations: import('@kb-labs/policy-contracts').PolicyViolation[];\n try {\n ruleViolations = await checkFn(repo.path, config, workspaceRoot);\n } catch (err) {\n console.warn(`[policy] Rule '${rule}' threw an unexpected error (skipping): ${(err as Error).message}`);\n continue;\n }\n\n if (ruleViolations.length === 0) {\n passed.push(rule);\n } else {\n violations.push(...ruleViolations.map((v) => ({ ...v, rule })));\n }\n }\n\n repoResults.push({\n path: repo.path,\n category: repo.category,\n violations,\n passed,\n });\n }\n\n const totalViolations = repoResults.reduce((sum, r) => sum + r.violations.length, 0);\n const failedRepos = repoResults.filter((r) => r.violations.length > 0).length;\n\n return {\n passed: totalViolations === 0,\n repos: repoResults,\n summary: {\n total: repos.length,\n passed: repos.length - failedRepos,\n failed: failedRepos,\n violations: totalViolations,\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
|
|
3
|
+
type DetectInput = {
|
|
4
|
+
path?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, DetectInput, unknown>;
|
|
8
|
+
|
|
9
|
+
export { _default as default };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { defineCommand, findRepoRoot, useConfig } from '@kb-labs/sdk';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/detect.ts
|
|
5
|
+
|
|
6
|
+
// src/core/category-resolver.ts
|
|
7
|
+
function matchesPattern(repoPath, pattern) {
|
|
8
|
+
const normalizedPath = repoPath.replace(/\/$/, "");
|
|
9
|
+
const normalizedPattern = pattern.replace(/\/$/, "");
|
|
10
|
+
if (normalizedPattern === normalizedPath) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
if (normalizedPattern.endsWith("/*")) {
|
|
14
|
+
const prefix = normalizedPattern.slice(0, -2);
|
|
15
|
+
const pathPrefix = normalizedPath.split("/").slice(0, prefix.split("/").length).join("/");
|
|
16
|
+
return pathPrefix === prefix;
|
|
17
|
+
}
|
|
18
|
+
if (normalizedPattern.includes("*")) {
|
|
19
|
+
const regexStr = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]+");
|
|
20
|
+
return new RegExp(`^${regexStr}$`).test(normalizedPath);
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
function detectCategory(repoPath, config) {
|
|
25
|
+
for (const [categoryName, categoryConfig] of Object.entries(config.categories)) {
|
|
26
|
+
for (const pattern of categoryConfig.paths) {
|
|
27
|
+
if (matchesPattern(repoPath, pattern)) {
|
|
28
|
+
return {
|
|
29
|
+
path: repoPath,
|
|
30
|
+
category: categoryName,
|
|
31
|
+
rules: categoryConfig.rules
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
path: repoPath,
|
|
38
|
+
category: null,
|
|
39
|
+
rules: ["boundary-check"]
|
|
40
|
+
// default fallback rule
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/cli/commands/detect.ts
|
|
45
|
+
var detect_default = defineCommand({
|
|
46
|
+
id: "policy:detect",
|
|
47
|
+
description: "Detect the policy category for repos based on changed files or a specific path",
|
|
48
|
+
handler: {
|
|
49
|
+
async execute(ctx, input) {
|
|
50
|
+
const flags = input.flags ?? input;
|
|
51
|
+
const workspaceRoot = await findRepoRoot(ctx.cwd) ?? ctx.cwd;
|
|
52
|
+
const policyConfig = await useConfig();
|
|
53
|
+
if (!policyConfig?.categories) {
|
|
54
|
+
ctx.ui.error('No policies config found in .kb/kb.config.json (expected "policies" key)');
|
|
55
|
+
return { exitCode: 1, repos: [] };
|
|
56
|
+
}
|
|
57
|
+
const repoPaths = flags.path ? [flags.path] : detectChangedRepos(workspaceRoot);
|
|
58
|
+
const repos = repoPaths.map((p) => detectCategory(p, policyConfig));
|
|
59
|
+
if (flags.json) {
|
|
60
|
+
ctx.ui.json?.({ repos });
|
|
61
|
+
} else {
|
|
62
|
+
if (repos.length === 0) {
|
|
63
|
+
ctx.ui.info?.("No repos detected");
|
|
64
|
+
} else {
|
|
65
|
+
const lines = repos.map((r) => {
|
|
66
|
+
const cat = r.category ?? "(no category \u2014 using defaults)";
|
|
67
|
+
const warn = !r.category ? " \u26A0\uFE0F" : "";
|
|
68
|
+
return ` ${r.path} \u2192 ${cat} [${r.rules.join(", ")}]${warn}`;
|
|
69
|
+
});
|
|
70
|
+
ctx.ui.success?.("Policy Detect", { sections: [{ header: "Repos", items: lines }] });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { exitCode: 0, repos };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
function detectChangedRepos(workspaceRoot) {
|
|
78
|
+
try {
|
|
79
|
+
const output = execSync("git diff --name-only HEAD 2>/dev/null || git diff --name-only", {
|
|
80
|
+
cwd: workspaceRoot,
|
|
81
|
+
encoding: "utf-8",
|
|
82
|
+
timeout: 1e4
|
|
83
|
+
});
|
|
84
|
+
const repoSet = /* @__PURE__ */ new Set();
|
|
85
|
+
for (const file of output.trim().split("\n").filter(Boolean)) {
|
|
86
|
+
const parts = file.split("/");
|
|
87
|
+
if (parts.length >= 2) {
|
|
88
|
+
const topDir = parts[0];
|
|
89
|
+
const repoDir = parts[1];
|
|
90
|
+
if (["platform", "plugins", "infra", "templates", "installer", "sites"].includes(topDir)) {
|
|
91
|
+
repoSet.add(`${topDir}/${repoDir}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return Array.from(repoSet);
|
|
96
|
+
} catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { detect_default as default };
|
|
102
|
+
//# sourceMappingURL=detect.js.map
|
|
103
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/core/category-resolver.ts","../../../src/cli/commands/detect.ts"],"names":[],"mappings":"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","file":"detect.js","sourcesContent":["import type { CategoryResult, PolicyConfig } from '@kb-labs/policy-contracts';\n\n/**\n * Checks if a repo path matches a glob-like category path pattern.\n * Supports simple wildcards: \"plugins/*\" matches \"plugins/kb-labs-mind\".\n */\nfunction matchesPattern(repoPath: string, pattern: string): boolean {\n // Normalize trailing slashes\n const normalizedPath = repoPath.replace(/\\/$/, '');\n const normalizedPattern = pattern.replace(/\\/$/, '');\n\n if (normalizedPattern === normalizedPath) {return true;}\n\n // Handle wildcard: \"plugins/*\" → matches \"plugins/anything\"\n if (normalizedPattern.endsWith('/*')) {\n const prefix = normalizedPattern.slice(0, -2); // remove /*\n const pathPrefix = normalizedPath.split('/').slice(0, prefix.split('/').length).join('/');\n return pathPrefix === prefix;\n }\n\n // Exact prefix match with single segment after\n if (normalizedPattern.includes('*')) {\n const regexStr = normalizedPattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '[^/]+');\n return new RegExp(`^${regexStr}$`).test(normalizedPath);\n }\n\n return false;\n}\n\n/**\n * Detects the category for a given repo path based on the policies config.\n * Returns first matching category. If no match, returns category: null.\n */\nexport function detectCategory(repoPath: string, config: PolicyConfig): CategoryResult {\n for (const [categoryName, categoryConfig] of Object.entries(config.categories)) {\n for (const pattern of categoryConfig.paths) {\n if (matchesPattern(repoPath, pattern)) {\n return {\n path: repoPath,\n category: categoryName,\n rules: categoryConfig.rules,\n };\n }\n }\n }\n\n return {\n path: repoPath,\n category: null,\n rules: ['boundary-check'], // default fallback rule\n };\n}\n\n/**\n * Detects categories for multiple repo paths.\n */\nexport function detectCategories(repoPaths: string[], config: PolicyConfig): CategoryResult[] {\n return repoPaths.map((p) => detectCategory(p, config));\n}\n","import { defineCommand, useConfig, findRepoRoot, type PluginContextV3 } from '@kb-labs/sdk';\nimport { execSync } from 'node:child_process';\nimport type { PolicyConfig, CategoryResult } from '@kb-labs/policy-contracts';\nimport { detectCategory } from '../../core/category-resolver.js';\n\ntype DetectInput = {\n path?: string;\n json?: boolean;\n};\n\ntype DetectResult = {\n exitCode: number;\n repos: CategoryResult[];\n};\n\nexport default defineCommand({\n id: 'policy:detect',\n description: 'Detect the policy category for repos based on changed files or a specific path',\n\n handler: {\n async execute(ctx: PluginContextV3, input: DetectInput): Promise<DetectResult> {\n const flags = (input as { flags?: DetectInput }).flags ?? input;\n const workspaceRoot = (await findRepoRoot(ctx.cwd)) ?? ctx.cwd;\n const policyConfig = await useConfig<PolicyConfig>();\n\n if (!policyConfig?.categories) {\n ctx.ui.error('No policies config found in .kb/kb.config.json (expected \"policies\" key)');\n return { exitCode: 1, repos: [] };\n }\n\n const repoPaths = flags.path\n ? [flags.path]\n : detectChangedRepos(workspaceRoot);\n\n const repos = repoPaths.map((p) => detectCategory(p, policyConfig));\n\n if (flags.json) {\n ctx.ui.json?.({ repos });\n } else {\n if (repos.length === 0) {\n ctx.ui.info?.('No repos detected');\n } else {\n const lines = repos.map((r) => {\n const cat = r.category ?? '(no category — using defaults)';\n const warn = !r.category ? ' ⚠️' : '';\n return ` ${r.path} → ${cat} [${r.rules.join(', ')}]${warn}`;\n });\n ctx.ui.success?.('Policy Detect', { sections: [{ header: 'Repos', items: lines }] });\n }\n }\n\n return { exitCode: 0, repos };\n },\n },\n});\n\nfunction detectChangedRepos(workspaceRoot: string): string[] {\n try {\n const output = execSync('git diff --name-only HEAD 2>/dev/null || git diff --name-only', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n timeout: 10000,\n });\n\n const repoSet = new Set<string>();\n for (const file of output.trim().split('\\n').filter(Boolean)) {\n const parts = file.split('/');\n if (parts.length >= 2) {\n const topDir = parts[0]!;\n const repoDir = parts[1]!;\n if (['platform', 'plugins', 'infra', 'templates', 'installer', 'sites'].includes(topDir)) {\n repoSet.add(`${topDir}/${repoDir}`);\n }\n }\n }\n return Array.from(repoSet);\n } catch {\n return [];\n }\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineCommand, useConfig } from '@kb-labs/sdk';
|
|
2
|
+
|
|
3
|
+
// src/cli/commands/rules.ts
|
|
4
|
+
var rules_default = defineCommand({
|
|
5
|
+
id: "policy:rules",
|
|
6
|
+
description: "Show all policy rules and which categories they apply to",
|
|
7
|
+
handler: {
|
|
8
|
+
async execute(ctx, input) {
|
|
9
|
+
const flags = input.flags ?? input;
|
|
10
|
+
const policyConfig = await useConfig();
|
|
11
|
+
if (!policyConfig?.categories || !policyConfig?.rules) {
|
|
12
|
+
ctx.ui.error('No policies config found in .kb/kb.config.json (expected "policies" key)');
|
|
13
|
+
return { exitCode: 1 };
|
|
14
|
+
}
|
|
15
|
+
const ruleToCategories = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const [categoryName, categoryConfig] of Object.entries(policyConfig.categories)) {
|
|
17
|
+
for (const rule of categoryConfig.rules) {
|
|
18
|
+
const existing = ruleToCategories.get(rule) ?? [];
|
|
19
|
+
existing.push(categoryName);
|
|
20
|
+
ruleToCategories.set(rule, existing);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (flags.json) {
|
|
24
|
+
const output = Object.entries(policyConfig.rules).map(([name, ruleDef]) => ({
|
|
25
|
+
name,
|
|
26
|
+
description: ruleDef.description,
|
|
27
|
+
severity: ruleDef.severity,
|
|
28
|
+
appliedTo: ruleToCategories.get(name) ?? []
|
|
29
|
+
}));
|
|
30
|
+
ctx.ui.json?.({ rules: output });
|
|
31
|
+
} else {
|
|
32
|
+
const items = Object.entries(policyConfig.rules).map(([name, ruleDef]) => {
|
|
33
|
+
const categories = ruleToCategories.get(name) ?? [];
|
|
34
|
+
const appliedTo = categories.length > 0 ? categories.join(", ") : "(none)";
|
|
35
|
+
return ` ${name}
|
|
36
|
+
${ruleDef.description}
|
|
37
|
+
Applied to: ${appliedTo}
|
|
38
|
+
Severity: ${ruleDef.severity}`;
|
|
39
|
+
});
|
|
40
|
+
ctx.ui.success?.("Policy Rules", { sections: [{ header: "Rules", items }] });
|
|
41
|
+
}
|
|
42
|
+
return { exitCode: 0 };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export { rules_default as default };
|
|
48
|
+
//# sourceMappingURL=rules.js.map
|
|
49
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/rules.ts"],"names":[],"mappings":";;;AAOA,IAAO,gBAAQ,aAAA,CAAc;AAAA,EAC3B,EAAA,EAAI,cAAA;AAAA,EACJ,WAAA,EAAa,0DAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAkD;AACpF,MAAA,MAAM,KAAA,GAAS,MAAiC,KAAA,IAAS,KAAA;AACzD,MAAA,MAAM,YAAA,GAAe,MAAM,SAAA,EAAwB;AAEnD,MAAA,IAAI,CAAC,YAAA,EAAc,UAAA,IAAc,CAAC,cAAc,KAAA,EAAO;AACrD,QAAA,GAAA,CAAI,EAAA,CAAG,MAAM,0EAA0E,CAAA;AACvF,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAGA,MAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAsB;AACnD,MAAA,KAAA,MAAW,CAAC,cAAc,cAAc,CAAA,IAAK,OAAO,OAAA,CAAQ,YAAA,CAAa,UAAU,CAAA,EAAG;AACpF,QAAA,KAAA,MAAW,IAAA,IAAQ,eAAe,KAAA,EAAO;AACvC,UAAA,MAAM,QAAA,GAAW,gBAAA,CAAiB,GAAA,CAAI,IAAI,KAAK,EAAC;AAChD,UAAA,QAAA,CAAS,KAAK,YAAY,CAAA;AAC1B,UAAA,gBAAA,CAAiB,GAAA,CAAI,MAAM,QAAQ,CAAA;AAAA,QACrC;AAAA,MACF;AAEA,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,YAAA,CAAa,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,OAAO,CAAA,MAAO;AAAA,UAC1E,IAAA;AAAA,UACA,aAAa,OAAA,CAAQ,WAAA;AAAA,UACrB,UAAU,OAAA,CAAQ,QAAA;AAAA,UAClB,SAAA,EAAW,gBAAA,CAAiB,GAAA,CAAI,IAAI,KAAK;AAAC,SAC5C,CAAE,CAAA;AACF,QAAA,GAAA,CAAI,EAAA,CAAG,IAAA,GAAO,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,MACjC,CAAA,MAAO;AACL,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA,CAAa,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,OAAO,CAAA,KAAM;AACxE,UAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,CAAI,IAAI,KAAK,EAAC;AAClD,UAAA,MAAM,YAAY,UAAA,CAAW,MAAA,GAAS,IAAI,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA,GAAI,QAAA;AAClE,UAAA,OAAO,KAAK,IAAI;AAAA,IAAA,EAAS,QAAQ,WAAW;AAAA,gBAAA,EAAqB,SAAS;AAAA,cAAA,EAAmB,QAAQ,QAAQ,CAAA,CAAA;AAAA,QAC/G,CAAC,CAAA;AACD,QAAA,GAAA,CAAI,EAAA,CAAG,OAAA,GAAU,cAAA,EAAgB,EAAE,QAAA,EAAU,CAAC,EAAE,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAO,CAAA,EAAG,CAAA;AAAA,MAC7E;AAEA,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"rules.js","sourcesContent":["import { defineCommand, useConfig, type PluginContextV3 } from '@kb-labs/sdk';\nimport type { PolicyConfig } from '@kb-labs/policy-contracts';\n\ntype RulesInput = {\n json?: boolean;\n};\n\nexport default defineCommand({\n id: 'policy:rules',\n description: 'Show all policy rules and which categories they apply to',\n\n handler: {\n async execute(ctx: PluginContextV3, input: RulesInput): Promise<{ exitCode: number }> {\n const flags = (input as { flags?: RulesInput }).flags ?? input;\n const policyConfig = await useConfig<PolicyConfig>();\n\n if (!policyConfig?.categories || !policyConfig?.rules) {\n ctx.ui.error('No policies config found in .kb/kb.config.json (expected \"policies\" key)');\n return { exitCode: 1 };\n }\n\n // Build reverse map: rule → categories that use it\n const ruleToCategories = new Map<string, string[]>();\n for (const [categoryName, categoryConfig] of Object.entries(policyConfig.categories)) {\n for (const rule of categoryConfig.rules) {\n const existing = ruleToCategories.get(rule) ?? [];\n existing.push(categoryName);\n ruleToCategories.set(rule, existing);\n }\n }\n\n if (flags.json) {\n const output = Object.entries(policyConfig.rules).map(([name, ruleDef]) => ({\n name,\n description: ruleDef.description,\n severity: ruleDef.severity,\n appliedTo: ruleToCategories.get(name) ?? [],\n }));\n ctx.ui.json?.({ rules: output });\n } else {\n const items = Object.entries(policyConfig.rules).map(([name, ruleDef]) => {\n const categories = ruleToCategories.get(name) ?? [];\n const appliedTo = categories.length > 0 ? categories.join(', ') : '(none)';\n return ` ${name}\\n ${ruleDef.description}\\n Applied to: ${appliedTo}\\n Severity: ${ruleDef.severity}`;\n });\n ctx.ui.success?.('Policy Rules', { sections: [{ header: 'Rules', items }] });\n }\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { defineCommand, findRepoRoot } from '@kb-labs/sdk';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
// src/cli/commands/snapshot.ts
|
|
6
|
+
|
|
7
|
+
// src/checks/symbol-extractor.ts
|
|
8
|
+
var RegexSymbolExtractor = class {
|
|
9
|
+
extract(dtsContent) {
|
|
10
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const m of dtsContent.matchAll(/^export\s+(?:async\s+)?function\s+(\w+)/gm)) {
|
|
12
|
+
symbols.add(m[1]);
|
|
13
|
+
}
|
|
14
|
+
for (const m of dtsContent.matchAll(/^export\s+(?:abstract\s+)?class\s+(\w+)/gm)) {
|
|
15
|
+
symbols.add(m[1]);
|
|
16
|
+
}
|
|
17
|
+
for (const m of dtsContent.matchAll(/^export\s+(?:type\s+|interface\s+)(\w+)/gm)) {
|
|
18
|
+
symbols.add(m[1]);
|
|
19
|
+
}
|
|
20
|
+
for (const m of dtsContent.matchAll(/^export\s+(?:const|let|var)\s+(\w+)/gm)) {
|
|
21
|
+
symbols.add(m[1]);
|
|
22
|
+
}
|
|
23
|
+
for (const m of dtsContent.matchAll(/^export\s+(?:const\s+)?enum\s+(\w+)/gm)) {
|
|
24
|
+
symbols.add(m[1]);
|
|
25
|
+
}
|
|
26
|
+
for (const m of dtsContent.matchAll(/^export\s+\{([^}]+)\}/gm)) {
|
|
27
|
+
const entries = m[1].split(",").map((s) => s.trim());
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const asMatch = entry.match(/\w+\s+as\s+(\w+)/);
|
|
30
|
+
if (asMatch) {
|
|
31
|
+
symbols.add(asMatch[1]);
|
|
32
|
+
} else {
|
|
33
|
+
const nameMatch = entry.match(/^(\w+)/);
|
|
34
|
+
if (nameMatch) {
|
|
35
|
+
symbols.add(nameMatch[1]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (/^export\s+default\s+/m.test(dtsContent)) {
|
|
41
|
+
symbols.add("default");
|
|
42
|
+
}
|
|
43
|
+
return symbols;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var defaultSymbolExtractor = new RegexSymbolExtractor();
|
|
47
|
+
|
|
48
|
+
// src/checks/api-compat-check.ts
|
|
49
|
+
var SNAPSHOTS_DIR = ".kb/api-snapshots";
|
|
50
|
+
function updateSnapshots(repoPath, workspaceRoot) {
|
|
51
|
+
const absRepoPath = path.resolve(workspaceRoot, repoPath);
|
|
52
|
+
const packageJsonPaths = findPackageJsonPaths(absRepoPath);
|
|
53
|
+
for (const pkgJsonPath of packageJsonPaths) {
|
|
54
|
+
let json;
|
|
55
|
+
try {
|
|
56
|
+
json = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
57
|
+
} catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!json.name || !json.version) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const pkgDir = path.dirname(pkgJsonPath);
|
|
64
|
+
const symbols = extractSymbolsFromDist(pkgDir);
|
|
65
|
+
const snapshotPath = getSnapshotPath(workspaceRoot, json.name);
|
|
66
|
+
saveSnapshot(snapshotPath, json.name, json.version, symbols);
|
|
67
|
+
console.log(`[policy] Saved snapshot for ${json.name} @ ${json.version} (${symbols.size} symbols)`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function extractSymbolsFromDist(pkgDir) {
|
|
71
|
+
const distDir = path.join(pkgDir, "dist");
|
|
72
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
73
|
+
if (!fs.existsSync(distDir)) {
|
|
74
|
+
return symbols;
|
|
75
|
+
}
|
|
76
|
+
const dtsFiles = findDtsFiles(distDir);
|
|
77
|
+
for (const dtsFile of dtsFiles) {
|
|
78
|
+
const content = fs.readFileSync(dtsFile, "utf-8");
|
|
79
|
+
for (const sym of defaultSymbolExtractor.extract(content)) {
|
|
80
|
+
symbols.add(sym);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return symbols;
|
|
84
|
+
}
|
|
85
|
+
function findDtsFiles(dir) {
|
|
86
|
+
const results = [];
|
|
87
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
88
|
+
const fullPath = path.join(dir, entry.name);
|
|
89
|
+
if (entry.isDirectory()) {
|
|
90
|
+
results.push(...findDtsFiles(fullPath));
|
|
91
|
+
} else if (entry.name.endsWith(".d.ts")) {
|
|
92
|
+
results.push(fullPath);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
function getSnapshotPath(workspaceRoot, packageName) {
|
|
98
|
+
const safeName = packageName.replace(/\//g, "__").replace(/@/g, "");
|
|
99
|
+
const snapshotsDir = path.join(workspaceRoot, SNAPSHOTS_DIR);
|
|
100
|
+
if (!fs.existsSync(snapshotsDir)) {
|
|
101
|
+
fs.mkdirSync(snapshotsDir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
return path.join(snapshotsDir, `${safeName}.json`);
|
|
104
|
+
}
|
|
105
|
+
function saveSnapshot(snapshotPath, packageName, version, symbols) {
|
|
106
|
+
const snapshot = {
|
|
107
|
+
packageName,
|
|
108
|
+
version,
|
|
109
|
+
symbols: Array.from(symbols).sort(),
|
|
110
|
+
extractedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
111
|
+
};
|
|
112
|
+
try {
|
|
113
|
+
fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.warn(`[policy] api-compat: Failed to write snapshot to ${snapshotPath}: ${err.message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function findPackageJsonPaths(absRepoPath) {
|
|
119
|
+
const results = [];
|
|
120
|
+
for (const subdir of ["packages", "apps"]) {
|
|
121
|
+
const subdirPath = path.join(absRepoPath, subdir);
|
|
122
|
+
if (!fs.existsSync(subdirPath)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
for (const entry of fs.readdirSync(subdirPath)) {
|
|
126
|
+
const pkgJsonPath = path.join(subdirPath, entry, "package.json");
|
|
127
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
128
|
+
results.push(pkgJsonPath);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return results;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/cli/commands/snapshot.ts
|
|
136
|
+
var snapshot_default = defineCommand({
|
|
137
|
+
id: "policy:snapshot",
|
|
138
|
+
description: "Create or update the API snapshot for packages in a repo. Run after npm publish.",
|
|
139
|
+
handler: {
|
|
140
|
+
async execute(ctx, input) {
|
|
141
|
+
const flags = input.flags ?? input;
|
|
142
|
+
if (!flags.path) {
|
|
143
|
+
ctx.ui.error('--path is required. Example: pnpm kb policy snapshot --path="platform/kb-labs-sdk"');
|
|
144
|
+
return { exitCode: 1 };
|
|
145
|
+
}
|
|
146
|
+
const workspaceRoot = await findRepoRoot(ctx.cwd) ?? ctx.cwd;
|
|
147
|
+
ctx.ui.info?.(`Extracting API snapshot for ${flags.path}...`);
|
|
148
|
+
updateSnapshots(flags.path, workspaceRoot);
|
|
149
|
+
ctx.ui.success?.("Snapshot updated", {
|
|
150
|
+
sections: [
|
|
151
|
+
{
|
|
152
|
+
header: "Info",
|
|
153
|
+
items: [
|
|
154
|
+
`Path: ${flags.path}`,
|
|
155
|
+
`Snapshots saved to: .kb/api-snapshots/`
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
return { exitCode: 0 };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
export { snapshot_default as default };
|
|
166
|
+
//# sourceMappingURL=snapshot.js.map
|
|
167
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/checks/symbol-extractor.ts","../../../src/checks/api-compat-check.ts","../../../src/cli/commands/snapshot.ts"],"names":[],"mappings":";;;;;;;AAQO,IAAM,uBAAN,MAAsD;AAAA,EAC3D,QAAQ,UAAA,EAAiC;AACvC,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAGhC,IAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,2CAA2C,CAAA,EAAG;AAChF,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,CAAC,CAAE,CAAA;AAAA,IACnB;AAGA,IAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,2CAA2C,CAAA,EAAG;AAChF,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,CAAC,CAAE,CAAA;AAAA,IACnB;AAGA,IAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,2CAA2C,CAAA,EAAG;AAChF,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,CAAC,CAAE,CAAA;AAAA,IACnB;AAGA,IAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,uCAAuC,CAAA,EAAG;AAC5E,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,CAAC,CAAE,CAAA;AAAA,IACnB;AAGA,IAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,uCAAuC,CAAA,EAAG;AAC5E,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,CAAC,CAAE,CAAA;AAAA,IACnB;AAGA,IAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,yBAAyB,CAAA,EAAG;AAC9D,MAAA,MAAM,OAAA,GAAU,CAAA,CAAE,CAAC,CAAA,CAAG,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AACpD,MAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAE3B,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,kBAAkB,CAAA;AAC9C,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,OAAA,CAAQ,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAE,CAAA;AAAA,QACzB,CAAA,MAAO;AACL,UAAA,MAAM,SAAA,GAAY,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAA;AACtC,UAAA,IAAI,SAAA,EAAW;AAAC,YAAA,OAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,CAAC,CAAE,CAAA;AAAA,UAAE;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAGA,IAAA,IAAI,uBAAA,CAAwB,IAAA,CAAK,UAAU,CAAA,EAAG;AAC5C,MAAA,OAAA,CAAQ,IAAI,SAAS,CAAA;AAAA,IACvB;AAEA,IAAA,OAAO,OAAA;AAAA,EACT;AACF,CAAA;AAEO,IAAM,sBAAA,GAA0C,IAAI,oBAAA,EAAqB;;;ACxDhF,IAAM,aAAA,GAAgB,mBAAA;AAyFf,SAAS,eAAA,CAAgB,UAAkB,aAAA,EAA6B;AAC7E,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,CAAQ,aAAA,EAAe,QAAQ,CAAA;AACxD,EAAA,MAAM,gBAAA,GAAmB,qBAAqB,WAAW,CAAA;AAEzD,EAAA,KAAA,MAAW,eAAe,gBAAA,EAAkB;AAC1C,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AACF,MAAA,IAAA,GAAO,KAAK,KAAA,CAAM,EAAA,CAAG,YAAA,CAAa,WAAA,EAAa,OAAO,CAAC,CAAA;AAAA,IACzD,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,IAAA,CAAK,IAAA,IAAQ,CAAC,KAAK,OAAA,EAAS;AAAC,MAAA;AAAA,IAAS;AAE3C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA;AACvC,IAAA,MAAM,OAAA,GAAU,uBAAuB,MAAM,CAAA;AAC7C,IAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,aAAA,EAAe,IAAA,CAAK,IAAI,CAAA;AAC7D,IAAA,YAAA,CAAa,YAAA,EAAc,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,SAAS,OAAO,CAAA;AAC3D,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,4BAAA,EAA+B,IAAA,CAAK,IAAI,CAAA,GAAA,EAAM,KAAK,OAAO,CAAA,EAAA,EAAK,OAAA,CAAQ,IAAI,CAAA,SAAA,CAAW,CAAA;AAAA,EACpG;AACF;AAEA,SAAS,uBAAuB,MAAA,EAA6B;AAC3D,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,MAAM,CAAA;AACxC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAEhC,EAAA,IAAI,CAAC,EAAA,CAAG,UAAA,CAAW,OAAO,CAAA,EAAG;AAAC,IAAA,OAAO,OAAA;AAAA,EAAQ;AAE7C,EAAA,MAAM,QAAA,GAAW,aAAa,OAAO,CAAA;AACrC,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAM,OAAA,GAAU,EAAA,CAAG,YAAA,CAAa,OAAA,EAAS,OAAO,CAAA;AAChD,IAAA,KAAA,MAAW,GAAA,IAAO,sBAAA,CAAuB,OAAA,CAAQ,OAAO,CAAA,EAAG;AACzD,MAAA,OAAA,CAAQ,IAAI,GAAG,CAAA;AAAA,IACjB;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,aAAa,GAAA,EAAuB;AAC3C,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,KAAA,IAAS,GAAG,WAAA,CAAY,GAAA,EAAK,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA,EAAG;AAChE,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK,MAAM,IAAI,CAAA;AAC1C,IAAA,IAAI,KAAA,CAAM,aAAY,EAAG;AACvB,MAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,YAAA,CAAa,QAAQ,CAAC,CAAA;AAAA,IACxC,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAG;AACvC,MAAA,OAAA,CAAQ,KAAK,QAAQ,CAAA;AAAA,IACvB;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,eAAA,CAAgB,eAAuB,WAAA,EAA6B;AAC3E,EAAA,MAAM,QAAA,GAAW,YAAY,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAM,EAAE,CAAA;AAClE,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,IAAA,CAAK,aAAA,EAAe,aAAa,CAAA;AAC3D,EAAA,IAAI,CAAC,EAAA,CAAG,UAAA,CAAW,YAAY,CAAA,EAAG;AAChC,IAAA,EAAA,CAAG,SAAA,CAAU,YAAA,EAAc,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,CAAA,EAAG,QAAQ,CAAA,KAAA,CAAO,CAAA;AACnD;AAEA,SAAS,YAAA,CAAa,YAAA,EAAsB,WAAA,EAAqB,OAAA,EAAiB,OAAA,EAA4B;AAC5G,EAAA,MAAM,QAAA,GAAwB;AAAA,IAC5B,WAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA,EAAS,KAAA,CAAM,IAAA,CAAK,OAAO,EAAE,IAAA,EAAK;AAAA,IAClC,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AAGA,EAAA,IAAI;AACF,IAAA,EAAA,CAAG,cAAc,YAAA,EAAc,IAAA,CAAK,UAAU,QAAA,EAAU,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,EAClE,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,KAAK,CAAA,iDAAA,EAAoD,YAAY,CAAA,EAAA,EAAM,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAAA,EAC5G;AACF;AAMA,SAAS,qBAAqB,WAAA,EAA+B;AAC3D,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,MAAA,IAAU,CAAC,UAAA,EAAY,MAAM,CAAA,EAAG;AACzC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,MAAM,CAAA;AAChD,IAAA,IAAI,CAAC,EAAA,CAAG,UAAA,CAAW,UAAU,CAAA,EAAG;AAAC,MAAA;AAAA,IAAS;AAC1C,IAAA,KAAA,MAAW,KAAA,IAAS,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,EAAG;AAC9C,MAAA,MAAM,WAAA,GAAc,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,OAAO,cAAc,CAAA;AAC/D,MAAA,IAAI,EAAA,CAAG,UAAA,CAAW,WAAW,CAAA,EAAG;AAAC,QAAA,OAAA,CAAQ,KAAK,WAAW,CAAA;AAAA,MAAE;AAAA,IAC7D;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;;;AClLA,IAAO,mBAAQ,aAAA,CAAc;AAAA,EAC3B,EAAA,EAAI,iBAAA;AAAA,EACJ,WAAA,EAAa,kFAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAqD;AACvF,MAAA,MAAM,KAAA,GAAS,MAAoC,KAAA,IAAS,KAAA;AAE5D,MAAA,IAAI,CAAC,MAAM,IAAA,EAAM;AACf,QAAA,GAAA,CAAI,EAAA,CAAG,MAAM,oFAAoF,CAAA;AACjG,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,MAAM,gBAAiB,MAAM,YAAA,CAAa,GAAA,CAAI,GAAG,KAAM,GAAA,CAAI,GAAA;AAE3D,MAAA,GAAA,CAAI,EAAA,CAAG,IAAA,GAAO,CAAA,4BAAA,EAA+B,KAAA,CAAM,IAAI,CAAA,GAAA,CAAK,CAAA;AAC5D,MAAA,eAAA,CAAgB,KAAA,CAAM,MAAM,aAAa,CAAA;AACzC,MAAA,GAAA,CAAI,EAAA,CAAG,UAAU,kBAAA,EAAoB;AAAA,QACnC,QAAA,EAAU;AAAA,UACR;AAAA,YACE,MAAA,EAAQ,MAAA;AAAA,YACR,KAAA,EAAO;AAAA,cACL,CAAA,MAAA,EAAS,MAAM,IAAI,CAAA,CAAA;AAAA,cACnB,CAAA,sCAAA;AAAA;AACF;AACF;AACF,OACD,CAAA;AAED,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"snapshot.js","sourcesContent":["export interface SymbolExtractor {\n extract(dtsContent: string): Set<string>;\n}\n\n/**\n * Regex-based symbol extractor for .d.ts files.\n * Handles common export patterns. Interface allows future replacement with TS Compiler API.\n */\nexport class RegexSymbolExtractor implements SymbolExtractor {\n extract(dtsContent: string): Set<string> {\n const symbols = new Set<string>();\n\n // export function foo / export async function foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:async\\s+)?function\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export class Foo / export abstract class Foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:abstract\\s+)?class\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export type Foo / export interface Foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:type\\s+|interface\\s+)(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export const foo / export let foo / export var foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:const|let|var)\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export enum Foo\n for (const m of dtsContent.matchAll(/^export\\s+(?:const\\s+)?enum\\s+(\\w+)/gm)) {\n symbols.add(m[1]!);\n }\n\n // export { foo, bar as baz }\n for (const m of dtsContent.matchAll(/^export\\s+\\{([^}]+)\\}/gm)) {\n const entries = m[1]!.split(',').map((s) => s.trim());\n for (const entry of entries) {\n // Handle \"foo as bar\" — the exported name is \"bar\"\n const asMatch = entry.match(/\\w+\\s+as\\s+(\\w+)/);\n if (asMatch) {\n symbols.add(asMatch[1]!);\n } else {\n const nameMatch = entry.match(/^(\\w+)/);\n if (nameMatch) {symbols.add(nameMatch[1]!);}\n }\n }\n }\n\n // export default\n if (/^export\\s+default\\s+/m.test(dtsContent)) {\n symbols.add('default');\n }\n\n return symbols;\n }\n}\n\nexport const defaultSymbolExtractor: SymbolExtractor = new RegexSymbolExtractor();\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { PolicyConfig, PolicyViolation, ApiSnapshot } from '@kb-labs/policy-contracts';\nimport { defaultSymbolExtractor } from './symbol-extractor.js';\n\nconst SNAPSHOTS_DIR = '.kb/api-snapshots';\n\n/**\n * Checks API backward compatibility by comparing exported symbols against a stored snapshot.\n * Also handles \"no-breaking-without-major\" rule (both rules map to this check).\n *\n * First run (no snapshot): warns and skips — does NOT auto-create a snapshot.\n * Use updateSnapshots() to create/refresh snapshots explicitly.\n */\nexport async function checkApiCompat(\n repoPath: string,\n _config: PolicyConfig,\n workspaceRoot: string,\n): Promise<PolicyViolation[]> {\n const violations: PolicyViolation[] = [];\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n\n const packageJsonPaths = findPackageJsonPaths(absRepoPath);\n\n for (const pkgJsonPath of packageJsonPaths) {\n let json: { name?: string; version?: string };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n if (!json.name || !json.version) {continue;}\n\n const pkgName = json.name;\n const currentVersion = json.version;\n const snapshotPath = getSnapshotPath(workspaceRoot, pkgName);\n\n // Gather current exported symbols from dist/*.d.ts\n const pkgDir = path.dirname(pkgJsonPath);\n const currentSymbols = extractSymbolsFromDist(pkgDir);\n\n if (!fs.existsSync(snapshotPath)) {\n // FIX 2 (CRITICAL): removed the auto-saveSnapshot() call that was here.\n // checkApiCompat is a read-only check function; writing files as a side-effect\n // inside it violated the read/write separation and caused unexpected mutations\n // during dry-run / CI read-only policy checks.\n // Snapshots must be created explicitly via updateSnapshots().\n console.warn(\n `[policy] api-compat: No snapshot for ${pkgName} — run 'policy update-snapshots' to create one.`,\n );\n continue;\n }\n\n // Load snapshot and compare\n let snapshot: ApiSnapshot;\n try {\n snapshot = JSON.parse(fs.readFileSync(snapshotPath, 'utf-8'));\n } catch {\n console.warn(`[policy] api-compat: Could not read snapshot for ${pkgName}, skipping.`);\n continue;\n }\n\n const snapshotSymbols = new Set(snapshot.symbols);\n const relPath = path.relative(workspaceRoot, pkgJsonPath);\n\n const removed: string[] = [];\n for (const sym of snapshotSymbols) {\n if (!currentSymbols.has(sym)) {removed.push(sym);}\n }\n\n if (removed.length > 0) {\n // Check if major version bumped\n const currentMajor = parseMajor(currentVersion);\n const snapshotMajor = parseMajor(snapshot.version);\n\n if (currentMajor <= snapshotMajor) {\n violations.push({\n rule: 'api-compat-check',\n severity: 'error',\n message: `${pkgName} removed exported symbols without major version bump`,\n package: pkgName,\n detail: `Removed: ${removed.join(', ')}. Bump major version (current: ${currentVersion}, snapshot: ${snapshot.version}) or restore symbols.`,\n file: relPath,\n });\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Creates or updates the API snapshot for all packages in a repo.\n */\nexport function updateSnapshots(repoPath: string, workspaceRoot: string): void {\n const absRepoPath = path.resolve(workspaceRoot, repoPath);\n const packageJsonPaths = findPackageJsonPaths(absRepoPath);\n\n for (const pkgJsonPath of packageJsonPaths) {\n let json: { name?: string; version?: string };\n try {\n json = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n if (!json.name || !json.version) {continue;}\n\n const pkgDir = path.dirname(pkgJsonPath);\n const symbols = extractSymbolsFromDist(pkgDir);\n const snapshotPath = getSnapshotPath(workspaceRoot, json.name);\n saveSnapshot(snapshotPath, json.name, json.version, symbols);\n console.log(`[policy] Saved snapshot for ${json.name} @ ${json.version} (${symbols.size} symbols)`);\n }\n}\n\nfunction extractSymbolsFromDist(pkgDir: string): Set<string> {\n const distDir = path.join(pkgDir, 'dist');\n const symbols = new Set<string>();\n\n if (!fs.existsSync(distDir)) {return symbols;}\n\n const dtsFiles = findDtsFiles(distDir);\n for (const dtsFile of dtsFiles) {\n const content = fs.readFileSync(dtsFile, 'utf-8');\n for (const sym of defaultSymbolExtractor.extract(content)) {\n symbols.add(sym);\n }\n }\n\n return symbols;\n}\n\nfunction findDtsFiles(dir: string): string[] {\n const results: string[] = [];\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...findDtsFiles(fullPath));\n } else if (entry.name.endsWith('.d.ts')) {\n results.push(fullPath);\n }\n }\n return results;\n}\n\nfunction getSnapshotPath(workspaceRoot: string, packageName: string): string {\n const safeName = packageName.replace(/\\//g, '__').replace(/@/g, '');\n const snapshotsDir = path.join(workspaceRoot, SNAPSHOTS_DIR);\n if (!fs.existsSync(snapshotsDir)) {\n fs.mkdirSync(snapshotsDir, { recursive: true });\n }\n return path.join(snapshotsDir, `${safeName}.json`);\n}\n\nfunction saveSnapshot(snapshotPath: string, packageName: string, version: string, symbols: Set<string>): void {\n const snapshot: ApiSnapshot = {\n packageName,\n version,\n symbols: Array.from(symbols).sort(),\n extractedAt: new Date().toISOString(),\n };\n // FIX 5 (MEDIUM): guarded writeFileSync — a permission error or a full disk must\n // not crash the entire update run; log a warning and continue instead.\n try {\n fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));\n } catch (err) {\n console.warn(`[policy] api-compat: Failed to write snapshot to ${snapshotPath}: ${(err as Error).message}`);\n }\n}\n\nfunction parseMajor(version: string): number {\n return parseInt(version.split('.')[0] ?? '0', 10);\n}\n\nfunction findPackageJsonPaths(absRepoPath: string): string[] {\n const results: string[] = [];\n for (const subdir of ['packages', 'apps']) {\n const subdirPath = path.join(absRepoPath, subdir);\n if (!fs.existsSync(subdirPath)) {continue;}\n for (const entry of fs.readdirSync(subdirPath)) {\n const pkgJsonPath = path.join(subdirPath, entry, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {results.push(pkgJsonPath);}\n }\n }\n return results;\n}\n","import { defineCommand, findRepoRoot, type PluginContextV3 } from '@kb-labs/sdk';\nimport { updateSnapshots } from '../../checks/api-compat-check.js';\n\ntype SnapshotInput = {\n path: string;\n};\n\nexport default defineCommand({\n id: 'policy:snapshot',\n description: 'Create or update the API snapshot for packages in a repo. Run after npm publish.',\n\n handler: {\n async execute(ctx: PluginContextV3, input: SnapshotInput): Promise<{ exitCode: number }> {\n const flags = (input as { flags?: SnapshotInput }).flags ?? input;\n\n if (!flags.path) {\n ctx.ui.error('--path is required. Example: pnpm kb policy snapshot --path=\"platform/kb-labs-sdk\"');\n return { exitCode: 1 };\n }\n\n const workspaceRoot = (await findRepoRoot(ctx.cwd)) ?? ctx.cwd;\n\n ctx.ui.info?.(`Extracting API snapshot for ${flags.path}...`);\n updateSnapshots(flags.path, workspaceRoot);\n ctx.ui.success?.('Snapshot updated', {\n sections: [\n {\n header: 'Info',\n items: [\n `Path: ${flags.path}`,\n `Snapshots saved to: .kb/api-snapshots/`,\n ],\n },\n ],\n });\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PolicyConfig, CategoryResult, CheckReport } from '@kb-labs/policy-contracts';
|
|
2
|
+
export { default as manifest } from './manifest.v3.js';
|
|
3
|
+
import '@kb-labs/perm-presets';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detects the category for a given repo path based on the policies config.
|
|
7
|
+
* Returns first matching category. If no match, returns category: null.
|
|
8
|
+
*/
|
|
9
|
+
declare function detectCategory(repoPath: string, config: PolicyConfig): CategoryResult;
|
|
10
|
+
/**
|
|
11
|
+
* Detects categories for multiple repo paths.
|
|
12
|
+
*/
|
|
13
|
+
declare function detectCategories(repoPaths: string[], config: PolicyConfig): CategoryResult[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Scans all packages in the workspace and returns a map of packageName → category.
|
|
17
|
+
* Also returns full PackageInfo for more detailed lookups.
|
|
18
|
+
*/
|
|
19
|
+
declare function buildPackageMap(workspaceRoot: string, config: PolicyConfig): Map<string, string | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns all packages in a specific repo (by repo path relative to workspaceRoot).
|
|
22
|
+
*/
|
|
23
|
+
declare function getRepoPackageNames(workspaceRoot: string, repoPath: string): string[];
|
|
24
|
+
|
|
25
|
+
declare function runChecks(repos: CategoryResult[], config: PolicyConfig, workspaceRoot: string): Promise<CheckReport>;
|
|
26
|
+
|
|
27
|
+
export { buildPackageMap, detectCategories, detectCategory, getRepoPackageNames, runChecks };
|