@neurcode-ai/cli 0.10.1 → 0.12.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/.telemetry-bundle/dist/contracts.d.ts +1 -1
- package/README.md +74 -25
- package/dist/commands/remediate-export.js +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +36 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/verify-output.d.ts.map +1 -1
- package/dist/commands/verify-output.js +66 -4
- package/dist/commands/verify-output.js.map +1 -1
- package/dist/commands/verify.d.ts +22 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +446 -34
- package/dist/commands/verify.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +4 -0
- package/dist/daemon/server.js.map +1 -1
- package/dist/governance/intent/drift-detector.d.ts +100 -0
- package/dist/governance/intent/drift-detector.d.ts.map +1 -0
- package/dist/governance/intent/drift-detector.js +275 -0
- package/dist/governance/intent/drift-detector.js.map +1 -0
- package/dist/governance/intent/glob-match.d.ts +43 -0
- package/dist/governance/intent/glob-match.d.ts.map +1 -0
- package/dist/governance/intent/glob-match.js +108 -0
- package/dist/governance/intent/glob-match.js.map +1 -0
- package/dist/governance/intent/import-graph.d.ts +56 -0
- package/dist/governance/intent/import-graph.d.ts.map +1 -0
- package/dist/governance/intent/import-graph.js +133 -0
- package/dist/governance/intent/import-graph.js.map +1 -0
- package/dist/governance/intent/index.d.ts +23 -0
- package/dist/governance/intent/index.d.ts.map +1 -0
- package/dist/governance/intent/index.js +48 -0
- package/dist/governance/intent/index.js.map +1 -0
- package/dist/governance/intent/intelligence-boundaries.d.ts +69 -0
- package/dist/governance/intent/intelligence-boundaries.d.ts.map +1 -0
- package/dist/governance/intent/intelligence-boundaries.js +163 -0
- package/dist/governance/intent/intelligence-boundaries.js.map +1 -0
- package/dist/governance/intent/intent-contract.d.ts +76 -0
- package/dist/governance/intent/intent-contract.d.ts.map +1 -0
- package/dist/governance/intent/intent-contract.js +397 -0
- package/dist/governance/intent/intent-contract.js.map +1 -0
- package/dist/governance/intent/intent-graph.d.ts +135 -0
- package/dist/governance/intent/intent-graph.d.ts.map +1 -0
- package/dist/governance/intent/intent-graph.js +67 -0
- package/dist/governance/intent/intent-graph.js.map +1 -0
- package/dist/governance/pipeline/computation-trace.d.ts +52 -0
- package/dist/governance/pipeline/computation-trace.d.ts.map +1 -0
- package/dist/governance/pipeline/computation-trace.js +79 -0
- package/dist/governance/pipeline/computation-trace.js.map +1 -0
- package/dist/governance/pipeline/envelope-assembly.d.ts +132 -0
- package/dist/governance/pipeline/envelope-assembly.d.ts.map +1 -0
- package/dist/governance/pipeline/envelope-assembly.js +140 -0
- package/dist/governance/pipeline/envelope-assembly.js.map +1 -0
- package/dist/governance/pipeline/fingerprint.d.ts +34 -0
- package/dist/governance/pipeline/fingerprint.d.ts.map +1 -0
- package/dist/governance/pipeline/fingerprint.js +78 -0
- package/dist/governance/pipeline/fingerprint.js.map +1 -0
- package/dist/governance/pipeline/helpers.d.ts +74 -0
- package/dist/governance/pipeline/helpers.d.ts.map +1 -0
- package/dist/governance/pipeline/helpers.js +112 -0
- package/dist/governance/pipeline/helpers.js.map +1 -0
- package/dist/governance/pipeline/index.d.ts +27 -0
- package/dist/governance/pipeline/index.d.ts.map +1 -0
- package/dist/governance/pipeline/index.js +63 -0
- package/dist/governance/pipeline/index.js.map +1 -0
- package/dist/governance/pipeline/lineage.d.ts +26 -0
- package/dist/governance/pipeline/lineage.d.ts.map +1 -0
- package/dist/governance/pipeline/lineage.js +51 -0
- package/dist/governance/pipeline/lineage.js.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.d.ts +15 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.js +44 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.js.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.d.ts +102 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.js +170 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.js.map +1 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.d.ts +133 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.js +125 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.js.map +1 -0
- package/dist/governance/pipeline/orchestration/index.d.ts +16 -0
- package/dist/governance/pipeline/orchestration/index.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/index.js +30 -0
- package/dist/governance/pipeline/orchestration/index.js.map +1 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.d.ts +65 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.js +102 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.js.map +1 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.d.ts +41 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.js +74 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.js.map +1 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.d.ts +165 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.js +160 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.js.map +1 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.d.ts +152 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.js +188 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.js.map +1 -0
- package/dist/governance/pipeline/runtime.d.ts +70 -0
- package/dist/governance/pipeline/runtime.d.ts.map +1 -0
- package/dist/governance/pipeline/runtime.js +223 -0
- package/dist/governance/pipeline/runtime.js.map +1 -0
- package/dist/governance/pipeline/shared-types.d.ts +7 -0
- package/dist/governance/pipeline/shared-types.d.ts.map +1 -0
- package/dist/governance/pipeline/shared-types.js +7 -0
- package/dist/governance/pipeline/shared-types.js.map +1 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.d.ts +28 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.js +53 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.d.ts +63 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.js +140 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.d.ts +53 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.js +129 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/index.d.ts +29 -0
- package/dist/governance/pipeline/stages/index.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/index.js +40 -0
- package/dist/governance/pipeline/stages/index.js.map +1 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.d.ts +31 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.js +71 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.d.ts +29 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.js +65 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.d.ts +24 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.js +58 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.js.map +1 -0
- package/dist/governance/pipeline/summary.d.ts +14 -0
- package/dist/governance/pipeline/summary.d.ts.map +1 -0
- package/dist/governance/pipeline/summary.js +50 -0
- package/dist/governance/pipeline/summary.js.map +1 -0
- package/dist/governance/pipeline/types.d.ts +69 -0
- package/dist/governance/pipeline/types.d.ts.map +1 -0
- package/dist/governance/pipeline/types.js +30 -0
- package/dist/governance/pipeline/types.js.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/active-engineering-context.d.ts +16 -0
- package/dist/utils/active-engineering-context.d.ts.map +1 -1
- package/dist/utils/active-engineering-context.js +302 -0
- package/dist/utils/active-engineering-context.js.map +1 -1
- package/dist/utils/import-edge-classifier.d.ts +76 -0
- package/dist/utils/import-edge-classifier.d.ts.map +1 -0
- package/dist/utils/import-edge-classifier.js +308 -0
- package/dist/utils/import-edge-classifier.js.map +1 -0
- package/dist/utils/import-edge-extractor.d.ts +52 -0
- package/dist/utils/import-edge-extractor.d.ts.map +1 -0
- package/dist/utils/import-edge-extractor.js +223 -0
- package/dist/utils/import-edge-extractor.js.map +1 -0
- package/dist/utils/import-edge-governance.d.ts +37 -0
- package/dist/utils/import-edge-governance.d.ts.map +1 -0
- package/dist/utils/import-edge-governance.js +56 -0
- package/dist/utils/import-edge-governance.js.map +1 -0
- package/dist/utils/path-boundary-classifier.d.ts +42 -0
- package/dist/utils/path-boundary-classifier.d.ts.map +1 -0
- package/dist/utils/path-boundary-classifier.js +143 -0
- package/dist/utils/path-boundary-classifier.js.map +1 -0
- package/dist/utils/replay-html-report.d.ts +29 -0
- package/dist/utils/replay-html-report.d.ts.map +1 -0
- package/dist/utils/replay-html-report.js +309 -0
- package/dist/utils/replay-html-report.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic import-edge classifier.
|
|
3
|
+
*
|
|
4
|
+
* Pure path arithmetic — no AST, no filesystem walks beyond explicit
|
|
5
|
+
* candidate-file existence checks, no probability. Same input always
|
|
6
|
+
* produces the same output.
|
|
7
|
+
*
|
|
8
|
+
* The classifier takes an `ImportEdge`, resolves it to one or more candidate
|
|
9
|
+
* repository paths, and matches those candidates against:
|
|
10
|
+
* - the explicit `forbiddenBoundaries` declared by the intent contract
|
|
11
|
+
* - the existing path-boundary classifier (generated-code, infra, ci,
|
|
12
|
+
* dependency-manifest, sensitive)
|
|
13
|
+
*
|
|
14
|
+
* Only edges whose target falls within a forbidden boundary OR a
|
|
15
|
+
* `review-required` boundary OR a generated-code path produce findings.
|
|
16
|
+
* Edges that resolve to unrelated, unflagged paths are silently skipped —
|
|
17
|
+
* they are signal-free.
|
|
18
|
+
*/
|
|
19
|
+
import type { ImportEdge, ImportLanguage } from './import-edge-extractor';
|
|
20
|
+
export type ImportEdgeSeverity = 'blocking' | 'advisory';
|
|
21
|
+
export type ImportEdgePolicy = 'forbidden' | 'review-required' | 'generated-code';
|
|
22
|
+
export type ImportEdgeBoundaryType = 'sensitive' | 'infra' | 'ci' | 'dependency-manifest' | 'service' | 'module' | 'generated-code' | 'unspecified';
|
|
23
|
+
export interface ImportEdgeFinding {
|
|
24
|
+
/** The diff file that introduced the new import. */
|
|
25
|
+
sourceFile: string;
|
|
26
|
+
/** 1-based line number where the import appeared. */
|
|
27
|
+
sourceLine: number;
|
|
28
|
+
/** Verbatim authored target text (e.g. `airflow.providers.celery.executors.celery_executor`). */
|
|
29
|
+
importTarget: string;
|
|
30
|
+
/** Repository-relative path the target resolved to, when known. */
|
|
31
|
+
resolvedTargetPath: string;
|
|
32
|
+
/** The forbidden-boundary or classifier path that matched. */
|
|
33
|
+
resolvedBoundary: string;
|
|
34
|
+
/** Boundary classification carried into the canonical envelope. */
|
|
35
|
+
boundaryType: ImportEdgeBoundaryType;
|
|
36
|
+
/** Governance policy applied to the edge. */
|
|
37
|
+
policy: ImportEdgePolicy;
|
|
38
|
+
/** Derived severity (forbidden → blocking, review-required → advisory). */
|
|
39
|
+
governanceSeverity: ImportEdgeSeverity;
|
|
40
|
+
/** Human reason copied from the intent boundary, when available. */
|
|
41
|
+
reason: string;
|
|
42
|
+
/** Edge kind echoed from the extractor (static / relative / dynamic / require / side-effect). */
|
|
43
|
+
edgeKind: 'static' | 'relative' | 'dynamic' | 'require' | 'side-effect';
|
|
44
|
+
language: ImportLanguage;
|
|
45
|
+
/** Guarantee markers — never inferred, always literal. */
|
|
46
|
+
deterministic: true;
|
|
47
|
+
replayStable: true;
|
|
48
|
+
}
|
|
49
|
+
export interface IntentForbiddenBoundary {
|
|
50
|
+
type: string;
|
|
51
|
+
path: string;
|
|
52
|
+
policy: 'forbidden' | 'review-required' | 'allowed';
|
|
53
|
+
reason?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface IntentApprovedScope {
|
|
56
|
+
files: readonly string[];
|
|
57
|
+
modules: readonly string[];
|
|
58
|
+
services: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
export interface IntentContextSnapshot {
|
|
61
|
+
approvedScope: IntentApprovedScope;
|
|
62
|
+
forbiddenBoundaries: readonly IntentForbiddenBoundary[];
|
|
63
|
+
}
|
|
64
|
+
/** Candidate repository-relative paths for an import edge, in priority order. */
|
|
65
|
+
export declare function candidatePathsForEdge(edge: ImportEdge, projectRoot: string, intent: IntentContextSnapshot): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Resolve an edge to a single ImportEdgeFinding, or null if the edge is
|
|
68
|
+
* either unresolvable or resolves outside any flagged boundary.
|
|
69
|
+
*
|
|
70
|
+
* Resolution priority:
|
|
71
|
+
* 1. Explicit `forbiddenBoundaries` (forbidden first, then review-required)
|
|
72
|
+
* 2. Path-boundary classifier (generated-code only — other classifier
|
|
73
|
+
* categories are diagnostic but not auto-blocking for imports)
|
|
74
|
+
*/
|
|
75
|
+
export declare function classifyImportEdge(edge: ImportEdge, projectRoot: string, intent: IntentContextSnapshot): ImportEdgeFinding | null;
|
|
76
|
+
//# sourceMappingURL=import-edge-classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-edge-classifier.d.ts","sourceRoot":"","sources":["../../src/utils/import-edge-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAO1E,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,UAAU,CAAC;AACzD,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAClF,MAAM,MAAM,sBAAsB,GAC9B,WAAW,GACX,OAAO,GACP,IAAI,GACJ,qBAAqB,GACrB,SAAS,GACT,QAAQ,GACR,gBAAgB,GAChB,aAAa,CAAC;AAElB,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,iGAAiG;IACjG,YAAY,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,YAAY,EAAE,sBAAsB,CAAC;IACrC,6CAA6C;IAC7C,MAAM,EAAE,gBAAgB,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,QAAQ,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;IACxE,QAAQ,EAAE,cAAc,CAAC;IACzB,0DAA0D;IAC1D,aAAa,EAAE,IAAI,CAAC;IACpB,YAAY,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,mBAAmB,CAAC;IACnC,mBAAmB,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACzD;AAUD,iFAAiF;AACjF,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,UAAU,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,qBAAqB,GAC5B,MAAM,EAAE,CAKV;AAkJD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,UAAU,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,qBAAqB,GAC5B,iBAAiB,GAAG,IAAI,CA8E1B"}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic import-edge classifier.
|
|
4
|
+
*
|
|
5
|
+
* Pure path arithmetic — no AST, no filesystem walks beyond explicit
|
|
6
|
+
* candidate-file existence checks, no probability. Same input always
|
|
7
|
+
* produces the same output.
|
|
8
|
+
*
|
|
9
|
+
* The classifier takes an `ImportEdge`, resolves it to one or more candidate
|
|
10
|
+
* repository paths, and matches those candidates against:
|
|
11
|
+
* - the explicit `forbiddenBoundaries` declared by the intent contract
|
|
12
|
+
* - the existing path-boundary classifier (generated-code, infra, ci,
|
|
13
|
+
* dependency-manifest, sensitive)
|
|
14
|
+
*
|
|
15
|
+
* Only edges whose target falls within a forbidden boundary OR a
|
|
16
|
+
* `review-required` boundary OR a generated-code path produce findings.
|
|
17
|
+
* Edges that resolve to unrelated, unflagged paths are silently skipped —
|
|
18
|
+
* they are signal-free.
|
|
19
|
+
*/
|
|
20
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
23
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
24
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(o, k2, desc);
|
|
27
|
+
}) : (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
o[k2] = m[k];
|
|
30
|
+
}));
|
|
31
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
+
}) : function(o, v) {
|
|
34
|
+
o["default"] = v;
|
|
35
|
+
});
|
|
36
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
+
var ownKeys = function(o) {
|
|
38
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
+
var ar = [];
|
|
40
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
+
return ar;
|
|
42
|
+
};
|
|
43
|
+
return ownKeys(o);
|
|
44
|
+
};
|
|
45
|
+
return function (mod) {
|
|
46
|
+
if (mod && mod.__esModule) return mod;
|
|
47
|
+
var result = {};
|
|
48
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
+
__setModuleDefault(result, mod);
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
})();
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.candidatePathsForEdge = candidatePathsForEdge;
|
|
55
|
+
exports.classifyImportEdge = classifyImportEdge;
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
const core_1 = require("@neurcode-ai/core");
|
|
59
|
+
const path_boundary_classifier_1 = require("./path-boundary-classifier");
|
|
60
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
61
|
+
// Resolution helpers
|
|
62
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
63
|
+
const PY_INIT = '__init__.py';
|
|
64
|
+
const PY_INIT_STUB = '__init__.pyi';
|
|
65
|
+
const PY_FILE_EXTS = ['.py', '.pyi'];
|
|
66
|
+
/** Candidate repository-relative paths for an import edge, in priority order. */
|
|
67
|
+
function candidatePathsForEdge(edge, projectRoot, intent) {
|
|
68
|
+
if (edge.language === 'python') {
|
|
69
|
+
return candidatesForPython(edge, projectRoot, intent);
|
|
70
|
+
}
|
|
71
|
+
return candidatesForJavaScript(edge, projectRoot);
|
|
72
|
+
}
|
|
73
|
+
function candidatesForPython(edge, projectRoot, intent) {
|
|
74
|
+
const out = [];
|
|
75
|
+
// Relative imports: `from .foo import x` / `from ..bar import y`
|
|
76
|
+
if (edge.relativeLevel > 0) {
|
|
77
|
+
const sourceDirParts = path.posix
|
|
78
|
+
.normalize(edge.sourceFile)
|
|
79
|
+
.split('/')
|
|
80
|
+
.slice(0, -1);
|
|
81
|
+
const goUp = Math.max(0, edge.relativeLevel - 1);
|
|
82
|
+
const base = sourceDirParts.slice(0, sourceDirParts.length - goUp);
|
|
83
|
+
const targetParts = edge.importTarget
|
|
84
|
+
.replace(/^\.+/, '')
|
|
85
|
+
.split('.')
|
|
86
|
+
.filter(Boolean);
|
|
87
|
+
const baseJoined = [...base, ...targetParts].join('/');
|
|
88
|
+
if (baseJoined) {
|
|
89
|
+
out.push(...materializePythonModulePaths(baseJoined, projectRoot));
|
|
90
|
+
}
|
|
91
|
+
return uniqueOrdered(out);
|
|
92
|
+
}
|
|
93
|
+
// Absolute imports: try several layout roots so monorepos (Airflow,
|
|
94
|
+
// Celery, etc.) and src/-style packages all resolve.
|
|
95
|
+
const dotted = edge.importTarget.split('.').filter(Boolean);
|
|
96
|
+
if (dotted.length === 0)
|
|
97
|
+
return out;
|
|
98
|
+
const moduleRel = dotted.join('/');
|
|
99
|
+
const layoutRoots = inferLayoutRoots(intent);
|
|
100
|
+
for (const rootPrefix of layoutRoots) {
|
|
101
|
+
const composed = rootPrefix ? `${rootPrefix}/${moduleRel}` : moduleRel;
|
|
102
|
+
out.push(...materializePythonModulePaths(composed, projectRoot));
|
|
103
|
+
}
|
|
104
|
+
return uniqueOrdered(out);
|
|
105
|
+
}
|
|
106
|
+
function materializePythonModulePaths(modulePath, projectRoot) {
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const ext of PY_FILE_EXTS) {
|
|
109
|
+
const candidate = `${modulePath}${ext}`;
|
|
110
|
+
if (existsAtRoot(projectRoot, candidate))
|
|
111
|
+
out.push(candidate);
|
|
112
|
+
}
|
|
113
|
+
for (const init of [PY_INIT, PY_INIT_STUB]) {
|
|
114
|
+
const candidate = `${modulePath}/${init}`;
|
|
115
|
+
if (existsAtRoot(projectRoot, candidate))
|
|
116
|
+
out.push(candidate);
|
|
117
|
+
}
|
|
118
|
+
// Always include the unresolved candidates for boundary matching even if
|
|
119
|
+
// the file does not physically exist (e.g. when intent forbids importing
|
|
120
|
+
// a not-yet-installed module).
|
|
121
|
+
for (const ext of PY_FILE_EXTS)
|
|
122
|
+
out.push(`${modulePath}${ext}`);
|
|
123
|
+
out.push(`${modulePath}/${PY_INIT}`);
|
|
124
|
+
out.push(modulePath);
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function candidatesForJavaScript(edge, projectRoot) {
|
|
128
|
+
const target = edge.importTarget;
|
|
129
|
+
// External packages: anything that does not start with `./`, `../`, `/`
|
|
130
|
+
// is treated as bare and skipped from boundary-match resolution.
|
|
131
|
+
if (!target.startsWith('.') && !target.startsWith('/'))
|
|
132
|
+
return [];
|
|
133
|
+
const sourceDirParts = path.posix
|
|
134
|
+
.normalize(edge.sourceFile)
|
|
135
|
+
.split('/')
|
|
136
|
+
.slice(0, -1);
|
|
137
|
+
const relative = target.startsWith('/') ? target.slice(1) : path.posix.normalize([...sourceDirParts, target].join('/'));
|
|
138
|
+
const exts = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const ext of exts) {
|
|
141
|
+
const candidate = `${relative}${ext}`;
|
|
142
|
+
if (existsAtRoot(projectRoot, candidate))
|
|
143
|
+
out.push(candidate);
|
|
144
|
+
out.push(candidate); // also include unresolved form for boundary matching
|
|
145
|
+
}
|
|
146
|
+
for (const indexFile of ['index.ts', 'index.tsx', 'index.js', 'index.jsx', 'index.mjs', 'index.cjs']) {
|
|
147
|
+
const candidate = `${relative}/${indexFile}`;
|
|
148
|
+
if (existsAtRoot(projectRoot, candidate))
|
|
149
|
+
out.push(candidate);
|
|
150
|
+
out.push(candidate);
|
|
151
|
+
}
|
|
152
|
+
out.push(relative);
|
|
153
|
+
return uniqueOrdered(out);
|
|
154
|
+
}
|
|
155
|
+
function inferLayoutRoots(intent) {
|
|
156
|
+
// Always include the bare root first; then derive additional layout
|
|
157
|
+
// prefixes from any approved module that ends in a canonical Python
|
|
158
|
+
// source root (`/src`). This is bounded and deterministic.
|
|
159
|
+
const roots = new Set(['']);
|
|
160
|
+
for (const mod of intent.approvedScope.modules) {
|
|
161
|
+
const normalized = (0, core_1.normalizeRepoPath)(mod);
|
|
162
|
+
if (!normalized)
|
|
163
|
+
continue;
|
|
164
|
+
const parts = normalized.split('/');
|
|
165
|
+
for (let i = 1; i <= parts.length; i++) {
|
|
166
|
+
const prefix = parts.slice(0, i).join('/');
|
|
167
|
+
// Common monorepo source roots:
|
|
168
|
+
// `airflow-core/src/airflow/jobs` → `airflow-core/src`
|
|
169
|
+
// `apps/api/src/foo` → `apps/api/src`
|
|
170
|
+
// `packages/core/src/util` → `packages/core/src`
|
|
171
|
+
if (prefix.endsWith('/src') || prefix === 'src')
|
|
172
|
+
roots.add(prefix);
|
|
173
|
+
}
|
|
174
|
+
// Whole-prefix mode: also useful for shallow projects (`apps/api`)
|
|
175
|
+
roots.add(normalized);
|
|
176
|
+
}
|
|
177
|
+
return [...roots].sort();
|
|
178
|
+
}
|
|
179
|
+
function existsAtRoot(projectRoot, repoRelative) {
|
|
180
|
+
try {
|
|
181
|
+
return fs.existsSync(path.join(projectRoot, repoRelative));
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function uniqueOrdered(values) {
|
|
188
|
+
const seen = new Set();
|
|
189
|
+
const out = [];
|
|
190
|
+
for (const v of values) {
|
|
191
|
+
if (seen.has(v))
|
|
192
|
+
continue;
|
|
193
|
+
seen.add(v);
|
|
194
|
+
out.push(v);
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
199
|
+
// Boundary matching
|
|
200
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
201
|
+
const ALLOWED_BOUNDARY_TYPES = new Set([
|
|
202
|
+
'sensitive', 'infra', 'ci', 'dependency-manifest', 'service', 'module', 'generated-code', 'unspecified',
|
|
203
|
+
]);
|
|
204
|
+
function asBoundaryType(value) {
|
|
205
|
+
if (value && ALLOWED_BOUNDARY_TYPES.has(value)) {
|
|
206
|
+
return value;
|
|
207
|
+
}
|
|
208
|
+
return 'unspecified';
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Resolve an edge to a single ImportEdgeFinding, or null if the edge is
|
|
212
|
+
* either unresolvable or resolves outside any flagged boundary.
|
|
213
|
+
*
|
|
214
|
+
* Resolution priority:
|
|
215
|
+
* 1. Explicit `forbiddenBoundaries` (forbidden first, then review-required)
|
|
216
|
+
* 2. Path-boundary classifier (generated-code only — other classifier
|
|
217
|
+
* categories are diagnostic but not auto-blocking for imports)
|
|
218
|
+
*/
|
|
219
|
+
function classifyImportEdge(edge, projectRoot, intent) {
|
|
220
|
+
const candidates = candidatePathsForEdge(edge, projectRoot, intent);
|
|
221
|
+
if (candidates.length === 0)
|
|
222
|
+
return null;
|
|
223
|
+
// Pre-normalise approved-scope so we can short-circuit edges that resolve
|
|
224
|
+
// inside the declared scope. An import from an allowed file *into* an
|
|
225
|
+
// allowed module is signal-free.
|
|
226
|
+
const approvedFileSet = new Set(intent.approvedScope.files.map((p) => (0, core_1.normalizeRepoPath)(p)).filter(Boolean));
|
|
227
|
+
const approvedModulePaths = intent.approvedScope.modules.map((p) => (0, core_1.normalizeRepoPath)(p)).filter(Boolean);
|
|
228
|
+
// First pass: forbidden boundaries (forbidden > review-required).
|
|
229
|
+
const forbiddenSorted = [...intent.forbiddenBoundaries].sort((a, b) => {
|
|
230
|
+
if (a.policy === b.policy)
|
|
231
|
+
return 0;
|
|
232
|
+
if (a.policy === 'forbidden')
|
|
233
|
+
return -1;
|
|
234
|
+
if (b.policy === 'forbidden')
|
|
235
|
+
return 1;
|
|
236
|
+
return 0;
|
|
237
|
+
});
|
|
238
|
+
for (const boundary of forbiddenSorted) {
|
|
239
|
+
if (boundary.policy === 'allowed')
|
|
240
|
+
continue;
|
|
241
|
+
const boundaryPath = (0, core_1.normalizeRepoPath)(boundary.path);
|
|
242
|
+
if (!boundaryPath)
|
|
243
|
+
continue;
|
|
244
|
+
for (const candidate of candidates) {
|
|
245
|
+
const normalized = (0, core_1.normalizeRepoPath)(candidate);
|
|
246
|
+
if (!normalized)
|
|
247
|
+
continue;
|
|
248
|
+
if (normalized === boundaryPath || normalized.startsWith(`${boundaryPath}/`)) {
|
|
249
|
+
// Skip if the resolved target is also inside the approved scope —
|
|
250
|
+
// that means the intent allowed the import explicitly.
|
|
251
|
+
if (approvedFileSet.has(normalized))
|
|
252
|
+
continue;
|
|
253
|
+
if (matchesPrefix(normalized, approvedModulePaths) && boundary.policy !== 'forbidden') {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
sourceFile: edge.sourceFile,
|
|
258
|
+
sourceLine: edge.sourceLine,
|
|
259
|
+
importTarget: edge.importTarget,
|
|
260
|
+
resolvedTargetPath: normalized,
|
|
261
|
+
resolvedBoundary: boundaryPath,
|
|
262
|
+
boundaryType: asBoundaryType(boundary.type),
|
|
263
|
+
policy: boundary.policy === 'forbidden' ? 'forbidden' : 'review-required',
|
|
264
|
+
governanceSeverity: boundary.policy === 'forbidden' ? 'blocking' : 'advisory',
|
|
265
|
+
reason: boundary.reason ?? `Import edge crosses ${boundary.type} boundary (${boundary.path}).`,
|
|
266
|
+
edgeKind: edge.importKind,
|
|
267
|
+
language: edge.language,
|
|
268
|
+
deterministic: true,
|
|
269
|
+
replayStable: true,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Second pass: generated-code classifier. Only fire if the target was not
|
|
275
|
+
// already explicitly allowed.
|
|
276
|
+
for (const candidate of candidates) {
|
|
277
|
+
const normalized = (0, core_1.normalizeRepoPath)(candidate);
|
|
278
|
+
if (!normalized)
|
|
279
|
+
continue;
|
|
280
|
+
if (approvedFileSet.has(normalized))
|
|
281
|
+
continue;
|
|
282
|
+
if (matchesPrefix(normalized, approvedModulePaths))
|
|
283
|
+
continue;
|
|
284
|
+
const classification = (0, path_boundary_classifier_1.classifyPathBoundary)(normalized);
|
|
285
|
+
if (classification?.category === 'generated-code') {
|
|
286
|
+
return {
|
|
287
|
+
sourceFile: edge.sourceFile,
|
|
288
|
+
sourceLine: edge.sourceLine,
|
|
289
|
+
importTarget: edge.importTarget,
|
|
290
|
+
resolvedTargetPath: normalized,
|
|
291
|
+
resolvedBoundary: normalized,
|
|
292
|
+
boundaryType: 'generated-code',
|
|
293
|
+
policy: 'generated-code',
|
|
294
|
+
governanceSeverity: 'blocking',
|
|
295
|
+
reason: `Import edge targets generated-code (${classification.reason}). Regenerate from source instead of importing from a hand-written path.`,
|
|
296
|
+
edgeKind: edge.importKind,
|
|
297
|
+
language: edge.language,
|
|
298
|
+
deterministic: true,
|
|
299
|
+
replayStable: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
function matchesPrefix(file, prefixes) {
|
|
306
|
+
return prefixes.some((p) => p && (file === p || file.startsWith(`${p}/`)));
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=import-edge-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-edge-classifier.js","sourceRoot":"","sources":["../../src/utils/import-edge-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic import-edge extractor.
|
|
3
|
+
*
|
|
4
|
+
* Pure regex over source lines — no AST, no inference, no probability.
|
|
5
|
+
* Same input always produces the same output, in the same canonical order.
|
|
6
|
+
*
|
|
7
|
+
* Supported languages:
|
|
8
|
+
* - Python: `import x.y.z`, `from x.y import z`, relative `from .foo import bar`
|
|
9
|
+
* - TypeScript / JavaScript:
|
|
10
|
+
* `import ... from "..."`
|
|
11
|
+
* `import "..."` (side-effect)
|
|
12
|
+
* `import("...")` (dynamic)
|
|
13
|
+
* `require("...")` (CommonJS)
|
|
14
|
+
*
|
|
15
|
+
* The extractor is diff-aware: it consumes already-added source lines so we
|
|
16
|
+
* only flag imports introduced by the current diff. Pre-existing imports
|
|
17
|
+
* stay outside the governance frame.
|
|
18
|
+
*/
|
|
19
|
+
import type { DiffFile } from '@neurcode-ai/diff-parser';
|
|
20
|
+
export type ImportLanguage = 'python' | 'typescript' | 'javascript';
|
|
21
|
+
export type ImportEdgeKind = 'static' | 'relative' | 'dynamic' | 'require' | 'side-effect';
|
|
22
|
+
export interface ImportEdge {
|
|
23
|
+
/** The diff file that contains the new import line. */
|
|
24
|
+
sourceFile: string;
|
|
25
|
+
/** 1-based line number within sourceFile, where deterministically known. */
|
|
26
|
+
sourceLine: number;
|
|
27
|
+
/** Verbatim text of the import-bearing line (trimmed). */
|
|
28
|
+
importStatement: string;
|
|
29
|
+
/**
|
|
30
|
+
* The raw import target as authored.
|
|
31
|
+
* - Python: `x.y.z`, `.foo`, `..foo.bar`
|
|
32
|
+
* - TS/JS: `./bar`, `../baz`, `@org/pkg/sub`, `node:fs`
|
|
33
|
+
*/
|
|
34
|
+
importTarget: string;
|
|
35
|
+
importKind: ImportEdgeKind;
|
|
36
|
+
language: ImportLanguage;
|
|
37
|
+
/** Number of leading dots for Python relative imports; 0 otherwise. */
|
|
38
|
+
relativeLevel: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract import edges from the added lines of a diff. Deterministic and
|
|
42
|
+
* order-stable: identical diffs yield identical edge arrays.
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractImportEdgesFromDiff(diffFiles: readonly DiffFile[]): ImportEdge[];
|
|
45
|
+
/**
|
|
46
|
+
* Sort edges into a canonical, replay-stable order.
|
|
47
|
+
*
|
|
48
|
+
* Order: sourceFile → importTarget → sourceLine → importKind. Identical
|
|
49
|
+
* tuples are deduplicated.
|
|
50
|
+
*/
|
|
51
|
+
export declare function canonicalizeEdges(edges: readonly ImportEdge[]): ImportEdge[];
|
|
52
|
+
//# sourceMappingURL=import-edge-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-edge-extractor.d.ts","sourceRoot":"","sources":["../../src/utils/import-edge-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAC;AACpE,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE3F,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,cAAc,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;CACvB;AAuKD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAAG,UAAU,EAAE,CAavF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,EAAE,CAiB5E"}
|