@kb-labs/policy-contracts 2.16.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/plugins/policy/contracts/src/schema.ts","../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/plugins/policy/contracts/src/error-codes.ts","../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/plugins/policy/contracts/src/format.ts","../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/plugins/policy/contracts/src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\nexport const PolicyRuleConfigSchema = z.object({\n description: z.string(),\n severity: z.enum(['error', 'warning']),\n config: z.record(z.unknown()).optional(),\n});\n\nexport const PolicyCategoryConfigSchema = z.object({\n paths: z.array(z.string()),\n rules: z.array(z.string()),\n});\n\nexport const PolicyConfigSchema = z.object({\n categories: z.record(PolicyCategoryConfigSchema),\n rules: z.record(PolicyRuleConfigSchema),\n});\n\nexport type PolicyConfigInput = z.input<typeof PolicyConfigSchema>;\n","/**\n * Canonical error codes for every policy violation type.\n *\n * Attach `code` to a `PolicyViolation` to enable programmatic discrimination\n * of violation kinds without parsing free-form message strings.\n *\n * All codes share the `POLICY_` prefix so they are unambiguous when mixed\n * with error codes from other subsystems.\n */\nexport const PolicyErrorCode = {\n /**\n * A package depends on another package that belongs to a category outside\n * the set of categories permitted for the depending package's own category.\n * Produced by the `boundary-check` rule.\n */\n BOUNDARY_VIOLATION: 'POLICY_BOUNDARY_VIOLATION',\n\n /**\n * A plugin package imports an internal platform package directly instead of\n * going through `@kb-labs/sdk`. Plugin packages must restrict their\n * `@kb-labs/*` dependencies exclusively to `@kb-labs/sdk`.\n * Produced by the `sdk-only-deps` rule.\n */\n SDK_ONLY_DEP_VIOLATION: 'POLICY_SDK_ONLY_DEP_VIOLATION',\n\n /**\n * The local `package.json` version is lower than the version already\n * published to the npm registry. Published versions may never be decreased.\n * Produced by the `no-rollback` rule.\n */\n VERSION_ROLLBACK: 'POLICY_VERSION_ROLLBACK',\n\n /**\n * One or more previously exported public symbols have been removed without\n * a corresponding major-version bump, constituting a breaking API change.\n * Produced by the `api-compat-check` / `no-breaking-without-major` rules.\n */\n API_BREAKING_CHANGE: 'POLICY_API_BREAKING_CHANGE',\n\n /**\n * A policy configuration references a rule name that has no registered\n * check implementation. The rule will be skipped at runtime.\n * Produced by the policy runner when an unknown rule key is encountered.\n */\n UNKNOWN_RULE: 'POLICY_UNKNOWN_RULE',\n} as const;\n\n/**\n * Union type of all valid `PolicyErrorCode` string values.\n * Use this as the type for `PolicyViolation.code`.\n */\nexport type PolicyErrorCode = (typeof PolicyErrorCode)[keyof typeof PolicyErrorCode];\n\n/**\n * Human-readable descriptions for each `PolicyErrorCode`.\n *\n * These are intended as stable reference messages for documentation,\n * tooling output, and IDE integrations. Individual violations also carry\n * a context-specific `message` and optional `detail` field on the\n * `PolicyViolation` object.\n */\nexport const POLICY_ERROR_MESSAGES: Readonly<Record<PolicyErrorCode, string>> = {\n [PolicyErrorCode.BOUNDARY_VIOLATION]:\n 'A package depends on another package outside its allowed category boundaries. ' +\n 'Each workspace category may only import packages from the explicitly permitted categories ' +\n 'listed in the policy configuration.',\n\n [PolicyErrorCode.SDK_ONLY_DEP_VIOLATION]:\n 'A plugin package imports an internal platform package directly instead of going through ' +\n '@kb-labs/sdk. Plugin packages must limit their @kb-labs/* dependencies to @kb-labs/sdk only. ' +\n 'Move required types and utilities to the SDK or use its re-exports.',\n\n [PolicyErrorCode.VERSION_ROLLBACK]:\n 'The local package.json version is lower than the version already published to the npm registry. ' +\n 'Versions may never be decreased once published — restore the version to the published value or ' +\n 'release a higher version.',\n\n [PolicyErrorCode.API_BREAKING_CHANGE]:\n 'One or more previously exported symbols have been removed without a corresponding major-version ' +\n 'bump. Either restore the removed symbols to preserve backward compatibility, or increment the ' +\n 'major version before removing them.',\n\n [PolicyErrorCode.UNKNOWN_RULE]:\n 'A policy rule reference was encountered that has no registered check implementation. ' +\n 'Verify that the rule name in the policy configuration exactly matches a supported rule ' +\n 'identifier (e.g. \"sdk-only-deps\", \"boundary-check\", \"no-rollback\", \"api-compat-check\").',\n};\n\n/**\n * Returns the stable descriptive message for a given `PolicyErrorCode`.\n *\n * @example\n * ```ts\n * const msg = getPolicyErrorMessage(PolicyErrorCode.BOUNDARY_VIOLATION);\n * // \"A package depends on another package outside its allowed category boundaries. …\"\n * ```\n */\nexport function getPolicyErrorMessage(code: PolicyErrorCode): string {\n return POLICY_ERROR_MESSAGES[code];\n}\n","import type { PolicyViolation } from './types.js';\n\n/**\n * Options that control which parts of a {@link PolicyViolation} are included\n * in the formatted string.\n */\nexport interface FormatViolationOptions {\n /**\n * Include the `file` field as a path hint when it is present.\n * @default true\n */\n includeFile?: boolean;\n\n /**\n * Include the `detail` field as an indented continuation line when present.\n * @default true\n */\n includeDetail?: boolean;\n\n /**\n * Include the `package` field as a parenthetical suffix on the first line\n * when it is present.\n * @default false\n */\n includePackage?: boolean;\n}\n\n/**\n * Formats a single {@link PolicyViolation} into a human-readable string that\n * mirrors the canonical CLI output produced by `policy:check`.\n *\n * The returned string is **never** terminated with a newline so callers can\n * join multiple violations however they like (e.g. `'\\n'` for terminal output,\n * `'<br>'` for HTML).\n *\n * Layout (each line only emitted when the corresponding field is present and\n * its option is enabled):\n *\n * ```\n * [severity] rule — message (package)\n * → detail\n * @ file\n * ```\n *\n * @example\n * ```ts\n * import { formatViolation } from '@kb-labs/policy-contracts';\n *\n * const line = formatViolation(violation);\n * // \"[error] boundary-check — pkg-a depends on pkg-b (category: plugins)\"\n *\n * const withDetail = formatViolation(violation, { includeDetail: true });\n * // \"[error] boundary-check — pkg-a depends on pkg-b (category: plugins)\\n → Category \"platform\" may only depend on: shared\"\n * ```\n */\nexport function formatViolation(\n violation: PolicyViolation,\n options: FormatViolationOptions = {},\n): string {\n const { includeFile = true, includeDetail = true, includePackage = false } = options;\n\n const packageSuffix =\n includePackage && violation.package ? ` (${violation.package})` : '';\n\n const firstLine = `[${violation.severity}] ${violation.rule} — ${violation.message}${packageSuffix}`;\n\n const lines: string[] = [firstLine];\n\n if (includeDetail && violation.detail) {\n lines.push(` → ${violation.detail}`);\n }\n\n if (includeFile && violation.file) {\n lines.push(` @ ${violation.file}`);\n }\n\n return lines.join('\\n');\n}\n","import type { CheckReport, PolicyViolation, RepoCheckResult } from './types.js';\n\n/**\n * A mapping from rule identifier to the total number of violations produced\n * by that rule across all inputs passed to {@link getViolationSummary}.\n *\n * Only rules that produced **at least one** violation appear as keys; rules\n * that passed cleanly are omitted so callers can use a simple\n * `Object.keys(summary).length === 0` emptiness check.\n *\n * @example\n * ```ts\n * const summary: ViolationSummary = { 'sdk-only-deps': 3, 'boundary-check': 1 };\n * ```\n */\nexport type ViolationSummary = Record<string, number>;\n\n/**\n * Counts the number of violations per rule across a flat array of\n * {@link PolicyViolation} objects.\n *\n * @example\n * ```ts\n * import { getViolationSummary } from '@kb-labs/policy-contracts';\n *\n * const violations: PolicyViolation[] = [\n * { rule: 'sdk-only-deps', severity: 'error', message: 'pkg-a imports core' },\n * { rule: 'boundary-check', severity: 'warning', message: 'pkg-b depends on plugins' },\n * { rule: 'sdk-only-deps', severity: 'error', message: 'pkg-c imports core' },\n * ];\n *\n * getViolationSummary(violations);\n * // → { 'sdk-only-deps': 2, 'boundary-check': 1 }\n * ```\n */\nexport function getViolationSummary(violations: PolicyViolation[]): ViolationSummary;\n\n/**\n * Counts the number of violations per rule for a single\n * {@link RepoCheckResult}.\n *\n * @example\n * ```ts\n * import { getViolationSummary } from '@kb-labs/policy-contracts';\n *\n * getViolationSummary(repoResult);\n * // → { 'boundary-check': 3 }\n * ```\n */\nexport function getViolationSummary(result: RepoCheckResult): ViolationSummary;\n\n/**\n * Counts the number of violations per rule across **all** repos in a\n * {@link CheckReport}, aggregating results from every\n * `report.repos[n].violations` array.\n *\n * @example\n * ```ts\n * import { getViolationSummary } from '@kb-labs/policy-contracts';\n *\n * getViolationSummary(report);\n * // → { 'sdk-only-deps': 5, 'no-rollback': 2 }\n * ```\n */\nexport function getViolationSummary(report: CheckReport): ViolationSummary;\n\nexport function getViolationSummary(\n input: PolicyViolation[] | RepoCheckResult | CheckReport,\n): ViolationSummary {\n let violations: PolicyViolation[];\n\n if (Array.isArray(input)) {\n // Overload 1: flat PolicyViolation[]\n violations = input;\n } else if ('repos' in input) {\n // Overload 3: CheckReport — `repos` is unique to CheckReport; RepoCheckResult does not have it\n violations = (input as CheckReport).repos.flatMap((r) => r.violations);\n } else {\n // Overload 2: RepoCheckResult\n violations = (input as RepoCheckResult).violations;\n }\n\n const summary: ViolationSummary = {};\n for (const v of violations) {\n summary[v.rule] = (summary[v.rule] ?? 0) + 1;\n }\n return summary;\n}\n\n\n/**\n * Returns `true` when every repo in the report passed all policy rules\n * (i.e. `report.passed === true`), `false` otherwise.\n *\n * @example\n * ```ts\n * import { isPolicyPassing } from '@kb-labs/policy-contracts';\n *\n * if (!isPolicyPassing(report)) {\n * process.exit(1);\n * }\n * ```\n */\nexport function isPolicyPassing(report: CheckReport): boolean {\n return report.passed;\n}\n\n\n/**\n * Merges multiple {@link CheckReport} objects into a single consolidated report.\n *\n * All `repos` arrays are concatenated in input order. The `summary` counters\n * (`total`, `passed`, `failed`, `violations`) are recomputed from the merged\n * repo list. The top-level `passed` flag is `true` only when the merged result\n * has **zero** violations.\n *\n * Repos that share the same `path` across different input reports are kept as\n * separate entries (concatenation, not deduplication). Callers who need\n * dedup-by-path can post-process the returned `repos` array.\n *\n * @example\n * ```ts\n * import { mergeViolations } from '@kb-labs/policy-contracts';\n *\n * const combined = mergeViolations([reportA, reportB]);\n * // combined.repos === [...reportA.repos, ...reportB.repos]\n * // combined.passed === (combined.summary.violations === 0)\n * ```\n */\nexport function mergeViolations(reports: CheckReport[]): CheckReport {\n const repos = reports.flatMap((r) => r.repos);\n const total = repos.length;\n const failed = repos.filter((r) => r.violations.length > 0).length;\n const passedRepos = total - failed;\n const violations = repos.reduce((acc, r) => acc + r.violations.length, 0);\n return {\n passed: violations === 0,\n repos,\n summary: { total, passed: passedRepos, failed, violations },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/error-codes.ts","../src/format.ts","../src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\nexport const PolicyRuleConfigSchema = z.object({\n description: z.string(),\n severity: z.enum(['error', 'warning']),\n config: z.record(z.unknown()).optional(),\n});\n\nexport const PolicyCategoryConfigSchema = z.object({\n paths: z.array(z.string()),\n rules: z.array(z.string()),\n});\n\nexport const PolicyConfigSchema = z.object({\n categories: z.record(PolicyCategoryConfigSchema),\n rules: z.record(PolicyRuleConfigSchema),\n});\n\nexport type PolicyConfigInput = z.input<typeof PolicyConfigSchema>;\n","/**\n * Canonical error codes for every policy violation type.\n *\n * Attach `code` to a `PolicyViolation` to enable programmatic discrimination\n * of violation kinds without parsing free-form message strings.\n *\n * All codes share the `POLICY_` prefix so they are unambiguous when mixed\n * with error codes from other subsystems.\n */\nexport const PolicyErrorCode = {\n /**\n * A package depends on another package that belongs to a category outside\n * the set of categories permitted for the depending package's own category.\n * Produced by the `boundary-check` rule.\n */\n BOUNDARY_VIOLATION: 'POLICY_BOUNDARY_VIOLATION',\n\n /**\n * A plugin package imports an internal platform package directly instead of\n * going through `@kb-labs/sdk`. Plugin packages must restrict their\n * `@kb-labs/*` dependencies exclusively to `@kb-labs/sdk`.\n * Produced by the `sdk-only-deps` rule.\n */\n SDK_ONLY_DEP_VIOLATION: 'POLICY_SDK_ONLY_DEP_VIOLATION',\n\n /**\n * The local `package.json` version is lower than the version already\n * published to the npm registry. Published versions may never be decreased.\n * Produced by the `no-rollback` rule.\n */\n VERSION_ROLLBACK: 'POLICY_VERSION_ROLLBACK',\n\n /**\n * One or more previously exported public symbols have been removed without\n * a corresponding major-version bump, constituting a breaking API change.\n * Produced by the `api-compat-check` / `no-breaking-without-major` rules.\n */\n API_BREAKING_CHANGE: 'POLICY_API_BREAKING_CHANGE',\n\n /**\n * A policy configuration references a rule name that has no registered\n * check implementation. The rule will be skipped at runtime.\n * Produced by the policy runner when an unknown rule key is encountered.\n */\n UNKNOWN_RULE: 'POLICY_UNKNOWN_RULE',\n} as const;\n\n/**\n * Union type of all valid `PolicyErrorCode` string values.\n * Use this as the type for `PolicyViolation.code`.\n */\nexport type PolicyErrorCode = (typeof PolicyErrorCode)[keyof typeof PolicyErrorCode];\n\n/**\n * Human-readable descriptions for each `PolicyErrorCode`.\n *\n * These are intended as stable reference messages for documentation,\n * tooling output, and IDE integrations. Individual violations also carry\n * a context-specific `message` and optional `detail` field on the\n * `PolicyViolation` object.\n */\nexport const POLICY_ERROR_MESSAGES: Readonly<Record<PolicyErrorCode, string>> = {\n [PolicyErrorCode.BOUNDARY_VIOLATION]:\n 'A package depends on another package outside its allowed category boundaries. ' +\n 'Each workspace category may only import packages from the explicitly permitted categories ' +\n 'listed in the policy configuration.',\n\n [PolicyErrorCode.SDK_ONLY_DEP_VIOLATION]:\n 'A plugin package imports an internal platform package directly instead of going through ' +\n '@kb-labs/sdk. Plugin packages must limit their @kb-labs/* dependencies to @kb-labs/sdk only. ' +\n 'Move required types and utilities to the SDK or use its re-exports.',\n\n [PolicyErrorCode.VERSION_ROLLBACK]:\n 'The local package.json version is lower than the version already published to the npm registry. ' +\n 'Versions may never be decreased once published — restore the version to the published value or ' +\n 'release a higher version.',\n\n [PolicyErrorCode.API_BREAKING_CHANGE]:\n 'One or more previously exported symbols have been removed without a corresponding major-version ' +\n 'bump. Either restore the removed symbols to preserve backward compatibility, or increment the ' +\n 'major version before removing them.',\n\n [PolicyErrorCode.UNKNOWN_RULE]:\n 'A policy rule reference was encountered that has no registered check implementation. ' +\n 'Verify that the rule name in the policy configuration exactly matches a supported rule ' +\n 'identifier (e.g. \"sdk-only-deps\", \"boundary-check\", \"no-rollback\", \"api-compat-check\").',\n};\n\n/**\n * Returns the stable descriptive message for a given `PolicyErrorCode`.\n *\n * @example\n * ```ts\n * const msg = getPolicyErrorMessage(PolicyErrorCode.BOUNDARY_VIOLATION);\n * // \"A package depends on another package outside its allowed category boundaries. …\"\n * ```\n */\nexport function getPolicyErrorMessage(code: PolicyErrorCode): string {\n return POLICY_ERROR_MESSAGES[code];\n}\n","import type { PolicyViolation } from './types.js';\n\n/**\n * Options that control which parts of a {@link PolicyViolation} are included\n * in the formatted string.\n */\nexport interface FormatViolationOptions {\n /**\n * Include the `file` field as a path hint when it is present.\n * @default true\n */\n includeFile?: boolean;\n\n /**\n * Include the `detail` field as an indented continuation line when present.\n * @default true\n */\n includeDetail?: boolean;\n\n /**\n * Include the `package` field as a parenthetical suffix on the first line\n * when it is present.\n * @default false\n */\n includePackage?: boolean;\n}\n\n/**\n * Formats a single {@link PolicyViolation} into a human-readable string that\n * mirrors the canonical CLI output produced by `policy:check`.\n *\n * The returned string is **never** terminated with a newline so callers can\n * join multiple violations however they like (e.g. `'\\n'` for terminal output,\n * `'<br>'` for HTML).\n *\n * Layout (each line only emitted when the corresponding field is present and\n * its option is enabled):\n *\n * ```\n * [severity] rule — message (package)\n * → detail\n * @ file\n * ```\n *\n * @example\n * ```ts\n * import { formatViolation } from '@kb-labs/policy-contracts';\n *\n * const line = formatViolation(violation);\n * // \"[error] boundary-check — pkg-a depends on pkg-b (category: plugins)\"\n *\n * const withDetail = formatViolation(violation, { includeDetail: true });\n * // \"[error] boundary-check — pkg-a depends on pkg-b (category: plugins)\\n → Category \"platform\" may only depend on: shared\"\n * ```\n */\nexport function formatViolation(\n violation: PolicyViolation,\n options: FormatViolationOptions = {},\n): string {\n const { includeFile = true, includeDetail = true, includePackage = false } = options;\n\n const packageSuffix =\n includePackage && violation.package ? ` (${violation.package})` : '';\n\n const firstLine = `[${violation.severity}] ${violation.rule} — ${violation.message}${packageSuffix}`;\n\n const lines: string[] = [firstLine];\n\n if (includeDetail && violation.detail) {\n lines.push(` → ${violation.detail}`);\n }\n\n if (includeFile && violation.file) {\n lines.push(` @ ${violation.file}`);\n }\n\n return lines.join('\\n');\n}\n","import type { CheckReport, PolicyViolation, RepoCheckResult } from './types.js';\n\n/**\n * A mapping from rule identifier to the total number of violations produced\n * by that rule across all inputs passed to {@link getViolationSummary}.\n *\n * Only rules that produced **at least one** violation appear as keys; rules\n * that passed cleanly are omitted so callers can use a simple\n * `Object.keys(summary).length === 0` emptiness check.\n *\n * @example\n * ```ts\n * const summary: ViolationSummary = { 'sdk-only-deps': 3, 'boundary-check': 1 };\n * ```\n */\nexport type ViolationSummary = Record<string, number>;\n\n/**\n * Counts the number of violations per rule across a flat array of\n * {@link PolicyViolation} objects.\n *\n * @example\n * ```ts\n * import { getViolationSummary } from '@kb-labs/policy-contracts';\n *\n * const violations: PolicyViolation[] = [\n * { rule: 'sdk-only-deps', severity: 'error', message: 'pkg-a imports core' },\n * { rule: 'boundary-check', severity: 'warning', message: 'pkg-b depends on plugins' },\n * { rule: 'sdk-only-deps', severity: 'error', message: 'pkg-c imports core' },\n * ];\n *\n * getViolationSummary(violations);\n * // → { 'sdk-only-deps': 2, 'boundary-check': 1 }\n * ```\n */\nexport function getViolationSummary(violations: PolicyViolation[]): ViolationSummary;\n\n/**\n * Counts the number of violations per rule for a single\n * {@link RepoCheckResult}.\n *\n * @example\n * ```ts\n * import { getViolationSummary } from '@kb-labs/policy-contracts';\n *\n * getViolationSummary(repoResult);\n * // → { 'boundary-check': 3 }\n * ```\n */\nexport function getViolationSummary(result: RepoCheckResult): ViolationSummary;\n\n/**\n * Counts the number of violations per rule across **all** repos in a\n * {@link CheckReport}, aggregating results from every\n * `report.repos[n].violations` array.\n *\n * @example\n * ```ts\n * import { getViolationSummary } from '@kb-labs/policy-contracts';\n *\n * getViolationSummary(report);\n * // → { 'sdk-only-deps': 5, 'no-rollback': 2 }\n * ```\n */\nexport function getViolationSummary(report: CheckReport): ViolationSummary;\n\nexport function getViolationSummary(\n input: PolicyViolation[] | RepoCheckResult | CheckReport,\n): ViolationSummary {\n let violations: PolicyViolation[];\n\n if (Array.isArray(input)) {\n // Overload 1: flat PolicyViolation[]\n violations = input;\n } else if ('repos' in input) {\n // Overload 3: CheckReport — `repos` is unique to CheckReport; RepoCheckResult does not have it\n violations = (input as CheckReport).repos.flatMap((r) => r.violations);\n } else {\n // Overload 2: RepoCheckResult\n violations = (input as RepoCheckResult).violations;\n }\n\n const summary: ViolationSummary = {};\n for (const v of violations) {\n summary[v.rule] = (summary[v.rule] ?? 0) + 1;\n }\n return summary;\n}\n\n\n/**\n * Returns `true` when every repo in the report passed all policy rules\n * (i.e. `report.passed === true`), `false` otherwise.\n *\n * @example\n * ```ts\n * import { isPolicyPassing } from '@kb-labs/policy-contracts';\n *\n * if (!isPolicyPassing(report)) {\n * process.exit(1);\n * }\n * ```\n */\nexport function isPolicyPassing(report: CheckReport): boolean {\n return report.passed;\n}\n\n\n/**\n * Merges multiple {@link CheckReport} objects into a single consolidated report.\n *\n * All `repos` arrays are concatenated in input order. The `summary` counters\n * (`total`, `passed`, `failed`, `violations`) are recomputed from the merged\n * repo list. The top-level `passed` flag is `true` only when the merged result\n * has **zero** violations.\n *\n * Repos that share the same `path` across different input reports are kept as\n * separate entries (concatenation, not deduplication). Callers who need\n * dedup-by-path can post-process the returned `repos` array.\n *\n * @example\n * ```ts\n * import { mergeViolations } from '@kb-labs/policy-contracts';\n *\n * const combined = mergeViolations([reportA, reportB]);\n * // combined.repos === [...reportA.repos, ...reportB.repos]\n * // combined.passed === (combined.summary.violations === 0)\n * ```\n */\nexport function mergeViolations(reports: CheckReport[]): CheckReport {\n const repos = reports.flatMap((r) => r.repos);\n const total = repos.length;\n const failed = repos.filter((r) => r.violations.length > 0).length;\n const passedRepos = total - failed;\n const violations = repos.reduce((acc, r) => acc + r.violations.length, 0);\n return {\n passed: violations === 0,\n repos,\n summary: { total, passed: passedRepos, failed, violations },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kb-labs/policy-contracts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Types, interfaces, and schemas for the KB Labs policy plugin.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"tsup": "^8.5.0",
|
|
26
26
|
"typescript": "^5.6.3",
|
|
27
27
|
"vitest": "^3.2.4",
|
|
28
|
-
"@kb-labs/devkit": "2.
|
|
28
|
+
"@kb-labs/devkit": "2.17.0"
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=20.0.0",
|