@lsctech/polaris 0.5.0 → 0.5.3

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.
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.qcResultSchema = exports.qcPolicyDecisionSchema = exports.qcFindingSchema = exports.qcAttributionSchema = exports.qcCodeRangeSchema = exports.qcAttributionReasonSchema = exports.qcAttributionConfidenceSchema = exports.qcRoutingDecisionSchema = exports.qcFindingStatusSchema = exports.qcSeveritySchema = void 0;
4
+ exports.validateQcResult = validateQcResult;
5
+ exports.validateQcFinding = validateQcFinding;
6
+ const zod_1 = require("zod");
7
+ exports.qcSeveritySchema = zod_1.z.enum(["critical", "high", "medium", "low", "info"]);
8
+ exports.qcFindingStatusSchema = zod_1.z.enum([
9
+ "open",
10
+ "autofixed",
11
+ "repaired",
12
+ "waived",
13
+ "follow-up",
14
+ ]);
15
+ exports.qcRoutingDecisionSchema = zod_1.z.enum([
16
+ "original-worker",
17
+ "repair-worker",
18
+ "follow-up",
19
+ "operator-review",
20
+ ]);
21
+ exports.qcAttributionConfidenceSchema = zod_1.z.enum([
22
+ "high",
23
+ "medium",
24
+ "low",
25
+ "unattributed",
26
+ ]);
27
+ exports.qcAttributionReasonSchema = zod_1.z.enum([
28
+ "commit-line-match",
29
+ "changed-file-owner",
30
+ "child-scope-match",
31
+ "shared-file",
32
+ "pre-existing",
33
+ "provider-uncertain",
34
+ "unattributed",
35
+ ]);
36
+ exports.qcCodeRangeSchema = zod_1.z.object({
37
+ startLine: zod_1.z.number().int().positive(),
38
+ startColumn: zod_1.z.number().int().positive().optional(),
39
+ endLine: zod_1.z.number().int().positive().optional(),
40
+ endColumn: zod_1.z.number().int().positive().optional(),
41
+ });
42
+ exports.qcAttributionSchema = zod_1.z.object({
43
+ confidence: exports.qcAttributionConfidenceSchema,
44
+ reason: exports.qcAttributionReasonSchema,
45
+ childId: zod_1.z.string().optional(),
46
+ filePath: zod_1.z.string().optional(),
47
+ commitSha: zod_1.z.string().optional(),
48
+ });
49
+ exports.qcFindingSchema = zod_1.z.object({
50
+ findingId: zod_1.z.string(),
51
+ providerFindingId: zod_1.z.string().optional(),
52
+ severity: exports.qcSeveritySchema,
53
+ category: zod_1.z.string().optional(),
54
+ title: zod_1.z.string(),
55
+ message: zod_1.z.string().optional(),
56
+ filePath: zod_1.z.string().optional(),
57
+ commitSha: zod_1.z.string().optional(),
58
+ range: exports.qcCodeRangeSchema.optional(),
59
+ confidence: zod_1.z.number().min(0).max(1).optional(),
60
+ suggestedAction: zod_1.z.string().optional(),
61
+ fixAvailable: zod_1.z.boolean(),
62
+ autofixEligible: zod_1.z.boolean(),
63
+ attribution: exports.qcAttributionSchema,
64
+ routingDecision: exports.qcRoutingDecisionSchema.optional(),
65
+ status: exports.qcFindingStatusSchema,
66
+ });
67
+ exports.qcPolicyDecisionSchema = zod_1.z.object({
68
+ blocksDelivery: zod_1.z.boolean(),
69
+ requiresOperatorReview: zod_1.z.boolean(),
70
+ routedToRepair: zod_1.z.boolean(),
71
+ summary: zod_1.z.string(),
72
+ });
73
+ exports.qcResultSchema = zod_1.z.object({
74
+ schemaVersion: zod_1.z.string(),
75
+ qcRunId: zod_1.z.string(),
76
+ runId: zod_1.z.string(),
77
+ clusterId: zod_1.z.string(),
78
+ trigger: zod_1.z.enum(["pr", "completed-cluster", "child"]),
79
+ provider: zod_1.z.string(),
80
+ providerMode: zod_1.z.enum(["local", "pr", "metrics-import"]),
81
+ prUrl: zod_1.z.string().optional(),
82
+ startedAt: zod_1.z.string().datetime(),
83
+ completedAt: zod_1.z.string().datetime(),
84
+ status: zod_1.z.enum(["passed", "findings", "blocked", "failed", "skipped"]),
85
+ findings: zod_1.z.array(exports.qcFindingSchema),
86
+ rawArtifactPaths: zod_1.z.array(zod_1.z.string()),
87
+ parserVersion: zod_1.z.string(),
88
+ policyDecision: exports.qcPolicyDecisionSchema,
89
+ });
90
+ /**
91
+ * Validate an unknown value as a normalized QC result.
92
+ * Returns a typed result on success or a Zod-safe parsed error on failure.
93
+ */
94
+ function validateQcResult(value) {
95
+ const parsed = exports.qcResultSchema.safeParse(value);
96
+ if (parsed.success) {
97
+ return { success: true, result: parsed.data };
98
+ }
99
+ return { success: false, errors: parsed.error.issues.map((issue) => issue.message) };
100
+ }
101
+ /**
102
+ * Validate an unknown value as a normalized QC finding.
103
+ */
104
+ function validateQcFinding(value) {
105
+ const parsed = exports.qcFindingSchema.safeParse(value);
106
+ if (parsed.success) {
107
+ return { success: true, finding: parsed.data };
108
+ }
109
+ return { success: false, errors: parsed.error.issues.map((issue) => issue.message) };
110
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECURITY_CATEGORY_PATTERN = void 0;
4
+ exports.isSecurityCategory = isSecurityCategory;
5
+ /** Shared QC security-category classification. */
6
+ exports.SECURITY_CATEGORY_PATTERN = /security|secret|vulnerability|vuln|auth|crypto|injection|xss|csrf|sql/i;
7
+ function isSecurityCategory(category) {
8
+ if (!category)
9
+ return false;
10
+ return exports.SECURITY_CATEGORY_PATTERN.test(category);
11
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SEVERITY_ORDER = exports.DEFAULT_SEVERITY_MAPPING = void 0;
4
+ exports.normalizeSeverity = normalizeSeverity;
5
+ exports.compareSeverity = compareSeverity;
6
+ exports.maxSeverity = maxSeverity;
7
+ /**
8
+ * Built-in severity label mappings for common QC providers.
9
+ * Provider-specific configs can override these.
10
+ */
11
+ exports.DEFAULT_SEVERITY_MAPPING = {
12
+ // Common explicit labels
13
+ critical: "critical",
14
+ severe: "critical",
15
+ blocker: "critical",
16
+ high: "high",
17
+ major: "high",
18
+ error: "high",
19
+ medium: "medium",
20
+ moderate: "medium",
21
+ warning: "medium",
22
+ low: "low",
23
+ minor: "low",
24
+ info: "info",
25
+ informational: "info",
26
+ note: "info",
27
+ suggestion: "info",
28
+ // CodeRabbit-style labels
29
+ "needs-action": "high",
30
+ "needs-review": "medium",
31
+ nitpick: "low",
32
+ };
33
+ /**
34
+ * Normalize a provider severity label into a Polaris severity level.
35
+ * Unknown or empty labels fall back to "info" so that nothing is silently lost.
36
+ */
37
+ function normalizeSeverity(label, mapping) {
38
+ const raw = (label ?? "").toString().trim().toLowerCase();
39
+ if (!raw) {
40
+ return "info";
41
+ }
42
+ const combined = { ...exports.DEFAULT_SEVERITY_MAPPING, ...mapping };
43
+ if (Object.hasOwn(combined, raw)) {
44
+ return combined[raw];
45
+ }
46
+ // Substring fallbacks for noisy provider labels
47
+ if (raw.includes("critical") || raw.includes("severe") || raw.includes("blocker")) {
48
+ return "critical";
49
+ }
50
+ if (raw.includes("high") || raw.includes("major") || raw.includes("error")) {
51
+ return "high";
52
+ }
53
+ if (raw.includes("medium") || raw.includes("moderate") || raw.includes("warning")) {
54
+ return "medium";
55
+ }
56
+ if (raw.includes("low") || raw.includes("minor") || raw.includes("nitpick")) {
57
+ return "low";
58
+ }
59
+ if (raw.includes("info") || raw.includes("note") || raw.includes("suggestion")) {
60
+ return "info";
61
+ }
62
+ return "info";
63
+ }
64
+ /** Ordered severity levels from least to most severe. */
65
+ exports.SEVERITY_ORDER = ["info", "low", "medium", "high", "critical"];
66
+ /**
67
+ * Compare two severities. Returns negative if a is less severe than b,
68
+ * positive if more severe, or zero if equal.
69
+ */
70
+ function compareSeverity(a, b) {
71
+ return exports.SEVERITY_ORDER.indexOf(a) - exports.SEVERITY_ORDER.indexOf(b);
72
+ }
73
+ /**
74
+ * Return the more severe of two severity levels.
75
+ */
76
+ function maxSeverity(a, b) {
77
+ return compareSeverity(a, b) >= 0 ? a : b;
78
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ /**
3
+ * QC trigger selection logic.
4
+ *
5
+ * Decides which lifecycle trigger a configured provider participates in, and
6
+ * whether child-level QC should be selected for a given dispatch.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.effectiveProviderTrigger = effectiveProviderTrigger;
10
+ exports.activeProvidersForTrigger = activeProvidersForTrigger;
11
+ exports.isHighRiskScope = isHighRiskScope;
12
+ exports.isChildQcSelected = isChildQcSelected;
13
+ exports.selectChildQcTrigger = selectChildQcTrigger;
14
+ /** High-risk scope patterns that make a child eligible for child-level QC. */
15
+ const HIGH_RISK_SCOPE_PATTERNS = [
16
+ /src\/auth/i,
17
+ /src\/security/i,
18
+ /src\/payments/i,
19
+ /src\/crypto/i,
20
+ /src\/db/i,
21
+ /src\/database/i,
22
+ /src\/api/i,
23
+ ];
24
+ /**
25
+ * Derive the effective trigger for a provider.
26
+ * Falls back to a sensible default derived from the provider mode, then the
27
+ * cluster-wide default trigger.
28
+ */
29
+ function effectiveProviderTrigger(provider, defaultTrigger) {
30
+ if (provider.trigger)
31
+ return provider.trigger;
32
+ switch (provider.mode) {
33
+ case "pr":
34
+ return "pr";
35
+ case "local":
36
+ return "completed-cluster";
37
+ case "metrics-import":
38
+ return "completed-cluster";
39
+ default:
40
+ return defaultTrigger;
41
+ }
42
+ }
43
+ /**
44
+ * Return configured providers that participate in the given trigger.
45
+ */
46
+ function activeProvidersForTrigger(config, trigger) {
47
+ if (!config?.enabled)
48
+ return [];
49
+ const defaultTrigger = config.defaultTrigger ?? "completed-cluster";
50
+ return Object.entries(config.providers ?? {}).filter(([, provider]) => {
51
+ return effectiveProviderTrigger(provider, defaultTrigger) === trigger;
52
+ });
53
+ }
54
+ /**
55
+ * Returns true when a scope touches files generally considered high-risk.
56
+ */
57
+ function isHighRiskScope(scope) {
58
+ return scope.some((pattern) => HIGH_RISK_SCOPE_PATTERNS.some((re) => re.test(pattern)));
59
+ }
60
+ /**
61
+ * Decide whether child-level QC should be selected for a child.
62
+ *
63
+ * Child-level QC is intentionally opt-in. It is selected only when:
64
+ * - QC is enabled and at least one provider is configured for the child trigger.
65
+ * - A route policy explicitly enables child-level QC for this route, OR
66
+ * - The child is explicitly tagged with "qc-child", OR
67
+ * - The child's scope contains high-risk paths (auth, security, payments, etc.).
68
+ */
69
+ function isChildQcSelected(config, childId, allowedScope, labels, routeName) {
70
+ if (!config?.enabled)
71
+ return false;
72
+ const childProviders = activeProvidersForTrigger(config, "child");
73
+ if (childProviders.length === 0)
74
+ return false;
75
+ const routePolicy = routeName ? config.routes?.[routeName] : undefined;
76
+ if (routePolicy?.childLevel)
77
+ return true;
78
+ if (labels?.includes("qc-child"))
79
+ return true;
80
+ if (isHighRiskScope(allowedScope))
81
+ return true;
82
+ return false;
83
+ }
84
+ /**
85
+ * Select the QC trigger for a child dispatch.
86
+ * Returns "child" when child-level QC is selected, otherwise null.
87
+ */
88
+ function selectChildQcTrigger(config, childId, allowedScope, labels, routeName) {
89
+ return isChildQcSelected(config, childId, allowedScope, labels, routeName)
90
+ ? "child"
91
+ : null;
92
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * Provider-neutral Quality Control types.
4
+ *
5
+ * These types mirror the normalized finding schema defined in the QC architecture
6
+ * spec. They intentionally do not reference tracker-specific or provider-specific
7
+ * shapes so that Polaris can support multiple QC backends without vendor lock-in.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsctech/polaris",
3
- "version": "0.5.0",
3
+ "version": "0.5.3",
4
4
  "description": "Polaris — standalone taskchain orchestration framework for governed AI agent workflows",
5
5
  "bin": {
6
6
  "polaris": "dist/cli/index.js",