@pratik7368patil/anchor-core 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +123 -3
- package/dist/index.js +496 -210
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/db/schema.sql +13 -0
package/dist/index.js
CHANGED
|
@@ -657,6 +657,18 @@ CREATE TABLE IF NOT EXISTS org_anomaly_events (
|
|
|
657
657
|
created_at TEXT NOT NULL
|
|
658
658
|
);
|
|
659
659
|
|
|
660
|
+
CREATE TABLE IF NOT EXISTS org_graph_state (
|
|
661
|
+
org TEXT PRIMARY KEY,
|
|
662
|
+
last_built_at TEXT,
|
|
663
|
+
last_status TEXT NOT NULL DEFAULT 'unknown',
|
|
664
|
+
last_duration_ms INTEGER,
|
|
665
|
+
edge_count INTEGER NOT NULL DEFAULT 0,
|
|
666
|
+
api_contract_count INTEGER NOT NULL DEFAULT 0,
|
|
667
|
+
api_consumer_count INTEGER NOT NULL DEFAULT 0,
|
|
668
|
+
last_error TEXT,
|
|
669
|
+
updated_at TEXT NOT NULL
|
|
670
|
+
);
|
|
671
|
+
|
|
660
672
|
CREATE TABLE IF NOT EXISTS org_sync_checkpoints (
|
|
661
673
|
org TEXT NOT NULL,
|
|
662
674
|
repo TEXT NOT NULL,
|
|
@@ -694,6 +706,7 @@ CREATE INDEX IF NOT EXISTS idx_org_edges_target ON org_cross_repo_edges(org, tar
|
|
|
694
706
|
CREATE INDEX IF NOT EXISTS idx_org_consumers_provider ON org_api_consumers(org, provider_repo);
|
|
695
707
|
CREATE INDEX IF NOT EXISTS idx_org_consumers_consumer ON org_api_consumers(org, consumer_repo);
|
|
696
708
|
CREATE INDEX IF NOT EXISTS idx_org_anomalies_org ON org_anomaly_events(org, severity);
|
|
709
|
+
CREATE INDEX IF NOT EXISTS idx_org_graph_state_status ON org_graph_state(org, last_status);
|
|
697
710
|
`;
|
|
698
711
|
|
|
699
712
|
// src/rules/team-rules.ts
|
|
@@ -1573,7 +1586,8 @@ function checkSchema(db) {
|
|
|
1573
1586
|
"org_repo_state",
|
|
1574
1587
|
"org_cross_repo_edges",
|
|
1575
1588
|
"org_api_consumers",
|
|
1576
|
-
"org_anomaly_events"
|
|
1589
|
+
"org_anomaly_events",
|
|
1590
|
+
"org_graph_state"
|
|
1577
1591
|
].every(
|
|
1578
1592
|
(tableName) => db.prepare("SELECT name FROM sqlite_master WHERE name = ?").all(tableName).length > 0
|
|
1579
1593
|
);
|
|
@@ -7653,10 +7667,62 @@ function recordOrgIndexRun(db, input) {
|
|
|
7653
7667
|
JSON.stringify(input.failures ?? [])
|
|
7654
7668
|
);
|
|
7655
7669
|
}
|
|
7670
|
+
function recordOrgGraphState(db, input) {
|
|
7671
|
+
initializeSchema(db);
|
|
7672
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7673
|
+
db.prepare(
|
|
7674
|
+
`INSERT INTO org_graph_state
|
|
7675
|
+
(org, last_built_at, last_status, last_duration_ms, edge_count, api_contract_count,
|
|
7676
|
+
api_consumer_count, last_error, updated_at)
|
|
7677
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
7678
|
+
ON CONFLICT(org) DO UPDATE SET
|
|
7679
|
+
last_built_at = COALESCE(excluded.last_built_at, org_graph_state.last_built_at),
|
|
7680
|
+
last_status = excluded.last_status,
|
|
7681
|
+
last_duration_ms = COALESCE(excluded.last_duration_ms, org_graph_state.last_duration_ms),
|
|
7682
|
+
edge_count = excluded.edge_count,
|
|
7683
|
+
api_contract_count = excluded.api_contract_count,
|
|
7684
|
+
api_consumer_count = excluded.api_consumer_count,
|
|
7685
|
+
last_error = excluded.last_error,
|
|
7686
|
+
updated_at = excluded.updated_at`
|
|
7687
|
+
).run(
|
|
7688
|
+
input.org,
|
|
7689
|
+
input.builtAt ?? null,
|
|
7690
|
+
input.status,
|
|
7691
|
+
input.durationMs ?? null,
|
|
7692
|
+
input.edgeCount ?? 0,
|
|
7693
|
+
input.apiContractCount ?? 0,
|
|
7694
|
+
input.apiConsumerCount ?? 0,
|
|
7695
|
+
input.error ?? null,
|
|
7696
|
+
now
|
|
7697
|
+
);
|
|
7698
|
+
}
|
|
7699
|
+
function getOrgGraphState(db, org) {
|
|
7700
|
+
initializeSchema(db);
|
|
7701
|
+
const row = db.prepare("SELECT * FROM org_graph_state WHERE org = ?").get(org);
|
|
7702
|
+
if (!row) return void 0;
|
|
7703
|
+
return {
|
|
7704
|
+
org: row.org,
|
|
7705
|
+
lastBuiltAt: row.last_built_at ?? void 0,
|
|
7706
|
+
lastStatus: row.last_status ?? void 0,
|
|
7707
|
+
lastDurationMs: row.last_duration_ms ?? void 0,
|
|
7708
|
+
edgeCount: row.edge_count ?? void 0,
|
|
7709
|
+
apiContractCount: row.api_contract_count ?? void 0,
|
|
7710
|
+
apiConsumerCount: row.api_consumer_count ?? void 0,
|
|
7711
|
+
lastError: row.last_error ?? void 0
|
|
7712
|
+
};
|
|
7713
|
+
}
|
|
7656
7714
|
function count(db, table, where = "", params = []) {
|
|
7657
7715
|
const row = db.prepare(`SELECT COUNT(*) AS count FROM ${table} ${where}`).get(...params);
|
|
7658
7716
|
return row.count;
|
|
7659
7717
|
}
|
|
7718
|
+
function getOrgGraphCounts(db, org) {
|
|
7719
|
+
initializeSchema(db);
|
|
7720
|
+
return {
|
|
7721
|
+
edges: count(db, "org_cross_repo_edges", "WHERE org = ?", [org]),
|
|
7722
|
+
apiContracts: count(db, "org_api_contracts", "WHERE org = ?", [org]),
|
|
7723
|
+
apiConsumers: count(db, "org_api_consumers", "WHERE org = ?", [org])
|
|
7724
|
+
};
|
|
7725
|
+
}
|
|
7660
7726
|
function grade(score) {
|
|
7661
7727
|
if (score <= 0) return "empty";
|
|
7662
7728
|
if (score < 35) return "poor";
|
|
@@ -7678,8 +7744,10 @@ function getOrgStatus(db, config, baseDir) {
|
|
|
7678
7744
|
const codeChunkCount = count(db, "code_chunks");
|
|
7679
7745
|
const wisdomUnitCount = count(db, "wisdom_units");
|
|
7680
7746
|
const crossRepoEdgeCount = count(db, "org_cross_repo_edges", "WHERE org = ?", [config.org]);
|
|
7747
|
+
const apiContractCount = count(db, "org_api_contracts", "WHERE org = ?", [config.org]);
|
|
7681
7748
|
const apiConsumerCount = count(db, "org_api_consumers", "WHERE org = ?", [config.org]);
|
|
7682
7749
|
const anomalyCount = count(db, "org_anomaly_events", "WHERE org = ?", [config.org]);
|
|
7750
|
+
const graphState = db.prepare("SELECT * FROM org_graph_state WHERE org = ?").get(config.org);
|
|
7683
7751
|
let score = 0;
|
|
7684
7752
|
const reasons = [];
|
|
7685
7753
|
if (enabledRepos.length > 0) {
|
|
@@ -7718,8 +7786,13 @@ function getOrgStatus(db, config, baseDir) {
|
|
|
7718
7786
|
codeChunkCount,
|
|
7719
7787
|
wisdomUnitCount,
|
|
7720
7788
|
crossRepoEdgeCount,
|
|
7789
|
+
apiContractCount,
|
|
7721
7790
|
apiConsumerCount,
|
|
7722
7791
|
anomalyCount,
|
|
7792
|
+
graphLastBuiltAt: graphState?.last_built_at ?? void 0,
|
|
7793
|
+
graphLastStatus: graphState?.last_status ?? void 0,
|
|
7794
|
+
graphLastDurationMs: graphState?.last_duration_ms ?? void 0,
|
|
7795
|
+
graphLastError: graphState?.last_error ?? void 0,
|
|
7723
7796
|
coverageScore: score,
|
|
7724
7797
|
coverageGrade: grade(score),
|
|
7725
7798
|
coverageReasons: reasons,
|
|
@@ -7845,16 +7918,32 @@ async function cloneOrgRepos(input) {
|
|
|
7845
7918
|
const repo = repos[next];
|
|
7846
7919
|
next += 1;
|
|
7847
7920
|
if (!repo) continue;
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7921
|
+
const current = next;
|
|
7922
|
+
input.onProgress?.({
|
|
7923
|
+
stage: "cloning_or_pulling_repo",
|
|
7924
|
+
org: input.config.org,
|
|
7925
|
+
repo: repo.fullName,
|
|
7926
|
+
current,
|
|
7927
|
+
total: repos.length
|
|
7928
|
+
});
|
|
7929
|
+
const result = cloneOrPullOrgRepo({
|
|
7930
|
+
org: input.config.org,
|
|
7931
|
+
repo,
|
|
7932
|
+
db: input.db,
|
|
7933
|
+
baseDir: input.baseDir,
|
|
7934
|
+
runner: input.runner
|
|
7935
|
+
});
|
|
7936
|
+
results.push(result);
|
|
7937
|
+
input.onProgress?.({
|
|
7938
|
+
stage: "cloned_or_pulled_repo",
|
|
7939
|
+
org: input.config.org,
|
|
7940
|
+
repo: repo.fullName,
|
|
7941
|
+
current,
|
|
7942
|
+
total: repos.length,
|
|
7943
|
+
cloned: result.cloned,
|
|
7944
|
+
pulled: result.pulled,
|
|
7945
|
+
error: result.error
|
|
7946
|
+
});
|
|
7858
7947
|
}
|
|
7859
7948
|
}
|
|
7860
7949
|
await Promise.all(Array.from({ length: Math.min(limit, repos.length) }, () => worker()));
|
|
@@ -7952,210 +8041,340 @@ function isApiConsumerText(text) {
|
|
|
7952
8041
|
function evidenceJson(evidence) {
|
|
7953
8042
|
return JSON.stringify(evidence);
|
|
7954
8043
|
}
|
|
7955
|
-
function
|
|
8044
|
+
function shouldEmitProgress(current, total, interval = 100) {
|
|
8045
|
+
return current === 1 || current === total || current % interval === 0;
|
|
8046
|
+
}
|
|
8047
|
+
function resolveOptions(baseDirOrOptions) {
|
|
8048
|
+
return typeof baseDirOrOptions === "string" ? { baseDir: baseDirOrOptions } : baseDirOrOptions ?? {};
|
|
8049
|
+
}
|
|
8050
|
+
function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
7956
8051
|
initializeSchema(db);
|
|
7957
|
-
const
|
|
7958
|
-
const
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
const
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
edge.targetPath ?? "",
|
|
7972
|
-
edge.relationship
|
|
7973
|
-
].join("\0");
|
|
7974
|
-
if (edges.some(
|
|
7975
|
-
(existing) => [
|
|
7976
|
-
existing.sourceRepo,
|
|
7977
|
-
existing.sourcePath,
|
|
7978
|
-
existing.targetRepo,
|
|
7979
|
-
existing.targetPath ?? "",
|
|
7980
|
-
existing.relationship
|
|
7981
|
-
].join("\0") === key
|
|
7982
|
-
)) {
|
|
7983
|
-
return;
|
|
7984
|
-
}
|
|
7985
|
-
edges.push(edge);
|
|
7986
|
-
};
|
|
7987
|
-
for (const repo of enabledRepos) {
|
|
7988
|
-
const manifest = readPackageManifest(orgRepoLocalPath(config.org, repo, baseDir));
|
|
7989
|
-
for (const dependency of dependenciesFor(manifest)) {
|
|
7990
|
-
const targetRepo = packageToRepo.get(dependency);
|
|
7991
|
-
if (!targetRepo || targetRepo === repo.fullName) continue;
|
|
7992
|
-
addEdge({
|
|
7993
|
-
org: config.org,
|
|
7994
|
-
sourceRepo: repo.fullName,
|
|
7995
|
-
sourcePath: "package.json",
|
|
7996
|
-
targetRepo,
|
|
7997
|
-
relationship: "depends_on_package",
|
|
7998
|
-
evidence: [fileEvidence(repo.fullName, "package.json", `depends on ${dependency}`)],
|
|
7999
|
-
confidence: 0.9
|
|
8000
|
-
});
|
|
8001
|
-
}
|
|
8002
|
-
}
|
|
8003
|
-
const imports = db.prepare(
|
|
8004
|
-
`SELECT r.full_name AS repo, ci.source_path, ci.specifier, ci.imported_path, ci.imported_symbols_json
|
|
8005
|
-
FROM code_imports ci
|
|
8006
|
-
JOIN repositories r ON r.id = ci.repo_id`
|
|
8007
|
-
).all();
|
|
8008
|
-
for (const item of imports) {
|
|
8009
|
-
const sourceRepo = repoByName.get(item.repo);
|
|
8010
|
-
if (!sourceRepo) continue;
|
|
8011
|
-
for (const [targetRepo, names] of packageNames.entries()) {
|
|
8012
|
-
if (targetRepo === item.repo) continue;
|
|
8013
|
-
const matchedName = names.find(
|
|
8014
|
-
(name) => item.specifier === name || item.specifier.startsWith(`${name}/`)
|
|
8015
|
-
);
|
|
8016
|
-
if (!matchedName) continue;
|
|
8017
|
-
addEdge({
|
|
8018
|
-
org: config.org,
|
|
8019
|
-
sourceRepo: item.repo,
|
|
8020
|
-
sourcePath: item.source_path,
|
|
8021
|
-
targetRepo,
|
|
8022
|
-
targetPath: item.imported_path ?? void 0,
|
|
8023
|
-
relationship: "imports",
|
|
8024
|
-
evidence: [
|
|
8025
|
-
fileEvidence(
|
|
8026
|
-
item.repo,
|
|
8027
|
-
item.source_path,
|
|
8028
|
-
`imports ${sanitizeHistoricalText(matchedName)}`
|
|
8029
|
-
)
|
|
8030
|
-
],
|
|
8031
|
-
confidence: parseJsonArray9(item.imported_symbols_json).length > 0 ? 0.88 : 0.76
|
|
8032
|
-
});
|
|
8033
|
-
}
|
|
8034
|
-
}
|
|
8035
|
-
const chunks = db.prepare(
|
|
8036
|
-
`SELECT r.full_name AS repo, cc.file_path, cc.sanitized_text, cc.symbols_json
|
|
8037
|
-
FROM code_chunks cc
|
|
8038
|
-
JOIN repositories r ON r.id = cc.repo_id`
|
|
8039
|
-
).all();
|
|
8040
|
-
const apiContracts = chunks.filter((chunk) => repoByName.has(chunk.repo) && isApiProviderPath(chunk.file_path)).flatMap(
|
|
8041
|
-
(chunk) => extractContracts(chunk.sanitized_text).map((contract) => ({
|
|
8042
|
-
repo: chunk.repo,
|
|
8043
|
-
filePath: chunk.file_path,
|
|
8044
|
-
contract,
|
|
8045
|
-
evidence: [fileEvidence(chunk.repo, chunk.file_path, `defines ${contract}`)],
|
|
8046
|
-
confidence: 0.74
|
|
8047
|
-
}))
|
|
8048
|
-
);
|
|
8049
|
-
const apiConsumers = [];
|
|
8050
|
-
for (const contract of apiContracts) {
|
|
8051
|
-
for (const chunk of chunks) {
|
|
8052
|
-
if (chunk.repo === contract.repo || !repoByName.has(chunk.repo)) continue;
|
|
8053
|
-
if (!isApiConsumerText(chunk.sanitized_text)) continue;
|
|
8054
|
-
if (!chunk.sanitized_text.includes(contract.contract)) continue;
|
|
8055
|
-
const consumer = {
|
|
8056
|
-
org: config.org,
|
|
8057
|
-
providerRepo: contract.repo,
|
|
8058
|
-
providerPath: contract.filePath,
|
|
8059
|
-
consumerRepo: chunk.repo,
|
|
8060
|
-
consumerPath: chunk.file_path,
|
|
8061
|
-
contract: contract.contract,
|
|
8062
|
-
evidence: [
|
|
8063
|
-
...contract.evidence,
|
|
8064
|
-
fileEvidence(chunk.repo, chunk.file_path, `consumes ${contract.contract}`)
|
|
8065
|
-
],
|
|
8066
|
-
confidence: 0.86
|
|
8067
|
-
};
|
|
8068
|
-
apiConsumers.push(consumer);
|
|
8069
|
-
addEdge({
|
|
8070
|
-
org: config.org,
|
|
8071
|
-
sourceRepo: chunk.repo,
|
|
8072
|
-
sourcePath: chunk.file_path,
|
|
8073
|
-
targetRepo: contract.repo,
|
|
8074
|
-
targetPath: contract.filePath,
|
|
8075
|
-
relationship: "api_consumer",
|
|
8076
|
-
evidence: consumer.evidence,
|
|
8077
|
-
confidence: consumer.confidence
|
|
8078
|
-
});
|
|
8052
|
+
const options = resolveOptions(baseDirOrOptions);
|
|
8053
|
+
const startedAt = Date.now();
|
|
8054
|
+
try {
|
|
8055
|
+
options.onProgress?.({
|
|
8056
|
+
stage: "loading_package_manifests",
|
|
8057
|
+
org: config.org,
|
|
8058
|
+
totalRepos: config.repos.filter((repo) => repo.enabled).length
|
|
8059
|
+
});
|
|
8060
|
+
const packageNames = repoPackageNames(config, options.baseDir);
|
|
8061
|
+
const enabledRepos = config.repos.filter((repo) => repo.enabled);
|
|
8062
|
+
const repoByName = new Map(enabledRepos.map((repo) => [repo.fullName, repo]));
|
|
8063
|
+
const packageToRepo = /* @__PURE__ */ new Map();
|
|
8064
|
+
for (const [repo, names] of packageNames.entries()) {
|
|
8065
|
+
for (const name of names) packageToRepo.set(name, repo);
|
|
8079
8066
|
}
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
const
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
for (const edge of edges) {
|
|
8092
|
-
insertEdge.run(
|
|
8093
|
-
`oge_${stableId([edge.org, edge.sourceRepo, edge.sourcePath, edge.targetRepo, edge.targetPath ?? "", edge.relationship])}`,
|
|
8094
|
-
edge.org,
|
|
8067
|
+
options.onProgress?.({
|
|
8068
|
+
stage: "loaded_package_manifests",
|
|
8069
|
+
org: config.org,
|
|
8070
|
+
repos: enabledRepos.length,
|
|
8071
|
+
packageNames: packageToRepo.size
|
|
8072
|
+
});
|
|
8073
|
+
const edges = [];
|
|
8074
|
+
const edgeKeys = /* @__PURE__ */ new Set();
|
|
8075
|
+
const addEdge = (edge) => {
|
|
8076
|
+
if (edge.sourceRepo === edge.targetRepo) return;
|
|
8077
|
+
const key = [
|
|
8095
8078
|
edge.sourceRepo,
|
|
8096
8079
|
edge.sourcePath,
|
|
8097
8080
|
edge.targetRepo,
|
|
8098
|
-
edge.targetPath ??
|
|
8099
|
-
edge.relationship
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
);
|
|
8104
|
-
}
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8081
|
+
edge.targetPath ?? "",
|
|
8082
|
+
edge.relationship
|
|
8083
|
+
].join("\0");
|
|
8084
|
+
if (edgeKeys.has(key)) return;
|
|
8085
|
+
edgeKeys.add(key);
|
|
8086
|
+
edges.push(edge);
|
|
8087
|
+
};
|
|
8088
|
+
enabledRepos.forEach((repo, index) => {
|
|
8089
|
+
const manifest = readPackageManifest(orgRepoLocalPath(config.org, repo, options.baseDir));
|
|
8090
|
+
for (const dependency of dependenciesFor(manifest)) {
|
|
8091
|
+
const targetRepo = packageToRepo.get(dependency);
|
|
8092
|
+
if (!targetRepo || targetRepo === repo.fullName) continue;
|
|
8093
|
+
addEdge({
|
|
8094
|
+
org: config.org,
|
|
8095
|
+
sourceRepo: repo.fullName,
|
|
8096
|
+
sourcePath: "package.json",
|
|
8097
|
+
targetRepo,
|
|
8098
|
+
relationship: "depends_on_package",
|
|
8099
|
+
evidence: [
|
|
8100
|
+
fileEvidence(
|
|
8101
|
+
repo.fullName,
|
|
8102
|
+
"package.json",
|
|
8103
|
+
`depends on ${sanitizeHistoricalText(dependency)}`
|
|
8104
|
+
)
|
|
8105
|
+
],
|
|
8106
|
+
confidence: 0.9
|
|
8107
|
+
});
|
|
8108
|
+
}
|
|
8109
|
+
options.onProgress?.({
|
|
8110
|
+
stage: "building_package_edges",
|
|
8111
|
+
org: config.org,
|
|
8112
|
+
current: index + 1,
|
|
8113
|
+
total: enabledRepos.length,
|
|
8114
|
+
repo: repo.fullName,
|
|
8115
|
+
edges: edges.length
|
|
8116
|
+
});
|
|
8117
|
+
});
|
|
8118
|
+
options.onProgress?.({ stage: "loading_imports", org: config.org });
|
|
8119
|
+
const imports = db.prepare(
|
|
8120
|
+
`SELECT r.full_name AS repo, ci.source_path, ci.specifier, ci.imported_path, ci.imported_symbols_json
|
|
8121
|
+
FROM code_imports ci
|
|
8122
|
+
JOIN repositories r ON r.id = ci.repo_id`
|
|
8123
|
+
).all();
|
|
8124
|
+
const packageMatchers = [...packageNames.entries()].flatMap(([repo, names]) => names.map((name) => ({ repo, name }))).sort((a, b) => b.name.length - a.name.length);
|
|
8125
|
+
imports.forEach((item, index) => {
|
|
8126
|
+
const sourceRepo = repoByName.get(item.repo);
|
|
8127
|
+
if (!sourceRepo) return;
|
|
8128
|
+
for (const candidate of packageMatchers) {
|
|
8129
|
+
if (candidate.repo === item.repo) continue;
|
|
8130
|
+
const matched = item.specifier === candidate.name || item.specifier.startsWith(`${candidate.name}/`);
|
|
8131
|
+
if (!matched) continue;
|
|
8132
|
+
addEdge({
|
|
8133
|
+
org: config.org,
|
|
8134
|
+
sourceRepo: item.repo,
|
|
8135
|
+
sourcePath: item.source_path,
|
|
8136
|
+
targetRepo: candidate.repo,
|
|
8137
|
+
targetPath: item.imported_path ?? void 0,
|
|
8138
|
+
relationship: "imports",
|
|
8139
|
+
evidence: [
|
|
8140
|
+
fileEvidence(
|
|
8141
|
+
item.repo,
|
|
8142
|
+
item.source_path,
|
|
8143
|
+
`imports ${sanitizeHistoricalText(candidate.name)}`
|
|
8144
|
+
)
|
|
8145
|
+
],
|
|
8146
|
+
confidence: parseJsonArray9(item.imported_symbols_json).length > 0 ? 0.88 : 0.76
|
|
8147
|
+
});
|
|
8148
|
+
break;
|
|
8149
|
+
}
|
|
8150
|
+
if (shouldEmitProgress(index + 1, imports.length)) {
|
|
8151
|
+
options.onProgress?.({
|
|
8152
|
+
stage: "building_import_edges",
|
|
8153
|
+
org: config.org,
|
|
8154
|
+
current: index + 1,
|
|
8155
|
+
total: imports.length,
|
|
8156
|
+
sourcePath: item.source_path,
|
|
8157
|
+
edges: edges.length
|
|
8158
|
+
});
|
|
8159
|
+
}
|
|
8160
|
+
});
|
|
8161
|
+
options.onProgress?.({ stage: "loading_code_chunks", org: config.org });
|
|
8162
|
+
const chunks = db.prepare(
|
|
8163
|
+
`SELECT r.full_name AS repo, cc.file_path, cc.sanitized_text, cc.symbols_json
|
|
8164
|
+
FROM code_chunks cc
|
|
8165
|
+
JOIN repositories r ON r.id = cc.repo_id`
|
|
8166
|
+
).all();
|
|
8167
|
+
const providerChunks = chunks.filter(
|
|
8168
|
+
(chunk) => repoByName.has(chunk.repo) && isApiProviderPath(chunk.file_path)
|
|
8109
8169
|
);
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
contract
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8170
|
+
const apiContracts = [];
|
|
8171
|
+
const contractKeys = /* @__PURE__ */ new Set();
|
|
8172
|
+
const contractsByToken = /* @__PURE__ */ new Map();
|
|
8173
|
+
providerChunks.forEach((chunk, index) => {
|
|
8174
|
+
for (const contract of extractContracts(chunk.sanitized_text)) {
|
|
8175
|
+
const sanitizedContract = sanitizeHistoricalText(contract);
|
|
8176
|
+
const key = [chunk.repo, chunk.file_path, sanitizedContract].join("\0");
|
|
8177
|
+
if (contractKeys.has(key)) continue;
|
|
8178
|
+
contractKeys.add(key);
|
|
8179
|
+
const apiContract = {
|
|
8180
|
+
repo: chunk.repo,
|
|
8181
|
+
filePath: chunk.file_path,
|
|
8182
|
+
contract: sanitizedContract,
|
|
8183
|
+
evidence: [fileEvidence(chunk.repo, chunk.file_path, `defines ${sanitizedContract}`)],
|
|
8184
|
+
confidence: 0.74
|
|
8185
|
+
};
|
|
8186
|
+
apiContracts.push(apiContract);
|
|
8187
|
+
const bucket = contractsByToken.get(sanitizedContract) ?? [];
|
|
8188
|
+
bucket.push(apiContract);
|
|
8189
|
+
contractsByToken.set(sanitizedContract, bucket);
|
|
8190
|
+
}
|
|
8191
|
+
if (shouldEmitProgress(index + 1, providerChunks.length)) {
|
|
8192
|
+
options.onProgress?.({
|
|
8193
|
+
stage: "extracting_api_contracts",
|
|
8194
|
+
org: config.org,
|
|
8195
|
+
current: index + 1,
|
|
8196
|
+
total: providerChunks.length,
|
|
8197
|
+
filePath: chunk.file_path,
|
|
8198
|
+
contracts: apiContracts.length
|
|
8199
|
+
});
|
|
8200
|
+
}
|
|
8201
|
+
});
|
|
8202
|
+
const apiConsumers = [];
|
|
8203
|
+
const consumerKeys = /* @__PURE__ */ new Set();
|
|
8204
|
+
const consumerChunks = chunks.filter(
|
|
8205
|
+
(chunk) => repoByName.has(chunk.repo) && isApiConsumerText(chunk.sanitized_text)
|
|
8126
8206
|
);
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8207
|
+
consumerChunks.forEach((chunk, index) => {
|
|
8208
|
+
const consumerTokens = extractContracts(chunk.sanitized_text);
|
|
8209
|
+
let chunkMatches = 0;
|
|
8210
|
+
for (const token of consumerTokens) {
|
|
8211
|
+
const contracts = contractsByToken.get(sanitizeHistoricalText(token));
|
|
8212
|
+
if (!contracts) continue;
|
|
8213
|
+
for (const contract of contracts) {
|
|
8214
|
+
if (chunk.repo === contract.repo) continue;
|
|
8215
|
+
const consumerKey = [
|
|
8216
|
+
contract.repo,
|
|
8217
|
+
contract.filePath,
|
|
8218
|
+
chunk.repo,
|
|
8219
|
+
chunk.file_path,
|
|
8220
|
+
contract.contract
|
|
8221
|
+
].join("\0");
|
|
8222
|
+
if (consumerKeys.has(consumerKey)) continue;
|
|
8223
|
+
consumerKeys.add(consumerKey);
|
|
8224
|
+
const consumer = {
|
|
8225
|
+
org: config.org,
|
|
8226
|
+
providerRepo: contract.repo,
|
|
8227
|
+
providerPath: contract.filePath,
|
|
8228
|
+
consumerRepo: chunk.repo,
|
|
8229
|
+
consumerPath: chunk.file_path,
|
|
8230
|
+
contract: contract.contract,
|
|
8231
|
+
evidence: [
|
|
8232
|
+
...contract.evidence,
|
|
8233
|
+
fileEvidence(chunk.repo, chunk.file_path, `consumes ${contract.contract}`)
|
|
8234
|
+
],
|
|
8235
|
+
confidence: 0.86
|
|
8236
|
+
};
|
|
8237
|
+
chunkMatches += 1;
|
|
8238
|
+
apiConsumers.push(consumer);
|
|
8239
|
+
addEdge({
|
|
8240
|
+
org: config.org,
|
|
8241
|
+
sourceRepo: chunk.repo,
|
|
8242
|
+
sourcePath: chunk.file_path,
|
|
8243
|
+
targetRepo: contract.repo,
|
|
8244
|
+
targetPath: contract.filePath,
|
|
8245
|
+
relationship: "api_consumer",
|
|
8246
|
+
evidence: consumer.evidence,
|
|
8247
|
+
confidence: consumer.confidence
|
|
8248
|
+
});
|
|
8249
|
+
}
|
|
8250
|
+
}
|
|
8251
|
+
if (shouldEmitProgress(index + 1, consumerChunks.length)) {
|
|
8252
|
+
options.onProgress?.({
|
|
8253
|
+
stage: "matching_api_consumers",
|
|
8254
|
+
org: config.org,
|
|
8255
|
+
current: index + 1,
|
|
8256
|
+
total: consumerChunks.length,
|
|
8257
|
+
filePath: chunk.file_path,
|
|
8258
|
+
matches: chunkMatches
|
|
8259
|
+
});
|
|
8260
|
+
}
|
|
8261
|
+
});
|
|
8262
|
+
options.onProgress?.({
|
|
8263
|
+
stage: "writing_org_graph",
|
|
8264
|
+
org: config.org,
|
|
8265
|
+
edges: edges.length,
|
|
8266
|
+
apiContracts: apiContracts.length,
|
|
8267
|
+
apiConsumers: apiConsumers.length
|
|
8268
|
+
});
|
|
8269
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8270
|
+
const transaction = db.transaction(() => {
|
|
8271
|
+
db.prepare("DELETE FROM org_cross_repo_edges WHERE org = ?").run(config.org);
|
|
8272
|
+
db.prepare("DELETE FROM org_api_contracts WHERE org = ?").run(config.org);
|
|
8273
|
+
db.prepare("DELETE FROM org_api_consumers WHERE org = ?").run(config.org);
|
|
8274
|
+
const insertEdge = db.prepare(
|
|
8275
|
+
`INSERT INTO org_cross_repo_edges
|
|
8276
|
+
(id, org, source_repo, source_path, target_repo, target_path, relationship, evidence_json, confidence, created_at)
|
|
8277
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
8278
|
+
);
|
|
8279
|
+
for (const edge of edges) {
|
|
8280
|
+
insertEdge.run(
|
|
8281
|
+
`oge_${stableId([edge.org, edge.sourceRepo, edge.sourcePath, edge.targetRepo, edge.targetPath ?? "", edge.relationship])}`,
|
|
8282
|
+
edge.org,
|
|
8283
|
+
edge.sourceRepo,
|
|
8284
|
+
edge.sourcePath,
|
|
8285
|
+
edge.targetRepo,
|
|
8286
|
+
edge.targetPath ?? null,
|
|
8287
|
+
edge.relationship,
|
|
8288
|
+
evidenceJson(edge.evidence),
|
|
8289
|
+
edge.confidence,
|
|
8290
|
+
now
|
|
8291
|
+
);
|
|
8292
|
+
}
|
|
8293
|
+
const insertContract = db.prepare(
|
|
8294
|
+
`INSERT INTO org_api_contracts
|
|
8295
|
+
(id, org, repo, file_path, contract, evidence_json, confidence, created_at)
|
|
8296
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
8297
|
+
);
|
|
8298
|
+
for (const contract of apiContracts) {
|
|
8299
|
+
insertContract.run(
|
|
8300
|
+
`oac_${stableId([config.org, contract.repo, contract.filePath, contract.contract])}`,
|
|
8301
|
+
config.org,
|
|
8302
|
+
contract.repo,
|
|
8303
|
+
contract.filePath,
|
|
8304
|
+
sanitizeHistoricalText(contract.contract),
|
|
8305
|
+
evidenceJson(contract.evidence),
|
|
8306
|
+
contract.confidence,
|
|
8307
|
+
now
|
|
8308
|
+
);
|
|
8309
|
+
}
|
|
8310
|
+
const insertConsumer = db.prepare(
|
|
8311
|
+
`INSERT INTO org_api_consumers
|
|
8312
|
+
(id, org, provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json, confidence, created_at)
|
|
8313
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
8314
|
+
);
|
|
8315
|
+
for (const consumer of apiConsumers) {
|
|
8316
|
+
insertConsumer.run(
|
|
8317
|
+
`oap_${stableId([
|
|
8318
|
+
consumer.org,
|
|
8319
|
+
consumer.providerRepo,
|
|
8320
|
+
consumer.providerPath ?? "",
|
|
8321
|
+
consumer.consumerRepo,
|
|
8322
|
+
consumer.consumerPath,
|
|
8323
|
+
consumer.contract
|
|
8324
|
+
])}`,
|
|
8130
8325
|
consumer.org,
|
|
8131
8326
|
consumer.providerRepo,
|
|
8132
|
-
consumer.providerPath ??
|
|
8327
|
+
consumer.providerPath ?? null,
|
|
8133
8328
|
consumer.consumerRepo,
|
|
8134
8329
|
consumer.consumerPath,
|
|
8135
|
-
consumer.contract
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8330
|
+
sanitizeHistoricalText(consumer.contract),
|
|
8331
|
+
evidenceJson(consumer.evidence),
|
|
8332
|
+
consumer.confidence,
|
|
8333
|
+
now
|
|
8334
|
+
);
|
|
8335
|
+
}
|
|
8336
|
+
});
|
|
8337
|
+
transaction();
|
|
8338
|
+
const durationMs = Date.now() - startedAt;
|
|
8339
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8340
|
+
recordOrgGraphState(db, {
|
|
8341
|
+
org: config.org,
|
|
8342
|
+
status: "success",
|
|
8343
|
+
builtAt: finishedAt,
|
|
8344
|
+
durationMs,
|
|
8345
|
+
edgeCount: edges.length,
|
|
8346
|
+
apiContractCount: apiContracts.length,
|
|
8347
|
+
apiConsumerCount: apiConsumers.length
|
|
8348
|
+
});
|
|
8349
|
+
options.onProgress?.({
|
|
8350
|
+
stage: "completed_org_graph",
|
|
8351
|
+
org: config.org,
|
|
8352
|
+
edges: edges.length,
|
|
8353
|
+
apiContracts: apiContracts.length,
|
|
8354
|
+
apiConsumers: apiConsumers.length,
|
|
8355
|
+
durationMs
|
|
8356
|
+
});
|
|
8357
|
+
return {
|
|
8358
|
+
edges,
|
|
8359
|
+
apiConsumers,
|
|
8360
|
+
apiContracts,
|
|
8361
|
+
durationMs
|
|
8362
|
+
};
|
|
8363
|
+
} catch (error) {
|
|
8364
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8365
|
+
recordOrgGraphState(db, {
|
|
8366
|
+
org: config.org,
|
|
8367
|
+
status: "failed",
|
|
8368
|
+
durationMs: Date.now() - startedAt,
|
|
8369
|
+
error: message
|
|
8370
|
+
});
|
|
8371
|
+
throw error;
|
|
8372
|
+
}
|
|
8155
8373
|
}
|
|
8156
8374
|
|
|
8157
8375
|
// src/org/index.ts
|
|
8158
8376
|
import fs13 from "fs";
|
|
8377
|
+
var ORG_SYNC_RESUME_WINDOW_MS = 12 * 60 * 60 * 1e3;
|
|
8159
8378
|
function readCommit(runner, cwd) {
|
|
8160
8379
|
try {
|
|
8161
8380
|
return runner("git", ["rev-parse", "HEAD"], { cwd });
|
|
@@ -8166,6 +8385,27 @@ function readCommit(runner, cwd) {
|
|
|
8166
8385
|
function missingCloneError(repo, localPath) {
|
|
8167
8386
|
return `Repo ${repo} is not cloned at ${localPath}. Run anchor org clone --repo ${repo} --org <org>.`;
|
|
8168
8387
|
}
|
|
8388
|
+
function latestIsoDate(dates) {
|
|
8389
|
+
return dates.filter((date) => Boolean(date)).sort().at(-1);
|
|
8390
|
+
}
|
|
8391
|
+
function graphIsFreshForState(input) {
|
|
8392
|
+
const latestRepoIndexAt = latestIsoDate([input.lastPrSyncAt, input.lastCodeIndexedAt]);
|
|
8393
|
+
return Boolean(
|
|
8394
|
+
latestRepoIndexAt && input.graphStatus === "success" && input.graphBuiltAt && input.graphBuiltAt >= latestRepoIndexAt
|
|
8395
|
+
);
|
|
8396
|
+
}
|
|
8397
|
+
function isWithinResumeWindow(date) {
|
|
8398
|
+
const parsed = Date.parse(date);
|
|
8399
|
+
return Number.isFinite(parsed) && Date.now() - parsed <= ORG_SYNC_RESUME_WINDOW_MS;
|
|
8400
|
+
}
|
|
8401
|
+
function shouldSkipPrFetchForResume(input) {
|
|
8402
|
+
if (input.options.command !== "org sync") return false;
|
|
8403
|
+
if (input.options.force || input.options.since || input.options.noGraph) return false;
|
|
8404
|
+
if (input.options.codeOnly || input.options.prsOnly) return false;
|
|
8405
|
+
if (!input.lastPrSyncAt) return false;
|
|
8406
|
+
if (!isWithinResumeWindow(input.lastPrSyncAt)) return false;
|
|
8407
|
+
return !graphIsFreshForState(input);
|
|
8408
|
+
}
|
|
8169
8409
|
async function indexOrgRepos(db, config, options = {}) {
|
|
8170
8410
|
initializeSchema(db);
|
|
8171
8411
|
syncOrgConfigToDatabase(db, config, options.baseDir);
|
|
@@ -8173,9 +8413,11 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
8173
8413
|
(repo) => repo.enabled && (!options.repo || repo.fullName === options.repo)
|
|
8174
8414
|
);
|
|
8175
8415
|
const runner = options.runner ?? defaultGitCommandRunner;
|
|
8416
|
+
const fetchPullRequests = options.fetchPullRequests ?? fetchMergedPullRequests;
|
|
8176
8417
|
const auth = options.token ? { token: options.token } : resolveGitHubToken();
|
|
8177
8418
|
const results = [];
|
|
8178
8419
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8420
|
+
const graphState = getOrgGraphState(db, config.org);
|
|
8179
8421
|
for (const repo of repos) {
|
|
8180
8422
|
const localPath = orgRepoLocalPath(config.org, repo, options.baseDir);
|
|
8181
8423
|
const repoStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -8187,16 +8429,32 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
8187
8429
|
const state = getOrgRepoState(db, config.org, repo.fullName);
|
|
8188
8430
|
let history;
|
|
8189
8431
|
let code;
|
|
8432
|
+
let skippedHistory = false;
|
|
8433
|
+
let historySkippedReason;
|
|
8190
8434
|
const repoFailures = [];
|
|
8191
8435
|
if (!options.codeOnly) {
|
|
8192
|
-
if (
|
|
8436
|
+
if (shouldSkipPrFetchForResume({
|
|
8437
|
+
options,
|
|
8438
|
+
lastPrSyncAt: state?.lastPrSyncAt,
|
|
8439
|
+
lastCodeIndexedAt: state?.lastCodeIndexedAt,
|
|
8440
|
+
graphBuiltAt: graphState?.lastBuiltAt,
|
|
8441
|
+
graphStatus: graphState?.lastStatus
|
|
8442
|
+
})) {
|
|
8443
|
+
skippedHistory = true;
|
|
8444
|
+
historySkippedReason = "PR history already synced; resuming unfinished org graph/index work.";
|
|
8445
|
+
options.onFetchProgress?.({
|
|
8446
|
+
stage: "skipped_pull_request_fetch",
|
|
8447
|
+
repo: repo.fullName,
|
|
8448
|
+
reason: historySkippedReason
|
|
8449
|
+
});
|
|
8450
|
+
} else if (!auth.token) {
|
|
8193
8451
|
repoFailures.push(
|
|
8194
8452
|
"GitHub authentication is required for org PR indexing. Run gh auth login, or export GITHUB_TOKEN/GH_TOKEN with read-only access."
|
|
8195
8453
|
);
|
|
8196
8454
|
} else {
|
|
8197
8455
|
try {
|
|
8198
8456
|
const since = options.since ?? (options.command === "org sync" ? state?.lastPrSyncAt ?? getLastSyncTime(db, repo.fullName) : void 0);
|
|
8199
|
-
const pullRequests = await
|
|
8457
|
+
const pullRequests = await fetchPullRequests({
|
|
8200
8458
|
token: auth.token,
|
|
8201
8459
|
repo: repo.fullName,
|
|
8202
8460
|
limit: 200,
|
|
@@ -8257,6 +8515,8 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
8257
8515
|
results.push({
|
|
8258
8516
|
repo: repo.fullName,
|
|
8259
8517
|
skippedCode: Boolean(codeUnchanged || options.prsOnly),
|
|
8518
|
+
skippedHistory,
|
|
8519
|
+
historySkippedReason,
|
|
8260
8520
|
currentCommit: currentCommit2,
|
|
8261
8521
|
history,
|
|
8262
8522
|
code,
|
|
@@ -8298,25 +8558,48 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
8298
8558
|
});
|
|
8299
8559
|
}
|
|
8300
8560
|
}
|
|
8301
|
-
|
|
8561
|
+
let graph;
|
|
8562
|
+
if (options.noGraph) {
|
|
8563
|
+
const counts = getOrgGraphCounts(db, config.org);
|
|
8564
|
+
recordOrgGraphState(db, {
|
|
8565
|
+
org: config.org,
|
|
8566
|
+
status: "skipped",
|
|
8567
|
+
edgeCount: counts.edges,
|
|
8568
|
+
apiContractCount: counts.apiContracts,
|
|
8569
|
+
apiConsumerCount: counts.apiConsumers
|
|
8570
|
+
});
|
|
8571
|
+
graph = { ...counts, skipped: true };
|
|
8572
|
+
} else {
|
|
8573
|
+
try {
|
|
8574
|
+
const rebuiltGraph = rebuildOrgGraph(db, config, {
|
|
8575
|
+
baseDir: options.baseDir,
|
|
8576
|
+
onProgress: options.onGraphProgress
|
|
8577
|
+
});
|
|
8578
|
+
graph = {
|
|
8579
|
+
edges: rebuiltGraph.edges.length,
|
|
8580
|
+
apiConsumers: rebuiltGraph.apiConsumers.length,
|
|
8581
|
+
apiContracts: rebuiltGraph.apiContracts.length
|
|
8582
|
+
};
|
|
8583
|
+
} catch (error) {
|
|
8584
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8585
|
+
const counts = getOrgGraphCounts(db, config.org);
|
|
8586
|
+
graph = { ...counts, error: message };
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8302
8589
|
recordOrgIndexRun(db, {
|
|
8303
8590
|
org: config.org,
|
|
8304
8591
|
command: options.command ?? "org index",
|
|
8305
8592
|
startedAt,
|
|
8306
8593
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8307
|
-
status: results.some((result) => result.error) ? "partial" : "success",
|
|
8594
|
+
status: results.some((result) => result.error) || graph.error ? "partial" : "success",
|
|
8308
8595
|
prsIndexed: results.reduce((sum, result) => sum + (result.history?.indexedPrs ?? 0), 0),
|
|
8309
8596
|
codeFilesIndexed: results.reduce((sum, result) => sum + (result.code?.indexedFiles ?? 0), 0),
|
|
8310
|
-
failures: results.map((result) => result.error).filter((error) => Boolean(error))
|
|
8597
|
+
failures: results.map((result) => result.error).concat(graph.error ? [graph.error] : []).filter((error) => Boolean(error))
|
|
8311
8598
|
});
|
|
8312
8599
|
return {
|
|
8313
8600
|
org: config.org,
|
|
8314
8601
|
repos: results.sort((a, b) => a.repo.localeCompare(b.repo)),
|
|
8315
|
-
graph
|
|
8316
|
-
edges: graph.edges.length,
|
|
8317
|
-
apiConsumers: graph.apiConsumers.length,
|
|
8318
|
-
apiContracts: graph.apiContracts.length
|
|
8319
|
-
}
|
|
8602
|
+
graph
|
|
8320
8603
|
};
|
|
8321
8604
|
}
|
|
8322
8605
|
|
|
@@ -9251,6 +9534,8 @@ export {
|
|
|
9251
9534
|
getIndexStatus,
|
|
9252
9535
|
getLastSyncTime,
|
|
9253
9536
|
getOrgArchitectureMap,
|
|
9537
|
+
getOrgGraphCounts,
|
|
9538
|
+
getOrgGraphState,
|
|
9254
9539
|
getOrgRepoState,
|
|
9255
9540
|
getOrgStatus,
|
|
9256
9541
|
getPlaybook,
|
|
@@ -9303,6 +9588,7 @@ export {
|
|
|
9303
9588
|
rebuildOrgGraph,
|
|
9304
9589
|
recordFeedback,
|
|
9305
9590
|
recordIndexRun,
|
|
9591
|
+
recordOrgGraphState,
|
|
9306
9592
|
recordOrgIndexRun,
|
|
9307
9593
|
redactSecrets,
|
|
9308
9594
|
redactedHistoricalText,
|