@kb-labs/policy-core 2.94.0 → 2.98.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.
@@ -137,6 +137,16 @@ var snapshot_default = defineCommand({
137
137
  id: "policy:snapshot",
138
138
  description: "Create or update the API snapshot for packages in a repo. Run after npm publish.",
139
139
  handler: {
140
+ async intent(_ctx, input) {
141
+ const flags = input.flags ?? input;
142
+ const path2 = flags.path ?? "(unknown)";
143
+ return {
144
+ summary: `Create or update API snapshot for "${path2}"`,
145
+ operations: [
146
+ { type: "create", resource: "file", details: { path: `.kb/api-snapshots/${path2}` } }
147
+ ]
148
+ };
149
+ },
140
150
  async execute(ctx, input) {
141
151
  const flags = input.flags ?? input;
142
152
  if (!flags.path) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/checks/symbol-extractor.ts","../../../src/checks/api-compat-check.ts","../../../src/cli/commands/snapshot.ts"],"names":[],"mappings":"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","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"]}
1
+ {"version":3,"sources":["../../../src/checks/symbol-extractor.ts","../../../src/checks/api-compat-check.ts","../../../src/cli/commands/snapshot.ts"],"names":["path"],"mappings":"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","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 intent(_ctx: PluginContextV3, input: SnapshotInput) {\n const flags = (input as { flags?: SnapshotInput }).flags ?? input;\n const path = flags.path ?? '(unknown)';\n return {\n summary: `Create or update API snapshot for \"${path}\"`,\n operations: [\n { type: 'create' as const, resource: 'file', details: { path: `.kb/api-snapshots/${path}` } },\n ],\n };\n },\n\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import { PolicyConfig, CategoryResult, CheckReport } from '@kb-labs/policy-contracts';
2
2
  export { default as manifest } from './manifest.v3.js';
3
- import '@kb-labs/perm-presets';
3
+ import '@kb-labs/plugin-contracts';
4
4
 
5
5
  /**
6
6
  * Detects the category for a given repo path based on the policies config.
package/dist/index.js CHANGED
@@ -566,18 +566,20 @@ var manifest = {
566
566
  configSection: "policy",
567
567
  display: {
568
568
  name: "Policy Enforcer",
569
- description: "Enforces workspace-level development policies per category. Detects repo categories, resolves applicable rules, and validates compliance.",
569
+ description: "Enforce workspace development policies",
570
570
  tags: ["policy", "governance", "boundaries", "sdk-only", "api-compat"]
571
571
  },
572
572
  cli: {
573
+ groupMeta: [
574
+ { path: "policy", describe: "Policy enforcement commands" }
575
+ ],
573
576
  commands: [
574
577
  {
575
- id: "policy:detect",
576
- group: "policy",
578
+ path: "policy detect",
577
579
  describe: "Detect policy category for changed or specified repos",
580
+ operationType: "analyze",
578
581
  longDescription: "Determines the category for repos based on git changes or a specified path, then resolves applicable policy rules.",
579
582
  handler: "./cli/commands/detect.js#default",
580
- handlerPath: "./cli/commands/detect.js",
581
583
  flags: defineCommandFlags({
582
584
  path: {
583
585
  type: "string",
@@ -592,12 +594,11 @@ var manifest = {
592
594
  permissions: detectPermissions
593
595
  },
594
596
  {
595
- id: "policy:check",
596
- group: "policy",
597
+ path: "policy check",
597
598
  describe: "Run policy checks for changed repos or a specific path",
599
+ operationType: "analyze",
598
600
  longDescription: "Runs all applicable policy rules for detected repos. Exits with code 1 on violations. Use in CI or pnpm done pipeline.",
599
601
  handler: "./cli/commands/check.js#default",
600
- handlerPath: "./cli/commands/check.js",
601
602
  flags: defineCommandFlags({
602
603
  path: {
603
604
  type: "string",
@@ -612,11 +613,10 @@ var manifest = {
612
613
  permissions: checkPermissions
613
614
  },
614
615
  {
615
- id: "policy:rules",
616
- group: "policy",
616
+ path: "policy rules",
617
617
  describe: "Show all configured policy rules and their categories",
618
+ operationType: "read",
618
619
  handler: "./cli/commands/rules.js#default",
619
- handlerPath: "./cli/commands/rules.js",
620
620
  flags: defineCommandFlags({
621
621
  json: {
622
622
  type: "boolean",
@@ -627,12 +627,11 @@ var manifest = {
627
627
  permissions: detectPermissions
628
628
  },
629
629
  {
630
- id: "policy:snapshot",
631
- group: "policy",
630
+ path: "policy snapshot",
632
631
  describe: "Create or update API snapshot for a repo (run after npm publish)",
632
+ operationType: "mutate",
633
633
  longDescription: "Extracts exported symbols from dist/*.d.ts files and saves them to .kb/api-snapshots/. Used by api-compat-check to detect breaking changes.",
634
634
  handler: "./cli/commands/snapshot.js#default",
635
- handlerPath: "./cli/commands/snapshot.js",
636
635
  flags: defineCommandFlags({
637
636
  path: {
638
637
  type: "string",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/category-resolver.ts","../src/core/index.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","../src/manifest.v3.ts"],"names":["path","fs","detectCategory","findPackageJsonPaths"],"mappings":"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","file":"index.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","export { detectCategory, detectCategories } from './category-resolver.js';\nexport { buildPackageMap, getRepoPackageNames } from './workspace-scanner.js';\nexport { runChecks } from './policy-runner.js';\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","import { defineCommandFlags, combinePermissions } from '@kb-labs/sdk';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withQuotas({\n timeoutMs: 60000,\n memoryMb: 256,\n })\n .build();\n\nconst detectPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withQuotas({ timeoutMs: 15000, memoryMb: 128 })\n .build();\n\nconst checkPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withFs({\n mode: 'readWrite',\n allow: ['.kb/api-snapshots/**'],\n })\n .withQuotas({ timeoutMs: 60000, memoryMb: 256 })\n .build();\n\nconst snapshotPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withFs({ mode: 'readWrite', allow: ['.kb/api-snapshots/**'] })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/policy',\n version: '0.1.0',\n\n configSection: 'policy',\n\n display: {\n name: 'Policy Enforcer',\n description:\n 'Enforces workspace-level development policies per category. Detects repo categories, resolves applicable rules, and validates compliance.',\n tags: ['policy', 'governance', 'boundaries', 'sdk-only', 'api-compat'],\n },\n\n cli: {\n commands: [\n {\n id: 'policy:detect',\n group: 'policy',\n describe: 'Detect policy category for changed or specified repos',\n longDescription:\n 'Determines the category for repos based on git changes or a specified path, then resolves applicable policy rules.',\n\n handler: './cli/commands/detect.js#default',\n handlerPath: './cli/commands/detect.js',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n id: 'policy:check',\n group: 'policy',\n describe: 'Run policy checks for changed repos or a specific path',\n longDescription:\n 'Runs all applicable policy rules for detected repos. Exits with code 1 on violations. Use in CI or pnpm done pipeline.',\n\n handler: './cli/commands/check.js#default',\n handlerPath: './cli/commands/check.js',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: checkPermissions,\n },\n {\n id: 'policy:rules',\n group: 'policy',\n describe: 'Show all configured policy rules and their categories',\n\n handler: './cli/commands/rules.js#default',\n handlerPath: './cli/commands/rules.js',\n\n flags: defineCommandFlags({\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n id: 'policy:snapshot',\n group: 'policy',\n describe: 'Create or update API snapshot for a repo (run after npm publish)',\n longDescription:\n 'Extracts exported symbols from dist/*.d.ts files and saves them to .kb/api-snapshots/. Used by api-compat-check to detect breaking changes.',\n\n handler: './cli/commands/snapshot.js#default',\n handlerPath: './cli/commands/snapshot.js',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path (relative to workspace root)',\n required: true,\n },\n }),\n\n permissions: snapshotPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
1
+ {"version":3,"sources":["../src/core/category-resolver.ts","../src/core/index.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","../src/manifest.v3.ts"],"names":["path","fs","detectCategory","findPackageJsonPaths"],"mappings":"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","file":"index.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","export { detectCategory, detectCategories } from './category-resolver.js';\nexport { buildPackageMap, getRepoPackageNames } from './workspace-scanner.js';\nexport { runChecks } from './policy-runner.js';\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","import { defineCommandFlags, combinePermissions } from '@kb-labs/sdk';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withQuotas({\n timeoutMs: 60000,\n memoryMb: 256,\n })\n .build();\n\nconst detectPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withQuotas({ timeoutMs: 15000, memoryMb: 128 })\n .build();\n\nconst checkPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withFs({\n mode: 'readWrite',\n allow: ['.kb/api-snapshots/**'],\n })\n .withQuotas({ timeoutMs: 60000, memoryMb: 256 })\n .build();\n\nconst snapshotPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withFs({ mode: 'readWrite', allow: ['.kb/api-snapshots/**'] })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/policy',\n version: '0.1.0',\n\n configSection: 'policy',\n\n display: {\n name: 'Policy Enforcer',\n description: 'Enforce workspace development policies',\n tags: ['policy', 'governance', 'boundaries', 'sdk-only', 'api-compat'],\n },\n\n cli: {\n groupMeta: [\n { path: 'policy', describe: 'Policy enforcement commands' },\n ],\n commands: [\n {\n path: 'policy detect',\n describe: 'Detect policy category for changed or specified repos',\n operationType: 'analyze' as const,\n longDescription:\n 'Determines the category for repos based on git changes or a specified path, then resolves applicable policy rules.',\n\n handler: './cli/commands/detect.js#default',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n path: 'policy check',\n describe: 'Run policy checks for changed repos or a specific path',\n operationType: 'analyze' as const,\n longDescription:\n 'Runs all applicable policy rules for detected repos. Exits with code 1 on violations. Use in CI or pnpm done pipeline.',\n\n handler: './cli/commands/check.js#default',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: checkPermissions,\n },\n {\n path: 'policy rules',\n describe: 'Show all configured policy rules and their categories',\n operationType: 'read' as const,\n\n handler: './cli/commands/rules.js#default',\n\n flags: defineCommandFlags({\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n path: 'policy snapshot',\n describe: 'Create or update API snapshot for a repo (run after npm publish)',\n operationType: 'mutate' as const,\n longDescription:\n 'Extracts exported symbols from dist/*.d.ts files and saves them to .kb/api-snapshots/. Used by api-compat-check to detect breaking changes.',\n\n handler: './cli/commands/snapshot.js#default',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path (relative to workspace root)',\n required: true,\n },\n }),\n\n permissions: snapshotPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
@@ -1,4 +1,4 @@
1
- import * as _kb_labs_perm_presets from '@kb-labs/perm-presets';
1
+ import * as _kb_labs_plugin_contracts from '@kb-labs/plugin-contracts';
2
2
 
3
3
  declare const manifest: {
4
4
  schema: string;
@@ -11,13 +11,16 @@ declare const manifest: {
11
11
  tags: string[];
12
12
  };
13
13
  cli: {
14
+ groupMeta: {
15
+ path: string;
16
+ describe: string;
17
+ }[];
14
18
  commands: ({
15
- id: string;
16
- group: string;
19
+ path: string;
17
20
  describe: string;
21
+ operationType: "analyze";
18
22
  longDescription: string;
19
23
  handler: string;
20
- handlerPath: string;
21
24
  flags: {
22
25
  name: string;
23
26
  type: "string" | "boolean" | "number" | "array";
@@ -27,13 +30,12 @@ declare const manifest: {
27
30
  choices?: string[];
28
31
  required?: boolean;
29
32
  }[];
30
- permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
33
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
31
34
  } | {
32
- id: string;
33
- group: string;
35
+ path: string;
34
36
  describe: string;
37
+ operationType: "read";
35
38
  handler: string;
36
- handlerPath: string;
37
39
  flags: {
38
40
  name: string;
39
41
  type: "string" | "boolean" | "number" | "array";
@@ -43,11 +45,27 @@ declare const manifest: {
43
45
  choices?: string[];
44
46
  required?: boolean;
45
47
  }[];
46
- permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
48
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
47
49
  longDescription?: undefined;
50
+ } | {
51
+ path: string;
52
+ describe: string;
53
+ operationType: "mutate";
54
+ longDescription: string;
55
+ handler: string;
56
+ flags: {
57
+ name: string;
58
+ type: "string" | "boolean" | "number" | "array";
59
+ alias?: string;
60
+ default?: unknown;
61
+ description?: string;
62
+ choices?: string[];
63
+ required?: boolean;
64
+ }[];
65
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
48
66
  })[];
49
67
  };
50
- permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
68
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
51
69
  };
52
70
 
53
71
  export { manifest as default, manifest };
@@ -24,18 +24,20 @@ var manifest = {
24
24
  configSection: "policy",
25
25
  display: {
26
26
  name: "Policy Enforcer",
27
- description: "Enforces workspace-level development policies per category. Detects repo categories, resolves applicable rules, and validates compliance.",
27
+ description: "Enforce workspace development policies",
28
28
  tags: ["policy", "governance", "boundaries", "sdk-only", "api-compat"]
29
29
  },
30
30
  cli: {
31
+ groupMeta: [
32
+ { path: "policy", describe: "Policy enforcement commands" }
33
+ ],
31
34
  commands: [
32
35
  {
33
- id: "policy:detect",
34
- group: "policy",
36
+ path: "policy detect",
35
37
  describe: "Detect policy category for changed or specified repos",
38
+ operationType: "analyze",
36
39
  longDescription: "Determines the category for repos based on git changes or a specified path, then resolves applicable policy rules.",
37
40
  handler: "./cli/commands/detect.js#default",
38
- handlerPath: "./cli/commands/detect.js",
39
41
  flags: defineCommandFlags({
40
42
  path: {
41
43
  type: "string",
@@ -50,12 +52,11 @@ var manifest = {
50
52
  permissions: detectPermissions
51
53
  },
52
54
  {
53
- id: "policy:check",
54
- group: "policy",
55
+ path: "policy check",
55
56
  describe: "Run policy checks for changed repos or a specific path",
57
+ operationType: "analyze",
56
58
  longDescription: "Runs all applicable policy rules for detected repos. Exits with code 1 on violations. Use in CI or pnpm done pipeline.",
57
59
  handler: "./cli/commands/check.js#default",
58
- handlerPath: "./cli/commands/check.js",
59
60
  flags: defineCommandFlags({
60
61
  path: {
61
62
  type: "string",
@@ -70,11 +71,10 @@ var manifest = {
70
71
  permissions: checkPermissions
71
72
  },
72
73
  {
73
- id: "policy:rules",
74
- group: "policy",
74
+ path: "policy rules",
75
75
  describe: "Show all configured policy rules and their categories",
76
+ operationType: "read",
76
77
  handler: "./cli/commands/rules.js#default",
77
- handlerPath: "./cli/commands/rules.js",
78
78
  flags: defineCommandFlags({
79
79
  json: {
80
80
  type: "boolean",
@@ -85,12 +85,11 @@ var manifest = {
85
85
  permissions: detectPermissions
86
86
  },
87
87
  {
88
- id: "policy:snapshot",
89
- group: "policy",
88
+ path: "policy snapshot",
90
89
  describe: "Create or update API snapshot for a repo (run after npm publish)",
90
+ operationType: "mutate",
91
91
  longDescription: "Extracts exported symbols from dist/*.d.ts files and saves them to .kb/api-snapshots/. Used by api-compat-check to detect breaking changes.",
92
92
  handler: "./cli/commands/snapshot.js#default",
93
- handlerPath: "./cli/commands/snapshot.js",
94
93
  flags: defineCommandFlags({
95
94
  path: {
96
95
  type: "string",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manifest.v3.ts"],"names":[],"mappings":"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","file":"manifest.v3.js","sourcesContent":["import { defineCommandFlags, combinePermissions } from '@kb-labs/sdk';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withQuotas({\n timeoutMs: 60000,\n memoryMb: 256,\n })\n .build();\n\nconst detectPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withQuotas({ timeoutMs: 15000, memoryMb: 128 })\n .build();\n\nconst checkPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withFs({\n mode: 'readWrite',\n allow: ['.kb/api-snapshots/**'],\n })\n .withQuotas({ timeoutMs: 60000, memoryMb: 256 })\n .build();\n\nconst snapshotPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withFs({ mode: 'readWrite', allow: ['.kb/api-snapshots/**'] })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/policy',\n version: '0.1.0',\n\n configSection: 'policy',\n\n display: {\n name: 'Policy Enforcer',\n description:\n 'Enforces workspace-level development policies per category. Detects repo categories, resolves applicable rules, and validates compliance.',\n tags: ['policy', 'governance', 'boundaries', 'sdk-only', 'api-compat'],\n },\n\n cli: {\n commands: [\n {\n id: 'policy:detect',\n group: 'policy',\n describe: 'Detect policy category for changed or specified repos',\n longDescription:\n 'Determines the category for repos based on git changes or a specified path, then resolves applicable policy rules.',\n\n handler: './cli/commands/detect.js#default',\n handlerPath: './cli/commands/detect.js',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n id: 'policy:check',\n group: 'policy',\n describe: 'Run policy checks for changed repos or a specific path',\n longDescription:\n 'Runs all applicable policy rules for detected repos. Exits with code 1 on violations. Use in CI or pnpm done pipeline.',\n\n handler: './cli/commands/check.js#default',\n handlerPath: './cli/commands/check.js',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: checkPermissions,\n },\n {\n id: 'policy:rules',\n group: 'policy',\n describe: 'Show all configured policy rules and their categories',\n\n handler: './cli/commands/rules.js#default',\n handlerPath: './cli/commands/rules.js',\n\n flags: defineCommandFlags({\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n id: 'policy:snapshot',\n group: 'policy',\n describe: 'Create or update API snapshot for a repo (run after npm publish)',\n longDescription:\n 'Extracts exported symbols from dist/*.d.ts files and saves them to .kb/api-snapshots/. Used by api-compat-check to detect breaking changes.',\n\n handler: './cli/commands/snapshot.js#default',\n handlerPath: './cli/commands/snapshot.js',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path (relative to workspace root)',\n required: true,\n },\n }),\n\n permissions: snapshotPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
1
+ {"version":3,"sources":["../src/manifest.v3.ts"],"names":[],"mappings":"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","file":"manifest.v3.js","sourcesContent":["import { defineCommandFlags, combinePermissions } from '@kb-labs/sdk';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withQuotas({\n timeoutMs: 60000,\n memoryMb: 256,\n })\n .build();\n\nconst detectPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withQuotas({ timeoutMs: 15000, memoryMb: 128 })\n .build();\n\nconst checkPermissions = combinePermissions()\n .withFs({\n mode: 'read',\n allow: ['.', '.kb/api-snapshots/**'],\n })\n .withFs({\n mode: 'readWrite',\n allow: ['.kb/api-snapshots/**'],\n })\n .withQuotas({ timeoutMs: 60000, memoryMb: 256 })\n .build();\n\nconst snapshotPermissions = combinePermissions()\n .withFs({ mode: 'read', allow: ['.'] })\n .withFs({ mode: 'readWrite', allow: ['.kb/api-snapshots/**'] })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/policy',\n version: '0.1.0',\n\n configSection: 'policy',\n\n display: {\n name: 'Policy Enforcer',\n description: 'Enforce workspace development policies',\n tags: ['policy', 'governance', 'boundaries', 'sdk-only', 'api-compat'],\n },\n\n cli: {\n groupMeta: [\n { path: 'policy', describe: 'Policy enforcement commands' },\n ],\n commands: [\n {\n path: 'policy detect',\n describe: 'Detect policy category for changed or specified repos',\n operationType: 'analyze' as const,\n longDescription:\n 'Determines the category for repos based on git changes or a specified path, then resolves applicable policy rules.',\n\n handler: './cli/commands/detect.js#default',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n path: 'policy check',\n describe: 'Run policy checks for changed repos or a specific path',\n operationType: 'analyze' as const,\n longDescription:\n 'Runs all applicable policy rules for detected repos. Exits with code 1 on violations. Use in CI or pnpm done pipeline.',\n\n handler: './cli/commands/check.js#default',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path to check (relative to workspace root). Defaults to git diff.',\n },\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: checkPermissions,\n },\n {\n path: 'policy rules',\n describe: 'Show all configured policy rules and their categories',\n operationType: 'read' as const,\n\n handler: './cli/commands/rules.js#default',\n\n flags: defineCommandFlags({\n json: {\n type: 'boolean',\n description: 'Output as JSON',\n default: false,\n },\n }),\n\n permissions: detectPermissions,\n },\n {\n path: 'policy snapshot',\n describe: 'Create or update API snapshot for a repo (run after npm publish)',\n operationType: 'mutate' as const,\n longDescription:\n 'Extracts exported symbols from dist/*.d.ts files and saves them to .kb/api-snapshots/. Used by api-compat-check to detect breaking changes.',\n\n handler: './cli/commands/snapshot.js#default',\n\n flags: defineCommandFlags({\n path: {\n type: 'string',\n description: 'Repo path (relative to workspace root)',\n required: true,\n },\n }),\n\n permissions: snapshotPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/policy-core",
3
3
  "description": "Core implementation for KB Labs policy plugin. Category resolver, policy runner, and checks.",
4
- "version": "2.94.0",
4
+ "version": "2.98.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -23,8 +23,8 @@
23
23
  "dependencies": {
24
24
  "semver": "^7.6.3",
25
25
  "zod": "^3.25.76",
26
- "@kb-labs/sdk": "2.21.2",
27
- "@kb-labs/policy-contracts": "2.94.0"
26
+ "@kb-labs/policy-contracts": "2.98.0",
27
+ "@kb-labs/sdk": "2.22.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^24.3.3",
@@ -32,8 +32,8 @@
32
32
  "rimraf": "^6.0.1",
33
33
  "tsup": "^8.5.0",
34
34
  "typescript": "^5.6.3",
35
- "vitest": "^3.2.4",
36
- "@kb-labs/devkit": "2.94.0"
35
+ "vitest": "^3.2.6",
36
+ "@kb-labs/devkit": "2.98.0"
37
37
  },
38
38
  "engines": {
39
39
  "node": ">=20.0.0",