@ctxo/cli 0.9.3 → 0.10.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/README.md +39 -0
- package/dist/{chunk-HXEPS2XY.js → chunk-I6HLEK4G.js} +100 -3
- package/dist/chunk-I6HLEK4G.js.map +1 -0
- package/dist/{cli-router-CQJ7CN6E.js → cli-router-45W4IRYE.js} +449 -25
- package/dist/cli-router-45W4IRYE.js.map +1 -0
- package/dist/index.js +3 -90
- package/dist/index.js.map +1 -1
- package/llms-full.txt +46 -0
- package/llms.txt +7 -0
- package/package.json +4 -3
- package/skills/ctxo-review-pr/SKILL.md +10 -0
- package/skills/ctxo-safe-edit/SKILL.md +15 -0
- package/skills/ctxo-understand/SKILL.md +14 -0
- package/dist/chunk-HXEPS2XY.js.map +0 -1
- package/dist/cli-router-CQJ7CN6E.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ArchitecturalOverlay,
|
|
4
|
+
BlastRadiusCalculator,
|
|
4
5
|
BoundaryViolationDetector,
|
|
5
6
|
DeadCodeDetector,
|
|
6
7
|
DriftDetector,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
makeGlobMatcher,
|
|
17
18
|
maskingClusterLabelPatterns,
|
|
18
19
|
statsEnabled
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-I6HLEK4G.js";
|
|
20
21
|
import {
|
|
21
22
|
createLogger
|
|
22
23
|
} from "./chunk-6EKERTJ7.js";
|
|
@@ -760,94 +761,6 @@ function handleGetChangeIntelligence(storage, git, masking, staleness, ctxoRoot
|
|
|
760
761
|
|
|
761
762
|
// src/adapters/mcp/get-blast-radius.ts
|
|
762
763
|
import { z as z4 } from "zod";
|
|
763
|
-
|
|
764
|
-
// src/core/blast-radius/blast-radius-calculator.ts
|
|
765
|
-
var CONFIRMED_KINDS = /* @__PURE__ */ new Set(["calls", "extends", "implements"]);
|
|
766
|
-
var LIKELY_KINDS = /* @__PURE__ */ new Set(["uses"]);
|
|
767
|
-
var CONFIDENCE_RANK = {
|
|
768
|
-
confirmed: 2,
|
|
769
|
-
likely: 1,
|
|
770
|
-
potential: 0
|
|
771
|
-
};
|
|
772
|
-
function edgeKindToConfidence(kind) {
|
|
773
|
-
if (CONFIRMED_KINDS.has(kind)) return "confirmed";
|
|
774
|
-
if (LIKELY_KINDS.has(kind)) return "likely";
|
|
775
|
-
return "potential";
|
|
776
|
-
}
|
|
777
|
-
var BlastRadiusCalculator = class {
|
|
778
|
-
calculate(graph, symbolId, coChangeMap) {
|
|
779
|
-
if (!graph.hasNode(symbolId)) {
|
|
780
|
-
return { impactedSymbols: [], directDependentsCount: 0, confirmedCount: 0, likelyCount: 0, potentialCount: 0, overallRiskScore: 0 };
|
|
781
|
-
}
|
|
782
|
-
const sourceFile = symbolId.split("::")[0];
|
|
783
|
-
const visited = /* @__PURE__ */ new Set([symbolId]);
|
|
784
|
-
const rawEntries = [];
|
|
785
|
-
const queue = [{ id: symbolId, depth: 0 }];
|
|
786
|
-
while (queue.length > 0) {
|
|
787
|
-
const current = queue.shift();
|
|
788
|
-
const reverseEdges = graph.getReverseEdges(current.id);
|
|
789
|
-
const bestByNode = /* @__PURE__ */ new Map();
|
|
790
|
-
for (const edge of reverseEdges) {
|
|
791
|
-
if (visited.has(edge.from)) continue;
|
|
792
|
-
const conf = edgeKindToConfidence(edge.kind);
|
|
793
|
-
const existing = bestByNode.get(edge.from);
|
|
794
|
-
if (!existing) {
|
|
795
|
-
bestByNode.set(edge.from, { confidence: conf, kinds: /* @__PURE__ */ new Set([edge.kind]) });
|
|
796
|
-
} else {
|
|
797
|
-
existing.kinds.add(edge.kind);
|
|
798
|
-
if (CONFIDENCE_RANK[conf] > CONFIDENCE_RANK[existing.confidence]) {
|
|
799
|
-
existing.confidence = conf;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
for (const [nodeId, info] of bestByNode) {
|
|
804
|
-
visited.add(nodeId);
|
|
805
|
-
const depth = current.depth + 1;
|
|
806
|
-
const riskScore = 1 / Math.pow(depth, 0.7);
|
|
807
|
-
let confidence = info.confidence;
|
|
808
|
-
let coChangeFrequency;
|
|
809
|
-
if (coChangeMap) {
|
|
810
|
-
const nodeFile = nodeId.split("::")[0];
|
|
811
|
-
const coEntries = coChangeMap.get(sourceFile);
|
|
812
|
-
if (coEntries) {
|
|
813
|
-
const match = coEntries.find((e) => e.file1 === nodeFile || e.file2 === nodeFile);
|
|
814
|
-
if (match) {
|
|
815
|
-
coChangeFrequency = match.frequency;
|
|
816
|
-
if (confidence === "potential" && match.frequency > 0.5) {
|
|
817
|
-
confidence = "likely";
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
rawEntries.push({
|
|
823
|
-
symbolId: nodeId,
|
|
824
|
-
depth,
|
|
825
|
-
riskScore: Math.round(riskScore * 1e3) / 1e3,
|
|
826
|
-
confidence,
|
|
827
|
-
edgeKinds: [...info.kinds],
|
|
828
|
-
coChangeFrequency
|
|
829
|
-
});
|
|
830
|
-
queue.push({ id: nodeId, depth });
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
const blastSet = new Set(rawEntries.map((e) => e.symbolId));
|
|
834
|
-
blastSet.add(symbolId);
|
|
835
|
-
const entries = rawEntries.map((e) => ({
|
|
836
|
-
...e,
|
|
837
|
-
dependentCount: graph.getReverseEdges(e.symbolId).filter((re) => blastSet.has(re.from)).length
|
|
838
|
-
}));
|
|
839
|
-
entries.sort((a, b) => a.depth - b.depth);
|
|
840
|
-
const directDependentsCount = entries.filter((e) => e.depth === 1).length;
|
|
841
|
-
const totalRisk = entries.reduce((sum, e) => sum + e.riskScore, 0);
|
|
842
|
-
const overallRiskScore = Math.round(Math.min(totalRisk / Math.max(directDependentsCount, 1), 1) * 1e3) / 1e3;
|
|
843
|
-
const confirmedCount = entries.filter((e) => e.confidence === "confirmed").length;
|
|
844
|
-
const likelyCount = entries.filter((e) => e.confidence === "likely").length;
|
|
845
|
-
const potentialCount = entries.filter((e) => e.confidence === "potential").length;
|
|
846
|
-
return { impactedSymbols: entries, directDependentsCount, confirmedCount, likelyCount, potentialCount, overallRiskScore };
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
// src/adapters/mcp/get-blast-radius.ts
|
|
851
764
|
function computeClusterBreakdown(snapshot, rootSymbolId, impactedSymbolIds) {
|
|
852
765
|
if (impactedSymbolIds.length === 0) return void 0;
|
|
853
766
|
const assignment = /* @__PURE__ */ new Map();
|
|
@@ -2747,7 +2660,7 @@ async function main() {
|
|
|
2747
2660
|
const args = process.argv.slice(2);
|
|
2748
2661
|
const httpPortStr = process.env.CTXO_HTTP_PORT || (args.includes("--http") ? args[args.indexOf("--port") + 1] || "3001" : null);
|
|
2749
2662
|
if (!httpPortStr && args.length > 0) {
|
|
2750
|
-
const { CliRouter } = await import("./cli-router-
|
|
2663
|
+
const { CliRouter } = await import("./cli-router-45W4IRYE.js");
|
|
2751
2664
|
const router = new CliRouter(process.cwd());
|
|
2752
2665
|
await router.route(args);
|
|
2753
2666
|
return;
|