@neurcode-ai/cli 0.9.64 → 0.9.66
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/LICENSE +201 -0
- package/dist/commands/bootstrap-policy.d.ts +29 -0
- package/dist/commands/bootstrap-policy.d.ts.map +1 -0
- package/dist/commands/bootstrap-policy.js +334 -0
- package/dist/commands/bootstrap-policy.js.map +1 -0
- package/dist/commands/brain.d.ts.map +1 -1
- package/dist/commands/brain.js +273 -0
- package/dist/commands/brain.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +82 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/pilot-report.d.ts +9 -0
- package/dist/commands/pilot-report.d.ts.map +1 -0
- package/dist/commands/pilot-report.js +176 -0
- package/dist/commands/pilot-report.js.map +1 -0
- package/dist/commands/quickstart.d.ts +21 -0
- package/dist/commands/quickstart.d.ts.map +1 -0
- package/dist/commands/quickstart.js +178 -0
- package/dist/commands/quickstart.js.map +1 -0
- package/dist/commands/remediate-export.d.ts +31 -0
- package/dist/commands/remediate-export.d.ts.map +1 -0
- package/dist/commands/remediate-export.js +283 -0
- package/dist/commands/remediate-export.js.map +1 -0
- package/dist/commands/remediate-governance.d.ts +54 -0
- package/dist/commands/remediate-governance.d.ts.map +1 -0
- package/dist/commands/remediate-governance.js +375 -0
- package/dist/commands/remediate-governance.js.map +1 -0
- package/dist/commands/remediate.d.ts.map +1 -1
- package/dist/commands/remediate.js.map +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +30 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +409 -30
- package/dist/commands/verify.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +1078 -0
- package/dist/daemon/server.js.map +1 -1
- package/dist/explainability/DeterminismClassifier.d.ts +34 -0
- package/dist/explainability/DeterminismClassifier.d.ts.map +1 -0
- package/dist/explainability/DeterminismClassifier.js +104 -0
- package/dist/explainability/DeterminismClassifier.js.map +1 -0
- package/dist/explainability/ViolationFormatter.d.ts +32 -0
- package/dist/explainability/ViolationFormatter.d.ts.map +1 -0
- package/dist/explainability/ViolationFormatter.js +252 -0
- package/dist/explainability/ViolationFormatter.js.map +1 -0
- package/dist/explainability/index.d.ts +15 -0
- package/dist/explainability/index.d.ts.map +1 -0
- package/dist/explainability/index.js +94 -0
- package/dist/explainability/index.js.map +1 -0
- package/dist/explainability/types.d.ts +37 -0
- package/dist/explainability/types.d.ts.map +1 -0
- package/dist/explainability/types.js +3 -0
- package/dist/explainability/types.js.map +1 -0
- package/dist/governance/canonical-invariants.d.ts +88 -0
- package/dist/governance/canonical-invariants.d.ts.map +1 -0
- package/dist/governance/canonical-invariants.js +197 -0
- package/dist/governance/canonical-invariants.js.map +1 -0
- package/dist/governance/canonical-ordering.d.ts +76 -0
- package/dist/governance/canonical-ordering.d.ts.map +1 -0
- package/dist/governance/canonical-ordering.js +189 -0
- package/dist/governance/canonical-ordering.js.map +1 -0
- package/dist/governance/canonical-pipeline.d.ts +45 -0
- package/dist/governance/canonical-pipeline.d.ts.map +1 -0
- package/dist/governance/canonical-pipeline.js +616 -0
- package/dist/governance/canonical-pipeline.js.map +1 -0
- package/dist/governance/diff-line-provenance.d.ts +59 -0
- package/dist/governance/diff-line-provenance.d.ts.map +1 -0
- package/dist/governance/diff-line-provenance.js +118 -0
- package/dist/governance/diff-line-provenance.js.map +1 -0
- package/dist/governance/pilot-readiness.d.ts +34 -0
- package/dist/governance/pilot-readiness.d.ts.map +1 -0
- package/dist/governance/pilot-readiness.js +226 -0
- package/dist/governance/pilot-readiness.js.map +1 -0
- package/dist/governance/policy-parity-validator.d.ts +62 -0
- package/dist/governance/policy-parity-validator.d.ts.map +1 -0
- package/dist/governance/policy-parity-validator.js +137 -0
- package/dist/governance/policy-parity-validator.js.map +1 -0
- package/dist/governance/remediation-boundary.d.ts +55 -0
- package/dist/governance/remediation-boundary.d.ts.map +1 -0
- package/dist/governance/remediation-boundary.js +120 -0
- package/dist/governance/remediation-boundary.js.map +1 -0
- package/dist/governance/structural-cache.d.ts +103 -0
- package/dist/governance/structural-cache.d.ts.map +1 -0
- package/dist/governance/structural-cache.js +240 -0
- package/dist/governance/structural-cache.js.map +1 -0
- package/dist/governance/structural-on-diff.d.ts +33 -0
- package/dist/governance/structural-on-diff.d.ts.map +1 -0
- package/dist/governance/structural-on-diff.js +67 -0
- package/dist/governance/structural-on-diff.js.map +1 -0
- package/dist/governance/structural-policy-merge.d.ts +22 -0
- package/dist/governance/structural-policy-merge.d.ts.map +1 -0
- package/dist/governance/structural-policy-merge.js +32 -0
- package/dist/governance/structural-policy-merge.js.map +1 -0
- package/dist/governance/verify-runtime-guard.d.ts +99 -0
- package/dist/governance/verify-runtime-guard.d.ts.map +1 -0
- package/dist/governance/verify-runtime-guard.js +129 -0
- package/dist/governance/verify-runtime-guard.js.map +1 -0
- package/dist/index.js +107 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/review-compression/index.d.ts +50 -0
- package/dist/integrations/review-compression/index.d.ts.map +1 -0
- package/dist/integrations/review-compression/index.js +158 -0
- package/dist/integrations/review-compression/index.js.map +1 -0
- package/dist/intent-engine/domain-taxonomy.d.ts +42 -0
- package/dist/intent-engine/domain-taxonomy.d.ts.map +1 -0
- package/dist/intent-engine/domain-taxonomy.js +534 -0
- package/dist/intent-engine/domain-taxonomy.js.map +1 -0
- package/dist/intent-engine/index.d.ts +1 -0
- package/dist/intent-engine/index.d.ts.map +1 -1
- package/dist/intent-engine/index.js +6 -1
- package/dist/intent-engine/index.js.map +1 -1
- package/dist/intent-engine/parser.d.ts.map +1 -1
- package/dist/intent-engine/parser.js +47 -0
- package/dist/intent-engine/parser.js.map +1 -1
- package/dist/intent-engine/repo-classifier.d.ts +64 -0
- package/dist/intent-engine/repo-classifier.d.ts.map +1 -0
- package/dist/intent-engine/repo-classifier.js +178 -0
- package/dist/intent-engine/repo-classifier.js.map +1 -0
- package/dist/intent-engine/semantic-expander.d.ts +104 -0
- package/dist/intent-engine/semantic-expander.d.ts.map +1 -0
- package/dist/intent-engine/semantic-expander.js +480 -0
- package/dist/intent-engine/semantic-expander.js.map +1 -0
- package/dist/patch-engine/patterns.d.ts.map +1 -1
- package/dist/patch-engine/patterns.js +8 -4
- package/dist/patch-engine/patterns.js.map +1 -1
- package/dist/semantic/index.d.ts +14 -0
- package/dist/semantic/index.d.ts.map +1 -0
- package/dist/semantic/index.js +30 -0
- package/dist/semantic/index.js.map +1 -0
- package/dist/semantic/tfidf-engine.d.ts +81 -0
- package/dist/semantic/tfidf-engine.d.ts.map +1 -0
- package/dist/semantic/tfidf-engine.js +278 -0
- package/dist/semantic/tfidf-engine.js.map +1 -0
- package/dist/semantic/vector-store.d.ts +108 -0
- package/dist/semantic/vector-store.d.ts.map +1 -0
- package/dist/semantic/vector-store.js +321 -0
- package/dist/semantic/vector-store.js.map +1 -0
- package/dist/structural-rules/context-severity.d.ts +46 -0
- package/dist/structural-rules/context-severity.d.ts.map +1 -0
- package/dist/structural-rules/context-severity.js +115 -0
- package/dist/structural-rules/context-severity.js.map +1 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts +11 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts.map +1 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js +212 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js.map +1 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts +11 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts.map +1 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.js +213 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.js.map +1 -0
- package/dist/structural-rules/distributed/index.d.ts +3 -0
- package/dist/structural-rules/distributed/index.d.ts.map +1 -0
- package/dist/structural-rules/distributed/index.js +8 -0
- package/dist/structural-rules/distributed/index.js.map +1 -0
- package/dist/structural-rules/engine.d.ts +25 -0
- package/dist/structural-rules/engine.d.ts.map +1 -0
- package/dist/structural-rules/engine.js +90 -0
- package/dist/structural-rules/engine.js.map +1 -0
- package/dist/structural-rules/index.d.ts +45 -0
- package/dist/structural-rules/index.d.ts.map +1 -0
- package/dist/structural-rules/index.js +158 -0
- package/dist/structural-rules/index.js.map +1 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts +11 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts.map +1 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js +66 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js.map +1 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts +11 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts.map +1 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js +135 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js.map +1 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts +32 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts.map +1 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.js +277 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.js.map +1 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts +11 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts.map +1 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.js +167 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.js.map +1 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts +11 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts.map +1 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js +154 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js.map +1 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts +11 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts.map +1 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.js +130 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.js.map +1 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts +11 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts.map +1 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js +93 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js.map +1 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts +11 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts.map +1 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.js +154 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.js.map +1 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts +11 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts.map +1 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js +133 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js.map +1 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts +11 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts.map +1 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js +80 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js.map +1 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.d.ts +11 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.d.ts.map +1 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.js +97 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.js.map +1 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.d.ts +11 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.d.ts.map +1 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.js +83 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.js.map +1 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.d.ts +11 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.d.ts.map +1 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.js +73 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.js.map +1 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.d.ts +11 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.d.ts.map +1 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.js +115 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.js.map +1 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts +11 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js +145 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js.map +1 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts +11 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.js +196 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.js.map +1 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts +11 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.js +148 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.js.map +1 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts +11 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js +162 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js.map +1 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts +11 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js +150 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js.map +1 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts +11 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js +161 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js.map +1 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.d.ts +11 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.js +175 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.js.map +1 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts +11 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.js +176 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.js.map +1 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts +11 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.js +168 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.js.map +1 -0
- package/dist/structural-rules/rules/SR010-retry-storm.d.ts +11 -0
- package/dist/structural-rules/rules/SR010-retry-storm.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR010-retry-storm.js +181 -0
- package/dist/structural-rules/rules/SR010-retry-storm.js.map +1 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts +11 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.js +208 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.js.map +1 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts +11 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.js +191 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.js.map +1 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts +11 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.js +219 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.js.map +1 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts +11 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.js +208 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.js.map +1 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts +11 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.js +190 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.js.map +1 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts +11 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.js +187 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.js.map +1 -0
- package/dist/structural-rules/suppressions.d.ts +43 -0
- package/dist/structural-rules/suppressions.d.ts.map +1 -0
- package/dist/structural-rules/suppressions.js +115 -0
- package/dist/structural-rules/suppressions.js.map +1 -0
- package/dist/structural-rules/types.d.ts +55 -0
- package/dist/structural-rules/types.d.ts.map +1 -0
- package/dist/structural-rules/types.js +3 -0
- package/dist/structural-rules/types.js.map +1 -0
- package/dist/utils/brain-cache.d.ts +100 -0
- package/dist/utils/brain-cache.d.ts.map +1 -0
- package/dist/utils/brain-cache.js +346 -0
- package/dist/utils/brain-cache.js.map +1 -0
- package/dist/utils/governance-provenance.d.ts +95 -0
- package/dist/utils/governance-provenance.d.ts.map +1 -0
- package/dist/utils/governance-provenance.js +187 -0
- package/dist/utils/governance-provenance.js.map +1 -0
- package/dist/utils/pilot-metrics.d.ts +46 -0
- package/dist/utils/pilot-metrics.d.ts.map +1 -0
- package/dist/utils/pilot-metrics.js +240 -0
- package/dist/utils/pilot-metrics.js.map +1 -0
- package/dist/utils/replay-runtime.d.ts +34 -0
- package/dist/utils/replay-runtime.d.ts.map +1 -1
- package/dist/utils/replay-runtime.js +207 -0
- package/dist/utils/replay-runtime.js.map +1 -1
- package/dist/utils/verify-runtime-stability.d.ts +142 -0
- package/dist/utils/verify-runtime-stability.d.ts.map +1 -0
- package/dist/utils/verify-runtime-stability.js +230 -0
- package/dist/utils/verify-runtime-stability.js.map +1 -0
- package/dist/workspace/cross-repo-graph.d.ts +111 -0
- package/dist/workspace/cross-repo-graph.d.ts.map +1 -0
- package/dist/workspace/cross-repo-graph.js +450 -0
- package/dist/workspace/cross-repo-graph.js.map +1 -0
- package/dist/workspace/federated-context.d.ts +144 -0
- package/dist/workspace/federated-context.d.ts.map +1 -0
- package/dist/workspace/federated-context.js +347 -0
- package/dist/workspace/federated-context.js.map +1 -0
- package/dist/workspace/index.d.ts +38 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +48 -0
- package/dist/workspace/index.js.map +1 -0
- package/package.json +9 -9
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-Repo Dependency Graph
|
|
4
|
+
*
|
|
5
|
+
* Detects coupling between repositories that is INVISIBLE to single-repo graph analysis.
|
|
6
|
+
* This is the key gap for microservice architectures where:
|
|
7
|
+
* - Service A calls Service B over HTTP/gRPC
|
|
8
|
+
* - Service C publishes Kafka events that Service D consumes
|
|
9
|
+
* - All services share a contract package (@company/shared-types)
|
|
10
|
+
* - Environment variables encode service discovery (AUTH_SERVICE_URL)
|
|
11
|
+
*
|
|
12
|
+
* Each detected edge has:
|
|
13
|
+
* - A `via` classification (how the coupling manifests)
|
|
14
|
+
* - A `confidence` level (high = structural proof, low = pattern heuristic)
|
|
15
|
+
* - `evidence` lines that prove the coupling exists
|
|
16
|
+
*
|
|
17
|
+
* The graph is deterministic: same inputs → identical edges, same ordering.
|
|
18
|
+
* All regex patterns are pre-compiled and stateless.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.buildCrossRepoGraph = buildCrossRepoGraph;
|
|
22
|
+
exports.getDownstreamRepos = getDownstreamRepos;
|
|
23
|
+
exports.getUpstreamRepos = getUpstreamRepos;
|
|
24
|
+
exports.getEdgesForFile = getEdgesForFile;
|
|
25
|
+
exports.getEdgesPointingToFile = getEdgesPointingToFile;
|
|
26
|
+
const fs_1 = require("fs");
|
|
27
|
+
const glob_1 = require("glob");
|
|
28
|
+
const path_1 = require("path");
|
|
29
|
+
// ── Detection Patterns ───────────────────────────────────────────────────────
|
|
30
|
+
//
|
|
31
|
+
// Each pattern set targets a specific coupling mechanism.
|
|
32
|
+
// Patterns are conservative: we prefer false-negatives over false-positives
|
|
33
|
+
// because an incorrect cross-repo edge is worse than a missed one.
|
|
34
|
+
/** HTTP client calls: axios, fetch, got, node-fetch, ky */
|
|
35
|
+
const HTTP_CLIENT_PATTERNS = [
|
|
36
|
+
/(?:axios|http|got|ky)\s*\.\s*(?:get|post|put|patch|delete)\s*\(\s*[`'"](https?:\/\/[^`'"]+)[`'"]/gi,
|
|
37
|
+
/(?:baseURL|baseUrl|BASE_URL)\s*[:=]\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
38
|
+
/new\s+(?:HttpService|HttpClient|ApiClient|RestClient)\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
39
|
+
/fetch\s*\(\s*[`'"](https?:\/\/[^`'"]+)[`'"]/gi,
|
|
40
|
+
];
|
|
41
|
+
/** gRPC client patterns */
|
|
42
|
+
const GRPC_CLIENT_PATTERNS = [
|
|
43
|
+
/new\s+(\w+(?:Service|Client))\s*\(\s*[`'"]([^`'"]+:\d+)[`'"]/gi,
|
|
44
|
+
/(?:@GrpcClient|@Client)\s*\(\s*\{[^}]*service\s*:\s*['"](\w+)['"]/gi,
|
|
45
|
+
/loadPackageDefinition.*?\.(\w+)\s*\.\s*(\w+Service)/gs,
|
|
46
|
+
];
|
|
47
|
+
/** Event publish patterns: Kafka, RabbitMQ, SQS, BullMQ, EventEmitter */
|
|
48
|
+
const EVENT_PUBLISH_PATTERNS = [
|
|
49
|
+
/(?:producer|publisher|client)\s*\.\s*send\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
50
|
+
/(?:emit|publish)\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
51
|
+
/@EventPattern\s*\(\s*[`'"]([^`'"]+)[`'"]/gi, // NestJS emit
|
|
52
|
+
/(?:channel|exchange|topic|queue)\s*[:=]\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
53
|
+
/\.sendToQueue\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
54
|
+
/SNS\.publish.*?TopicArn[^`'"]*[`'"]([^`'"]+)[`'"]/gi,
|
|
55
|
+
];
|
|
56
|
+
/** Event subscribe/consume patterns */
|
|
57
|
+
const EVENT_SUBSCRIBE_PATTERNS = [
|
|
58
|
+
/@MessagePattern\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
59
|
+
/\.subscribe\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
60
|
+
/consumer\.run.*?eachMessage/gs,
|
|
61
|
+
/(?:on|addListener)\s*\(\s*[`'"]([^`'".]+\.[^`'"]+)[`'"]/gi, // namespaced events only
|
|
62
|
+
/queue\.process\s*\(\s*[`'"]([^`'"]+)[`'"]/gi,
|
|
63
|
+
];
|
|
64
|
+
/** Shared contracts: @company/*, internal scoped packages */
|
|
65
|
+
const SHARED_CONTRACT_PATTERNS = [
|
|
66
|
+
/from\s+['"](@[a-z0-9-]+\/(?:shared|contracts?|types?|proto|common|api)[^'"]*)['"]/gi,
|
|
67
|
+
/require\s*\(\s*['"](@[a-z0-9-]+\/(?:shared|contracts?|types?|proto|common|api)[^'"]*)['"]\s*\)/gi,
|
|
68
|
+
];
|
|
69
|
+
/** Service discovery via environment variables */
|
|
70
|
+
const ENV_SERVICE_URL_PATTERNS = [
|
|
71
|
+
/process\.env\.([A-Z][A-Z0-9_]*(?:SERVICE|SVC|API|HOST|URL|ENDPOINT)[A-Z0-9_]*)/g,
|
|
72
|
+
/process\.env\[['"]([A-Z][A-Z0-9_]*(?:SERVICE|SVC|API|HOST|URL|ENDPOINT)[A-Z0-9_]*)['"]\]/g,
|
|
73
|
+
];
|
|
74
|
+
/** OpenAPI/Swagger generated clients */
|
|
75
|
+
const OPENAPI_CLIENT_PATTERNS = [
|
|
76
|
+
/from\s+['"](?:\.\.?\/)*(?:generated?|gen|client|api-client|openapi)[^'"]*['"]/gi,
|
|
77
|
+
/from\s+['"](@[a-z0-9-]+\/(?:api-client|client|generated)[^'"]*)['"]/gi,
|
|
78
|
+
];
|
|
79
|
+
// ── Service Name Resolution ──────────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* Given a service name extracted from code (e.g. "auth-service", "AUTH_SERVICE_URL"),
|
|
82
|
+
* tries to match it against known repos in the workspace.
|
|
83
|
+
*
|
|
84
|
+
* Returns the matched repo name, or null if no match found.
|
|
85
|
+
*/
|
|
86
|
+
function resolveServiceToRepo(serviceName, repos, currentRepoName) {
|
|
87
|
+
if (!serviceName)
|
|
88
|
+
return null;
|
|
89
|
+
const normalized = serviceName
|
|
90
|
+
.toLowerCase()
|
|
91
|
+
.replace(/_url$|_host$|_endpoint$|_api$|_svc$|_service$/, '')
|
|
92
|
+
.replace(/_/g, '-');
|
|
93
|
+
for (const repo of repos) {
|
|
94
|
+
if (repo.name === currentRepoName)
|
|
95
|
+
continue; // skip self
|
|
96
|
+
const repoNorm = repo.name.toLowerCase();
|
|
97
|
+
// Direct match
|
|
98
|
+
if (repoNorm === normalized)
|
|
99
|
+
return repo.name;
|
|
100
|
+
// Substring match (e.g., "auth" matches "auth-service")
|
|
101
|
+
if (repoNorm.includes(normalized) || normalized.includes(repoNorm))
|
|
102
|
+
return repo.name;
|
|
103
|
+
// Service array match
|
|
104
|
+
for (const svc of repo.services) {
|
|
105
|
+
const svcNorm = svc.toLowerCase();
|
|
106
|
+
if (svcNorm === normalized || svcNorm.includes(normalized))
|
|
107
|
+
return repo.name;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function scanFileForCrossRepoSignals(content) {
|
|
113
|
+
const fragments = [];
|
|
114
|
+
function runPatterns(patterns, via, groupIndex = 1) {
|
|
115
|
+
for (const pattern of patterns) {
|
|
116
|
+
const re = new RegExp(pattern.source, pattern.flags);
|
|
117
|
+
let match;
|
|
118
|
+
while ((match = re.exec(content)) !== null) {
|
|
119
|
+
const targetHint = (match[groupIndex] ?? '').trim();
|
|
120
|
+
if (!targetHint || targetHint.length < 2)
|
|
121
|
+
continue;
|
|
122
|
+
// Get the line containing this match for evidence
|
|
123
|
+
const matchStart = match.index;
|
|
124
|
+
const lineStart = content.lastIndexOf('\n', matchStart) + 1;
|
|
125
|
+
const lineEnd = content.indexOf('\n', matchStart);
|
|
126
|
+
const line = content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
|
|
127
|
+
fragments.push({ via, targetHint, evidence: line });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
runPatterns(HTTP_CLIENT_PATTERNS, 'http-client', 1);
|
|
132
|
+
runPatterns(GRPC_CLIENT_PATTERNS, 'grpc-client', 1);
|
|
133
|
+
runPatterns(EVENT_PUBLISH_PATTERNS, 'event-publish', 1);
|
|
134
|
+
runPatterns(EVENT_SUBSCRIBE_PATTERNS, 'event-subscribe', 1);
|
|
135
|
+
runPatterns(SHARED_CONTRACT_PATTERNS, 'shared-contract', 1);
|
|
136
|
+
runPatterns(ENV_SERVICE_URL_PATTERNS, 'env-service-url', 1);
|
|
137
|
+
runPatterns(OPENAPI_CLIENT_PATTERNS, 'openapi-client', 1);
|
|
138
|
+
return fragments;
|
|
139
|
+
}
|
|
140
|
+
// ── HTTP URL → service name extractor ────────────────────────────────────────
|
|
141
|
+
function extractServiceNameFromUrl(url) {
|
|
142
|
+
// Remove protocol: http://auth-service:3000/users → auth-service
|
|
143
|
+
const withoutProto = url.replace(/^https?:\/\//, '');
|
|
144
|
+
// Take host part only
|
|
145
|
+
const host = withoutProto.split('/')[0] ?? '';
|
|
146
|
+
// Remove port
|
|
147
|
+
const hostname = host.split(':')[0] ?? '';
|
|
148
|
+
// Remove env var placeholders like ${AUTH_SERVICE}
|
|
149
|
+
const clean = hostname.replace(/\$\{[^}]+\}/, '').replace(/\$[A-Z_]+/, '');
|
|
150
|
+
return clean;
|
|
151
|
+
}
|
|
152
|
+
// ── Contract File Locator ─────────────────────────────────────────────────────
|
|
153
|
+
/**
|
|
154
|
+
* Given a shared contract package name, tries to find the actual file in
|
|
155
|
+
* target repos that defines this contract.
|
|
156
|
+
*/
|
|
157
|
+
function findContractFileInRepo(packageName, repoBrainMap) {
|
|
158
|
+
if (!repoBrainMap)
|
|
159
|
+
return null;
|
|
160
|
+
// Extract the package basename (e.g., "@company/shared-types" → "shared-types")
|
|
161
|
+
const packageBase = packageName.split('/').pop() ?? '';
|
|
162
|
+
const contractKeywords = packageBase.replace(/-/g, '').toLowerCase();
|
|
163
|
+
for (const filePath of Object.keys(repoBrainMap.files)) {
|
|
164
|
+
const fileNorm = filePath.toLowerCase().replace(/[-./]/g, '');
|
|
165
|
+
if (fileNorm.includes(contractKeywords)) {
|
|
166
|
+
return filePath;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Build the cross-repo dependency graph for a workspace.
|
|
173
|
+
*
|
|
174
|
+
* This function:
|
|
175
|
+
* 1. Scans source files in each repo for cross-service coupling signals
|
|
176
|
+
* 2. Resolves each signal to a target repo using the workspace topology
|
|
177
|
+
* 3. Returns typed, evidence-backed edges with confidence scores
|
|
178
|
+
*
|
|
179
|
+
* Deterministic: same workspace config + same file contents → same graph.
|
|
180
|
+
*/
|
|
181
|
+
function buildCrossRepoGraph(input) {
|
|
182
|
+
const { repos, brainMaps = {}, options = {} } = input;
|
|
183
|
+
const maxFilesPerRepo = options.maxFilesPerRepo ?? 2000;
|
|
184
|
+
const edges = [];
|
|
185
|
+
let totalFilesScanned = 0;
|
|
186
|
+
for (const repo of repos) {
|
|
187
|
+
if (!repo.enabled)
|
|
188
|
+
continue;
|
|
189
|
+
const repoRoot = repo.rootPath;
|
|
190
|
+
if (!(0, fs_1.existsSync)(repoRoot))
|
|
191
|
+
continue;
|
|
192
|
+
const brainMap = brainMaps[repo.name] ?? null;
|
|
193
|
+
// Collect files to scan: prefer brain map file list (already parsed),
|
|
194
|
+
// fall back to glob scan
|
|
195
|
+
let filesToScan;
|
|
196
|
+
if (brainMap && Object.keys(brainMap.files).length > 0) {
|
|
197
|
+
filesToScan = Object.keys(brainMap.files)
|
|
198
|
+
.map((f) => (0, path_1.join)(repoRoot, f))
|
|
199
|
+
.filter((f) => (0, fs_1.existsSync)(f))
|
|
200
|
+
.slice(0, maxFilesPerRepo);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
filesToScan = (0, glob_1.globSync)('**/*.{ts,tsx,js,jsx,mjs,py}', {
|
|
204
|
+
cwd: repoRoot,
|
|
205
|
+
ignore: [
|
|
206
|
+
'**/node_modules/**',
|
|
207
|
+
'**/dist/**',
|
|
208
|
+
'**/build/**',
|
|
209
|
+
'**/*.d.ts',
|
|
210
|
+
'**/coverage/**',
|
|
211
|
+
],
|
|
212
|
+
absolute: true,
|
|
213
|
+
follow: options.followSymlinks ?? false,
|
|
214
|
+
}).slice(0, maxFilesPerRepo);
|
|
215
|
+
}
|
|
216
|
+
totalFilesScanned += filesToScan.length;
|
|
217
|
+
for (const absFilePath of filesToScan) {
|
|
218
|
+
let content;
|
|
219
|
+
try {
|
|
220
|
+
content = (0, fs_1.readFileSync)(absFilePath, 'utf-8');
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const relFilePath = (0, path_1.relative)(repoRoot, absFilePath).replace(/\\/g, '/');
|
|
226
|
+
const fragments = scanFileForCrossRepoSignals(content);
|
|
227
|
+
for (const fragment of fragments) {
|
|
228
|
+
let targetHint = fragment.targetHint;
|
|
229
|
+
let toRepo = null;
|
|
230
|
+
let toFile = null;
|
|
231
|
+
let confidence = 'low';
|
|
232
|
+
switch (fragment.via) {
|
|
233
|
+
case 'http-client': {
|
|
234
|
+
const serviceName = extractServiceNameFromUrl(targetHint);
|
|
235
|
+
toRepo = resolveServiceToRepo(serviceName, repos, repo.name);
|
|
236
|
+
confidence = toRepo ? 'medium' : 'low';
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
case 'grpc-client': {
|
|
240
|
+
toRepo = resolveServiceToRepo(targetHint, repos, repo.name);
|
|
241
|
+
confidence = toRepo ? 'medium' : 'low';
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case 'shared-contract': {
|
|
245
|
+
// Try to find which repo owns this package
|
|
246
|
+
for (const candidateRepo of repos) {
|
|
247
|
+
if (candidateRepo.name === repo.name)
|
|
248
|
+
continue;
|
|
249
|
+
const candidateBrain = brainMaps[candidateRepo.name] ?? null;
|
|
250
|
+
const contractFile = findContractFileInRepo(targetHint, candidateBrain);
|
|
251
|
+
if (contractFile) {
|
|
252
|
+
toRepo = candidateRepo.name;
|
|
253
|
+
toFile = contractFile;
|
|
254
|
+
confidence = 'high'; // We found the actual file
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Even without a resolved repo, shared contract imports are high-signal
|
|
259
|
+
if (!toRepo) {
|
|
260
|
+
// Mark as external package dependency — unknown repo
|
|
261
|
+
toRepo = `external:${targetHint.split('/')[0] ?? 'unknown'}`;
|
|
262
|
+
confidence = 'medium';
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
case 'env-service-url': {
|
|
267
|
+
// ENV var like AUTH_SERVICE_URL → try "auth-service" or "auth"
|
|
268
|
+
toRepo = resolveServiceToRepo(targetHint, repos, repo.name);
|
|
269
|
+
confidence = toRepo ? 'medium' : 'low';
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
case 'event-publish':
|
|
273
|
+
case 'event-subscribe': {
|
|
274
|
+
// Topic names like "user.created", "payment.completed"
|
|
275
|
+
// Extract the domain prefix (e.g., "user" from "user.created")
|
|
276
|
+
const topicDomain = targetHint.split('.')[0] ?? targetHint;
|
|
277
|
+
toRepo = resolveServiceToRepo(topicDomain, repos, repo.name);
|
|
278
|
+
// Event coupling is medium confidence even when resolved —
|
|
279
|
+
// we can't prove the other service subscribes without inspecting it
|
|
280
|
+
confidence = toRepo ? 'medium' : 'low';
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case 'openapi-client': {
|
|
284
|
+
// OpenAPI clients are usually generated from another service's API
|
|
285
|
+
// Try to match path components to known repos
|
|
286
|
+
const pathParts = targetHint.split('/').filter(Boolean);
|
|
287
|
+
for (const part of pathParts) {
|
|
288
|
+
toRepo = resolveServiceToRepo(part, repos, repo.name);
|
|
289
|
+
if (toRepo) {
|
|
290
|
+
confidence = 'high'; // Generated client = definitive contract
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Only emit an edge if we have a resolved target repo
|
|
298
|
+
if (!toRepo)
|
|
299
|
+
continue;
|
|
300
|
+
const impactSummary = buildImpactSummary(fragment.via, repo.name, toRepo, targetHint);
|
|
301
|
+
edges.push({
|
|
302
|
+
fromRepo: repo.name,
|
|
303
|
+
fromFile: relFilePath,
|
|
304
|
+
toRepo,
|
|
305
|
+
toFile,
|
|
306
|
+
via: fragment.via,
|
|
307
|
+
confidence,
|
|
308
|
+
evidence: [fragment.evidence],
|
|
309
|
+
impactSummary,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Deduplicate: merge edges with same fromRepo+fromFile+toRepo+via into one
|
|
315
|
+
// (keeps all evidence lines)
|
|
316
|
+
const deduped = deduplicateEdges(edges);
|
|
317
|
+
// Sort deterministically
|
|
318
|
+
deduped.sort((a, b) => {
|
|
319
|
+
const key = (e) => `${e.fromRepo}:${e.fromFile}:${e.toRepo}:${e.via}`;
|
|
320
|
+
return key(a).localeCompare(key(b));
|
|
321
|
+
});
|
|
322
|
+
const stats = computeStats(deduped, totalFilesScanned);
|
|
323
|
+
return {
|
|
324
|
+
generatedAt: new Date().toISOString(),
|
|
325
|
+
repos: repos.map((r) => r.name),
|
|
326
|
+
edges: deduped,
|
|
327
|
+
stats,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
// ── Utilities ────────────────────────────────────────────────────────────────
|
|
331
|
+
function deduplicateEdges(edges) {
|
|
332
|
+
const seen = new Map();
|
|
333
|
+
for (const edge of edges) {
|
|
334
|
+
const key = `${edge.fromRepo}|${edge.fromFile}|${edge.toRepo}|${edge.via}`;
|
|
335
|
+
const existing = seen.get(key);
|
|
336
|
+
if (!existing) {
|
|
337
|
+
seen.set(key, { ...edge, evidence: [...edge.evidence] });
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// Merge evidence, prefer higher confidence
|
|
341
|
+
for (const ev of edge.evidence) {
|
|
342
|
+
if (!existing.evidence.includes(ev)) {
|
|
343
|
+
existing.evidence.push(ev);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (edge.confidence === 'high' ||
|
|
347
|
+
(edge.confidence === 'medium' && existing.confidence === 'low')) {
|
|
348
|
+
existing.confidence = edge.confidence;
|
|
349
|
+
}
|
|
350
|
+
if (edge.toFile && !existing.toFile) {
|
|
351
|
+
existing.toFile = edge.toFile;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return [...seen.values()];
|
|
356
|
+
}
|
|
357
|
+
function buildImpactSummary(via, fromRepo, toRepo, hint) {
|
|
358
|
+
switch (via) {
|
|
359
|
+
case 'http-client':
|
|
360
|
+
return `${fromRepo} makes HTTP calls to ${toRepo} — API contract changes in ${toRepo} break ${fromRepo}`;
|
|
361
|
+
case 'grpc-client':
|
|
362
|
+
return `${fromRepo} uses gRPC stub from ${toRepo} — proto schema changes are breaking`;
|
|
363
|
+
case 'event-publish':
|
|
364
|
+
return `${fromRepo} publishes "${hint}" events consumed by ${toRepo} — event schema changes are breaking`;
|
|
365
|
+
case 'event-subscribe':
|
|
366
|
+
return `${fromRepo} consumes events from ${toRepo} — upstream schema changes in ${toRepo} propagate here`;
|
|
367
|
+
case 'shared-contract':
|
|
368
|
+
return `${fromRepo} imports shared types from ${toRepo} — any breaking type change cascades to ${fromRepo}`;
|
|
369
|
+
case 'env-service-url':
|
|
370
|
+
return `${fromRepo} resolves ${toRepo} at runtime via env var — deployment config must be coordinated`;
|
|
371
|
+
case 'openapi-client':
|
|
372
|
+
return `${fromRepo} uses generated OpenAPI client for ${toRepo} — API surface changes require client regeneration`;
|
|
373
|
+
case 'db-shared-schema':
|
|
374
|
+
return `${fromRepo} directly queries ${toRepo}'s database — schema migrations in ${toRepo} are immediately breaking`;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function computeStats(edges, filesScanned) {
|
|
378
|
+
const byVia = {
|
|
379
|
+
'http-client': 0,
|
|
380
|
+
'grpc-client': 0,
|
|
381
|
+
'event-publish': 0,
|
|
382
|
+
'event-subscribe': 0,
|
|
383
|
+
'shared-contract': 0,
|
|
384
|
+
'env-service-url': 0,
|
|
385
|
+
'openapi-client': 0,
|
|
386
|
+
'db-shared-schema': 0,
|
|
387
|
+
};
|
|
388
|
+
const byConfidence = {
|
|
389
|
+
high: 0,
|
|
390
|
+
medium: 0,
|
|
391
|
+
low: 0,
|
|
392
|
+
};
|
|
393
|
+
for (const edge of edges) {
|
|
394
|
+
byVia[edge.via] = (byVia[edge.via] ?? 0) + 1;
|
|
395
|
+
byConfidence[edge.confidence] = (byConfidence[edge.confidence] ?? 0) + 1;
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
filesScanned,
|
|
399
|
+
edgesDetected: edges.length,
|
|
400
|
+
byVia,
|
|
401
|
+
byConfidence,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
// ── Subgraph Query Helpers ───────────────────────────────────────────────────
|
|
405
|
+
/**
|
|
406
|
+
* Get all repos that are directly affected when a change occurs in `repoName`.
|
|
407
|
+
* Returns repos that import from / depend on `repoName`.
|
|
408
|
+
*/
|
|
409
|
+
function getDownstreamRepos(graph, repoName) {
|
|
410
|
+
const downstream = new Set();
|
|
411
|
+
for (const edge of graph.edges) {
|
|
412
|
+
// toRepo depends on fromRepo → if fromRepo changes, toRepo is affected
|
|
413
|
+
// Actually: fromRepo calls toRepo, so toRepo's changes affect fromRepo
|
|
414
|
+
// Let's be precise:
|
|
415
|
+
// fromRepo → toRepo means fromRepo DEPENDS ON toRepo
|
|
416
|
+
// if toRepo changes, fromRepo might break
|
|
417
|
+
// So "downstream of toRepo" = all fromRepos that call toRepo
|
|
418
|
+
if (edge.toRepo === repoName && !edge.toRepo.startsWith('external:')) {
|
|
419
|
+
downstream.add(edge.fromRepo);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return [...downstream].sort();
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Get all repos that `repoName` directly depends on (calls/imports).
|
|
426
|
+
*/
|
|
427
|
+
function getUpstreamRepos(graph, repoName) {
|
|
428
|
+
const upstream = new Set();
|
|
429
|
+
for (const edge of graph.edges) {
|
|
430
|
+
if (edge.fromRepo === repoName && !edge.toRepo.startsWith('external:')) {
|
|
431
|
+
upstream.add(edge.toRepo);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return [...upstream].sort();
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Get all edges involving a specific file change in a specific repo.
|
|
438
|
+
* Used to find "what cross-repo coupling does this file touch?"
|
|
439
|
+
*/
|
|
440
|
+
function getEdgesForFile(graph, repoName, filePath) {
|
|
441
|
+
return graph.edges.filter((e) => e.fromRepo === repoName && e.fromFile === filePath);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Get all edges that point TO a specific file in a repo.
|
|
445
|
+
* Used to find "who depends on this file?"
|
|
446
|
+
*/
|
|
447
|
+
function getEdgesPointingToFile(graph, repoName, filePath) {
|
|
448
|
+
return graph.edges.filter((e) => e.toRepo === repoName && e.toFile === filePath);
|
|
449
|
+
}
|
|
450
|
+
//# sourceMappingURL=cross-repo-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-repo-graph.js","sourceRoot":"","sources":["../../src/workspace/cross-repo-graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federated Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Answers the question: "When a developer changes files in repo-A, what is the
|
|
5
|
+
* complete blast radius across ALL repos in the workspace?"
|
|
6
|
+
*
|
|
7
|
+
* This is the enterprise multi-repo answer that single-repo context engines cannot
|
|
8
|
+
* provide. The federated context:
|
|
9
|
+
*
|
|
10
|
+
* 1. Builds the PRIMARY context from the repo where changes are occurring
|
|
11
|
+
* (full depth — constraints, advisory, uncertainty)
|
|
12
|
+
*
|
|
13
|
+
* 2. Resolves SECONDARY context for every repo transitively affected
|
|
14
|
+
* via cross-repo edges (lighter weight — impacted files + why)
|
|
15
|
+
*
|
|
16
|
+
* 3. Returns BLIND SPOTS — coupling that cannot be detected structurally
|
|
17
|
+
* (config coupling, runtime service discovery, infra-level routing)
|
|
18
|
+
*
|
|
19
|
+
* The output is deterministic: same changed files + same workspace topology
|
|
20
|
+
* + same cross-repo graph → identical FederatedContextPackage.
|
|
21
|
+
*
|
|
22
|
+
* Design constraint: this layer is ADDITIVE. It never replaces the primary
|
|
23
|
+
* single-repo context engine. It extends it with cross-repo intelligence.
|
|
24
|
+
*/
|
|
25
|
+
import type { BrainRepositoryMap } from '@neurcode-ai/core';
|
|
26
|
+
import type { WorkspaceRepository } from '../utils/workspace-runtime';
|
|
27
|
+
import { type CrossRepoEdge, type CrossRepoGraph } from './cross-repo-graph';
|
|
28
|
+
export interface FederatedExpansionBoundary {
|
|
29
|
+
maxCrossRepoDepth: 1;
|
|
30
|
+
maxDownstreamReposIncluded: number;
|
|
31
|
+
maxUpstreamReposIncluded: number;
|
|
32
|
+
maxTotalEdges: number;
|
|
33
|
+
traversalOrdering: 'deterministic-alpha';
|
|
34
|
+
truncated: boolean;
|
|
35
|
+
truncationReasons: string[];
|
|
36
|
+
}
|
|
37
|
+
export interface AffectedRepoContext {
|
|
38
|
+
/** Name of the repo affected by the change in the primary repo */
|
|
39
|
+
repoName: string;
|
|
40
|
+
/** Absolute path to this repo's root */
|
|
41
|
+
repoRoot: string;
|
|
42
|
+
/**
|
|
43
|
+
* Files in this repo that are structurally coupled to the changed files.
|
|
44
|
+
* May be empty if the coupling is at service-boundary level (HTTP/gRPC)
|
|
45
|
+
* rather than file level (shared contracts).
|
|
46
|
+
*/
|
|
47
|
+
affectedFiles: Array<{
|
|
48
|
+
file: string;
|
|
49
|
+
reason: string;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Cross-repo edges that create this repo's affected status.
|
|
53
|
+
* Sorted by confidence (high first).
|
|
54
|
+
*/
|
|
55
|
+
couplingEdges: CrossRepoEdge[];
|
|
56
|
+
/**
|
|
57
|
+
* Risk level for this repo given the primary change.
|
|
58
|
+
* Derived from: edge confidence + number of affected files + edge type.
|
|
59
|
+
*/
|
|
60
|
+
riskLevel: 'high' | 'medium' | 'low';
|
|
61
|
+
/**
|
|
62
|
+
* Whether this repo needs a coordinated deploy with the primary repo.
|
|
63
|
+
* True when any high-confidence edge exists (contract change, shared type, gRPC).
|
|
64
|
+
*/
|
|
65
|
+
requiresCoordinatedDeploy: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface FederatedBlindSpot {
|
|
68
|
+
/** What cannot be seen */
|
|
69
|
+
description: string;
|
|
70
|
+
/** What repos might be affected that we cannot prove */
|
|
71
|
+
potentialRepos: string[];
|
|
72
|
+
/**
|
|
73
|
+
* The structural gap that causes this blindspot.
|
|
74
|
+
* Matches the GraphBlindSpot taxonomy.
|
|
75
|
+
*/
|
|
76
|
+
structuralGap: 'runtime-service-discovery' | 'infra-routing-config' | 'sidecar-proxy-config' | 'feature-flag-routing' | 'db-shared-state' | 'third-party-webhook' | 'cdn-cache-invalidation' | 'compiled-proto-drift';
|
|
77
|
+
}
|
|
78
|
+
export interface FederatedContextPackage {
|
|
79
|
+
generatedAt: string;
|
|
80
|
+
/** Workspace name for display */
|
|
81
|
+
workspaceName: string;
|
|
82
|
+
/** The repo where the change originates */
|
|
83
|
+
primaryRepo: string;
|
|
84
|
+
/** Changed files in the primary repo */
|
|
85
|
+
changedFiles: string[];
|
|
86
|
+
/**
|
|
87
|
+
* Cross-repo graph used to compute this package.
|
|
88
|
+
* Included for auditability — same graph produces same result.
|
|
89
|
+
*/
|
|
90
|
+
crossRepoGraph: CrossRepoGraph;
|
|
91
|
+
/**
|
|
92
|
+
* Repos directly affected by changes in the primary repo.
|
|
93
|
+
* These are the repos that CALL or IMPORT FROM the primary repo
|
|
94
|
+
* and whose downstream behavior may change.
|
|
95
|
+
*/
|
|
96
|
+
affectedDownstreamRepos: AffectedRepoContext[];
|
|
97
|
+
/**
|
|
98
|
+
* Repos that the primary repo depends on and that may be relevant context.
|
|
99
|
+
* Included when changed files touch code that calls these services.
|
|
100
|
+
*/
|
|
101
|
+
relevantUpstreamRepos: AffectedRepoContext[];
|
|
102
|
+
/**
|
|
103
|
+
* Structural blindspots — coupling we cannot detect from code alone.
|
|
104
|
+
* These are advisory-only: the consumer must decide whether to act.
|
|
105
|
+
*/
|
|
106
|
+
federatedBlindSpots: FederatedBlindSpot[];
|
|
107
|
+
/**
|
|
108
|
+
* Summary metrics for quick assessment.
|
|
109
|
+
*/
|
|
110
|
+
summary: {
|
|
111
|
+
totalCrossRepoEdgesFromChangedFiles: number;
|
|
112
|
+
downstreamRepoCount: number;
|
|
113
|
+
upstreamRepoCount: number;
|
|
114
|
+
highConfidenceEdgeCount: number;
|
|
115
|
+
requiresCoordinatedDeploy: boolean;
|
|
116
|
+
coordinatedDeployRepos: string[];
|
|
117
|
+
};
|
|
118
|
+
/** Provenance for bounded federation — required for replay and reviewer trust. */
|
|
119
|
+
federationBoundary: FederatedExpansionBoundary;
|
|
120
|
+
}
|
|
121
|
+
export interface FederatedContextBuildInput {
|
|
122
|
+
/** Workspace name */
|
|
123
|
+
workspaceName: string;
|
|
124
|
+
/** All repos in the workspace topology */
|
|
125
|
+
repos: WorkspaceRepository[];
|
|
126
|
+
/** The repo name where development is currently happening */
|
|
127
|
+
primaryRepoName: string;
|
|
128
|
+
/** Files changed in the primary repo (relative paths) */
|
|
129
|
+
changedFiles: string[];
|
|
130
|
+
/**
|
|
131
|
+
* Pre-loaded brain maps keyed by repo name.
|
|
132
|
+
* Optional — improves file-level resolution accuracy.
|
|
133
|
+
*/
|
|
134
|
+
brainMaps?: Record<string, BrainRepositoryMap>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build the federated context package for a multi-repo workspace.
|
|
138
|
+
*
|
|
139
|
+
* This is the core function that answers: "What is the blast radius
|
|
140
|
+
* of this change across the entire service mesh?"
|
|
141
|
+
*/
|
|
142
|
+
export declare function buildFederatedContext(input: FederatedContextBuildInput): FederatedContextPackage;
|
|
143
|
+
export declare function formatFederatedContextSummary(pkg: FederatedContextPackage): string;
|
|
144
|
+
//# sourceMappingURL=federated-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federated-context.d.ts","sourceRoot":"","sources":["../../src/workspace/federated-context.ts"],"names":[],"mappings":"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"}
|