codeblast 0.3.4 → 0.3.5
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 +47 -21
- package/README.zh-CN.md +44 -21
- package/dist/bin.js +69 -31
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="#the-
|
|
12
|
+
<a href="#the-four-views"><img src="https://img.shields.io/badge/TypeScript-function--level-3178c6?style=flat-square" alt="TypeScript function-level"/></a>
|
|
13
13
|
<a href="#the-precision-promise-bounded-and-evidence-backed"><img src="https://img.shields.io/badge/recall-28%2F28_%3D_100%25-3fb950?style=flat-square" alt="mutation-tested recall 100%"/></a>
|
|
14
14
|
<a href="SKILL.md"><img src="https://img.shields.io/badge/Agent-Skill-7c3aed?style=flat-square" alt="agent skill"/></a>
|
|
15
15
|
<img src="https://img.shields.io/badge/license-MIT-8b949e?style=flat-square" alt="MIT"/>
|
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
steps:
|
|
32
32
|
- uses: actions/checkout@v4
|
|
33
33
|
with: { fetch-depth: 0 }
|
|
34
|
-
- uses: alloevil/codeblast@v0.3.
|
|
34
|
+
- uses: alloevil/codeblast@v0.3.5
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
On a structural PR, codeblast posts a bounded review decision, affected tests, `file:line` evidence,
|
|
@@ -40,14 +40,15 @@ locally in the runner; source is not uploaded to a codeblast service.
|
|
|
40
40
|
|
|
41
41
|
## What it is
|
|
42
42
|
|
|
43
|
-
**codeblast parses your repository into a deterministic code graph and
|
|
43
|
+
**codeblast parses your repository into a deterministic code graph and exposes four views of a change:**
|
|
44
44
|
> 🔗 **[Live interactive demo](https://alloevil.github.io/codeblast/)** — real architecture maps of tRPC / Tabby / sgp, with three-level drill-down
|
|
45
45
|
|
|
46
46
|
| | Question | Command |
|
|
47
47
|
|---|---|---|
|
|
48
|
-
| 🎯 | **What breaks if I change this?** | `impact` — direct
|
|
49
|
-
|
|
|
50
|
-
|
|
|
48
|
+
| 🎯 | **What breaks if I change this?** | `impact` — direct, transitive and affected-test reachability |
|
|
49
|
+
| 🛡️ | **Should this change receive targeted review?** | `check-change` — risk, graph health, affected tests and warnings |
|
|
50
|
+
| 🔍 | **What structurally changed?** | `change` — symbols and dependency edges added, removed or renamed |
|
|
51
|
+
| 🗺️ | **What does this project look like?** | `archmap` — module/file/symbol drill-down and cycle detection |
|
|
51
52
|
|
|
52
53
|
Built for humans (CLI / interactive HTML / PR comments) and for AI agents ([SKILL.md](SKILL.md)) — one graph, two front-ends.
|
|
53
54
|
<table>
|
|
@@ -72,7 +73,7 @@ Built for humans (CLI / interactive HTML / PR comments) and for AI agents ([SKIL
|
|
|
72
73
|
```bash
|
|
73
74
|
npx codeblast demo # build a graph of the current repo, run one impact query, emit the map
|
|
74
75
|
npm i -g codeblast # or install globally; needs Node ≥ 22.13 (built-in sqlite) or Bun
|
|
75
|
-
# npm serves 0.3.
|
|
76
|
+
# npm serves 0.3.5
|
|
76
77
|
|
|
77
78
|
# Install as an agent skill (Claude Code, Codex, Cursor, and 14 more harnesses)
|
|
78
79
|
npx skills add alloevil/codeblast
|
|
@@ -95,12 +96,12 @@ jobs:
|
|
|
95
96
|
steps:
|
|
96
97
|
- uses: actions/checkout@v4
|
|
97
98
|
with: { fetch-depth: 0 }
|
|
98
|
-
- uses: alloevil/codeblast@v0.3.
|
|
99
|
+
- uses: alloevil/codeblast@v0.3.5
|
|
99
100
|
```
|
|
100
101
|
|
|
101
|
-
The action builds the analyzer from the ref you pinned, posts one sticky comment
|
|
102
|
-
|
|
103
|
-
[workflow template](.github/workflows-template/codeblast.yml).
|
|
102
|
+
The action builds the analyzer from the ref you pinned, posts one sticky comment when a PR contains a
|
|
103
|
+
meaningful structural or tested behavior signal, and stays silent for docs-only, test-only, or
|
|
104
|
+
auxiliary-only noise. For the full input/output contract, use the [workflow template](.github/workflows-template/codeblast.yml).
|
|
104
105
|
|
|
105
106
|
|
|
106
107
|
## Why not yet another LLM diagram tool
|
|
@@ -113,10 +114,10 @@ codeblast: code → deterministic tsc/AST parse → graph → project graph
|
|
|
113
114
|
**Every node and every static-analysis edge carries `file:line` evidence** you can open and verify (`co_change` edges put a co-commit count in that field instead of a source line; file-level nodes carry line 1).
|
|
114
115
|
The LLM does exactly one job in the pipeline: giving modules human-readable names — node membership and edges always come from static analysis.
|
|
115
116
|
|
|
116
|
-
## The
|
|
117
|
+
## The four views
|
|
117
118
|
|
|
118
119
|
<p align="center">
|
|
119
|
-
<img src="assets/readme/three-queries.svg" width="100%" alt="
|
|
120
|
+
<img src="assets/readme/three-queries.svg" width="100%" alt="codeblast views — impact, change and architecture; check-change adds the machine-readable pre-merge safety decision"/>
|
|
120
121
|
</p>
|
|
121
122
|
|
|
122
123
|
```bash
|
|
@@ -130,11 +131,15 @@ codeblast impact graph.db "createOrder" --json
|
|
|
130
131
|
# → two channels: call-graph reachable (precision ~0.70, read first)
|
|
131
132
|
# + import reachable (conservative supplement, don't skip)
|
|
132
133
|
|
|
133
|
-
# ②
|
|
134
|
+
# ② Safety — one machine-readable pre-merge decision
|
|
135
|
+
codeblast check-change <repo> <base> <head> --json
|
|
136
|
+
# → decision / risk / graph_health / affected_test_files / warnings
|
|
137
|
+
|
|
138
|
+
# ③ Change Map — structural diff between two refs
|
|
134
139
|
codeblast change <repo> main~5 main --json
|
|
135
140
|
# → unexpected edges_added = a signal the change is out of scope
|
|
136
141
|
|
|
137
|
-
#
|
|
142
|
+
# ④ Architecture Map — interactive HTML: module → file → symbol drill-down,
|
|
138
143
|
# symbols link to source lines
|
|
139
144
|
codeblast archmap graph.db --out arch.html --repo-url <github-url> \
|
|
140
145
|
--site-url https://example.github.io/repo --og-image <share-image-url>
|
|
@@ -159,12 +164,11 @@ The self-pilot record is [`eval/pilot-2026-09-24.json`](eval/pilot-2026-09-24.js
|
|
|
159
164
|
package indexed this repository with 0 extraction failures and returned separate review-first and test
|
|
160
165
|
guidance. It is evidence that the workflow runs, not a claim of universal accuracy.
|
|
161
166
|
|
|
162
|
-
Copy [`.github/workflows-template/codeblast.yml`](.github/workflows-template/codeblast.yml) into your repo
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
[intent.md](intent.md).
|
|
167
|
+
Copy [`.github/workflows-template/codeblast.yml`](.github/workflows-template/codeblast.yml) into your repo.
|
|
168
|
+
PR comments contain structural changes, tested behavior signals, affected tests and evidence links;
|
|
169
|
+
docs-only, test-only and auxiliary-only changes stay silent. The deterministic offline replay matrix
|
|
170
|
+
guards these routing rules. Earlier historical replays and their human-review limitations remain logged
|
|
171
|
+
in [intent.md](intent.md).
|
|
168
172
|
## Evidence you can rerun
|
|
169
173
|
|
|
170
174
|
The headline promise is bounded: TypeScript, within the statically analyzable scope, and measured by
|
|
@@ -180,6 +184,28 @@ and every published figure has a machine-readable receipt in [`docs/claims.json`
|
|
|
180
184
|
The pilot is not a benchmark and does not establish a universal accuracy rate. It is a reproducible
|
|
181
185
|
smoke run of the published package against this repository.
|
|
182
186
|
|
|
187
|
+
### Current automated evidence
|
|
188
|
+
|
|
189
|
+
The current main branch is guarded by one command:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
bun run evolution-check
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
It runs build, tests, typecheck, deterministic replay, full/incremental graph equivalence and the
|
|
196
|
+
published-claims gate. Current committed evidence:
|
|
197
|
+
|
|
198
|
+
| Evidence | Current result |
|
|
199
|
+
|---|---:|
|
|
200
|
+
| Offline safety replay | 12/12, 0 incorrect silence, 0 invalid evidence, 0 nondeterministic output |
|
|
201
|
+
| Full vs incremental graph | nodes, edges and blind spots equal; deleted/renamed rows removed |
|
|
202
|
+
| Star-project graph completeness | n8n, Excalidraw and OpenCode: 0 extraction failures on pinned commits |
|
|
203
|
+
| Pinned mutation recall | tRPC 28/28; graphql-tools 10/10 |
|
|
204
|
+
| Modern compatibility radar | tRPC bounded sample 3/3; informational, not a release gate |
|
|
205
|
+
|
|
206
|
+
Literal `import.meta.glob("./fixtures/**/*.tsx")` patterns are represented as conservative imports.
|
|
207
|
+
Non-literal loaders, subprocess boundaries and unresolved runtime dispatch remain explicit blind spots.
|
|
208
|
+
|
|
183
209
|
### A reviewer's decision, not a diagram
|
|
184
210
|
|
|
185
211
|
For agents and CI, `check-change --json` returns a routing decision plus evidence:
|
package/README.zh-CN.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
**codeblast**
|
|
1
|
+
**codeblast** 是面向 TypeScript monorepo 和 AI coding agent 的合并前变更安全检查器:告诉你该看哪里、该跑哪些测试,以及图谱是否完整。
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="assets/readme/hero.svg" width="100%" alt="codeblast — deterministic code graph: know what breaks before you merge"/>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="
|
|
12
|
+
<a href="#四个视图"><img src="https://img.shields.io/badge/TypeScript-函数级-3178c6?style=flat-square" alt="TypeScript function-level"/></a>
|
|
13
13
|
<a href="#精度承诺有边界有证据"><img src="https://img.shields.io/badge/recall-28%2F28_%3D_100%25-3fb950?style=flat-square" alt="mutation-tested recall 100%"/></a>
|
|
14
14
|
<a href="SKILL.md"><img src="https://img.shields.io/badge/Agent-Skill-7c3aed?style=flat-square" alt="agent skill"/></a>
|
|
15
15
|
<img src="https://img.shields.io/badge/license-MIT-8b949e?style=flat-square" alt="MIT"/>
|
|
@@ -17,14 +17,15 @@
|
|
|
17
17
|
|
|
18
18
|
## 是什么
|
|
19
19
|
|
|
20
|
-
**codeblast
|
|
21
|
-
> 🔗 **[在线交互演示](https://alloevil.github.io/codeblast/)** — tRPC / Tabby / sgp
|
|
20
|
+
**codeblast 把仓库解析成确定性代码图谱,为一次改动提供四个视图:**
|
|
21
|
+
> 🔗 **[在线交互演示](https://alloevil.github.io/codeblast/)** — tRPC / Tabby / sgp 的真实架构图,可下钻到源码行
|
|
22
22
|
|
|
23
23
|
| | 问题 | 命令 |
|
|
24
24
|
|---|---|---|
|
|
25
|
-
| 🎯 |
|
|
26
|
-
|
|
|
27
|
-
|
|
|
25
|
+
| 🎯 | **改这个会影响哪里?** | `impact` — 直接、传递与受影响测试 |
|
|
26
|
+
| 🛡️ | **这个改动是否需要重点评审?** | `check-change` — 风险、图健康度、测试与警告 |
|
|
27
|
+
| 🔍 | **结构上改了什么?** | `change` — 符号和依赖边的新增、删除与重命名 |
|
|
28
|
+
| 🗺️ | **项目长什么样?** | `archmap` — 模块/文件/符号下钻与循环依赖 |
|
|
28
29
|
|
|
29
30
|
给人看(CLI / 交互 HTML / PR 评论),也给 AI agent 用([SKILL.md](SKILL.md))——同一份图谱,两个出口。
|
|
30
31
|
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
```bash
|
|
34
35
|
npx codeblast demo # 给当前仓库建图、跑一次 impact 查询、导出架构图
|
|
35
36
|
npm i -g codeblast # 或全局安装;需要 Node ≥ 22.13(内置 sqlite)或 Bun
|
|
36
|
-
# npm
|
|
37
|
+
# npm 当前版本为 0.3.5
|
|
37
38
|
|
|
38
39
|
# 作为 agent skill 安装(Claude Code、Codex、Cursor 等)
|
|
39
40
|
npx skills add alloevil/codeblast
|
|
@@ -49,7 +50,7 @@ codeblast: 代码 → tsc/AST 确定性解析 → 图谱 → 投影 图 =
|
|
|
49
50
|
**每个节点和每条静态分析边都带 `file:line` 证据**,可直接打开核对(`co_change` 边在该字段存的是共提交次数而非源码行;文件级节点行号为 1)。
|
|
50
51
|
LLM 在管线里只做一件事:给模块起人话名字——节点归属和边永远来自静态分析。
|
|
51
52
|
|
|
52
|
-
##
|
|
53
|
+
## 四个视图
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
56
|
# 建图:TS monorepo / Python 自动识别,hash 增量更新(tRPC 957 文件:6248 节点 / 17072 边,样例运行见 SKILL.md)
|
|
@@ -60,23 +61,45 @@ codeblast impact graph.db "createOrder" --json
|
|
|
60
61
|
# → direct 清单 = 必须检查的 callsite;tests 清单 = 必须跑的测试
|
|
61
62
|
# → 双通道:调用链可达(精确率 ~0.70,优先看)+ import 可达(保守补充,勿跳过)
|
|
62
63
|
|
|
63
|
-
# ②
|
|
64
|
+
# ② Safety —— 合并前机器判断
|
|
65
|
+
codeblast check-change <repo> <base> <head> --json
|
|
66
|
+
# → decision / risk / graph_health / affected_test_files / warnings
|
|
67
|
+
|
|
68
|
+
# ③ Change Map —— 两个 ref 之间的结构 diff
|
|
64
69
|
codeblast change <repo> main~5 main --json
|
|
65
70
|
# → 意料之外的 edges_added = 改动越界信号
|
|
66
71
|
|
|
67
|
-
#
|
|
72
|
+
# ④ Architecture Map —— 交互 HTML:模块→文件→符号三层下钻,符号跳源码行
|
|
68
73
|
codeblast archmap graph.db --out arch.html --repo-url <github-url>
|
|
69
74
|
|
|
70
75
|
# 可选:git 历史耦合挖掘(协议两端、配置与消费者——静态分析看不见的边)
|
|
71
76
|
codeblast cochange <repo> graph.db
|
|
72
77
|
```
|
|
73
78
|
|
|
74
|
-
### PR bot(CI
|
|
79
|
+
### PR bot(CI 内运行,宁静默不刷屏)
|
|
80
|
+
|
|
81
|
+
复制 [`.github/workflows-template/codeblast.yml`](.github/workflows-template/codeblast.yml) 到目标仓库。
|
|
82
|
+
有意义的结构变化或“生产函数体 + 同 PR 测试”变化会得到 review decision、测试建议和 `file:line` 证据;
|
|
83
|
+
docs-only、test-only、auxiliary-only 噪音默认静默。离线 replay 会自动防止错误静默和无效证据回归。
|
|
84
|
+
|
|
85
|
+
## 当前自动证据
|
|
75
86
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
```bash
|
|
88
|
+
bun run evolution-check
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
统一运行 build、测试、类型检查、离线 replay、full/incremental 图等价和 claims gate。当前结果:
|
|
92
|
+
|
|
93
|
+
| 证据 | 结果 |
|
|
94
|
+
|---|---:|
|
|
95
|
+
| 离线安全 replay | 12/12;错误静默、无效证据、非确定输出均为 0 |
|
|
96
|
+
| 全量与增量图 | nodes / edges / blind spots 相等;删除与重命名后的旧记录已清理 |
|
|
97
|
+
| 明星项目图完整性 | n8n、Excalidraw、OpenCode 固定 commit 均为 0 extraction failure |
|
|
98
|
+
| 固定 mutation gate | tRPC 28/28;graphql-tools 10/10 |
|
|
99
|
+
| modern 兼容性雷达 | tRPC 小样本 3/3;仅 informational,不是 release gate |
|
|
100
|
+
|
|
101
|
+
字面量 `import.meta.glob("./fixtures/**/*.tsx")` 会展开成保守 import 边;非字面量 loader、
|
|
102
|
+
子进程边界和无法解析的运行时派发仍作为显式 blind spot。
|
|
80
103
|
|
|
81
104
|
## 精度承诺(有边界,有证据)
|
|
82
105
|
|
|
@@ -107,13 +130,13 @@ codeblast cochange <repo> graph.db
|
|
|
107
130
|
|
|
108
131
|
## 给 AI Agent 用
|
|
109
132
|
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
|
|
133
|
+
```text
|
|
134
|
+
改前:impact "symbol" --json → review_first / run_tests / conservative / warnings
|
|
135
|
+
改后:check-change repo base head --json → decision / risk / graph_health / affected tests
|
|
113
136
|
```
|
|
114
137
|
|
|
115
|
-
|
|
116
|
-
Agent 规范另见 [AGENTS.md](AGENTS.md)。
|
|
138
|
+
`safe-to-review` 只是注意力路由,不等于“可以安全合并”。完整契约、schema version、exit code
|
|
139
|
+
和解读纪律见 [SKILL.md](SKILL.md);Agent 规范另见 [AGENTS.md](AGENTS.md)。
|
|
117
140
|
|
|
118
141
|
## 常见问题
|
|
119
142
|
|
package/dist/bin.js
CHANGED
|
@@ -467,21 +467,24 @@ class Extractor {
|
|
|
467
467
|
enclosing.push(id);
|
|
468
468
|
if (ts.isCallExpression(node) || ts.isNewExpression(node)) {
|
|
469
469
|
const caller = [...enclosing].reverse().find(Boolean) ?? relPath;
|
|
470
|
-
if (ts.isCallExpression(node) && node.expression.
|
|
470
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === "glob" && node.expression.expression.getText(sf) === "import.meta") {
|
|
471
|
+
const arg = node.arguments[0];
|
|
472
|
+
const patterns = arg && ts.isStringLiteral(arg) ? [arg.text] : arg && ts.isArrayLiteralExpression(arg) && arg.elements.every(ts.isStringLiteral) ? arg.elements.map((element) => element.text) : null;
|
|
473
|
+
if (patterns) {
|
|
474
|
+
const excluded = new Set(patterns.filter((pattern) => pattern.startsWith("!")).flatMap((pattern) => this.expandGlob(pattern.slice(1), sf.fileName)));
|
|
475
|
+
const matches = new Set(patterns.filter((pattern) => !pattern.startsWith("!")).flatMap((pattern) => this.expandGlob(pattern, sf.fileName)));
|
|
476
|
+
for (const match of matches)
|
|
477
|
+
if (!excluded.has(match))
|
|
478
|
+
edges.push({ src: relPath, dst: this.rel(match), kind: "imports", file: relPath, line: lineOf(node), confidence: "conservative", src_file: relPath });
|
|
479
|
+
} else {
|
|
480
|
+
blindSpots.push({ file: relPath, line: lineOf(node), reason: `dynamic import.meta.glob: ${(arg?.getText() ?? "").slice(0, 80)}`, src_file: relPath });
|
|
481
|
+
}
|
|
482
|
+
} else if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
471
483
|
const arg = node.arguments[0];
|
|
472
484
|
if (arg && ts.isStringLiteral(arg)) {
|
|
473
485
|
const resolved = this.resolveModule(arg.text, sf.fileName);
|
|
474
|
-
if (resolved)
|
|
475
|
-
edges.push({
|
|
476
|
-
src: relPath,
|
|
477
|
-
dst: this.rel(resolved),
|
|
478
|
-
kind: "imports",
|
|
479
|
-
file: relPath,
|
|
480
|
-
line: lineOf(node),
|
|
481
|
-
confidence: "exact",
|
|
482
|
-
src_file: relPath
|
|
483
|
-
});
|
|
484
|
-
}
|
|
486
|
+
if (resolved)
|
|
487
|
+
edges.push({ src: relPath, dst: this.rel(resolved), kind: "imports", file: relPath, line: lineOf(node), confidence: "exact", src_file: relPath });
|
|
485
488
|
} else {
|
|
486
489
|
blindSpots.push({ file: relPath, line: lineOf(node), reason: `dynamic import: ${(arg?.getText() ?? "").slice(0, 80)}`, src_file: relPath });
|
|
487
490
|
}
|
|
@@ -659,6 +662,28 @@ class Extractor {
|
|
|
659
662
|
isExported(node) {
|
|
660
663
|
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0;
|
|
661
664
|
}
|
|
665
|
+
expandGlob(pattern, fromFile) {
|
|
666
|
+
if (!pattern.startsWith("."))
|
|
667
|
+
return [];
|
|
668
|
+
const base = path.resolve(path.dirname(fromFile), pattern.split("*")[0]);
|
|
669
|
+
if (!fs.existsSync(base))
|
|
670
|
+
return [];
|
|
671
|
+
const rawSuffix = pattern.slice(pattern.indexOf("*"));
|
|
672
|
+
const suffix = rawSuffix.split("**").map((part) => part.split("*").map((piece) => piece.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join("[^/]*")).join(".*");
|
|
673
|
+
const re = new RegExp(`^${suffix}$`);
|
|
674
|
+
const out = [];
|
|
675
|
+
const walk = (dir) => {
|
|
676
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
677
|
+
const file = path.join(dir, entry.name);
|
|
678
|
+
if (entry.isDirectory())
|
|
679
|
+
walk(file);
|
|
680
|
+
else if (re.test(path.relative(base, file).replaceAll(path.sep, "/")))
|
|
681
|
+
out.push(file);
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
walk(base);
|
|
685
|
+
return out;
|
|
686
|
+
}
|
|
662
687
|
}
|
|
663
688
|
var TEST_FILE_RE;
|
|
664
689
|
var init_extract = __esm(() => {
|
|
@@ -879,25 +904,33 @@ var init_cli = __esm(() => {
|
|
|
879
904
|
}
|
|
880
905
|
pyProbe = spawnSync(["python3", path2.join(import.meta.dirname, "py_extract.py"), repoRoot]);
|
|
881
906
|
if (pyProbe.exitCode === 0) {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
907
|
+
try {
|
|
908
|
+
const payload = JSON.parse(pyProbe.stdout);
|
|
909
|
+
for (const f of payload.files) {
|
|
910
|
+
if (seenFiles.has(f.path))
|
|
911
|
+
continue;
|
|
912
|
+
seenFiles.add(f.path);
|
|
913
|
+
const existing = getHash.get(f.path);
|
|
914
|
+
if (existing?.hash === f.hash && f.hash !== "") {
|
|
915
|
+
skipped++;
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
writeBatch(f.path, f.hash, f.nodes, f.edges, f.blind_spots);
|
|
919
|
+
indexed++;
|
|
920
|
+
nodeCount += f.nodes.length;
|
|
921
|
+
edgeCount += f.edges.length;
|
|
922
|
+
blindCount += f.blind_spots.length;
|
|
891
923
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
924
|
+
const pyFiles = payload.files.length;
|
|
925
|
+
if (pyFiles > 0)
|
|
926
|
+
console.error(`python files ingested: ${pyFiles}`);
|
|
927
|
+
} catch (err) {
|
|
928
|
+
failures++;
|
|
929
|
+
console.error(`PYTHON INGEST FAILED: ${err instanceof Error ? err.message : err}`);
|
|
897
930
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
931
|
+
} else {
|
|
932
|
+
failures++;
|
|
933
|
+
console.error(`PYTHON INGEST FAILED: ${pyProbe.stderr.slice(0, 1000)}`);
|
|
901
934
|
}
|
|
902
935
|
if (failures === 0) {
|
|
903
936
|
const stale = db.prepare("SELECT path FROM files").all().filter((row) => !seenFiles.has(row.path));
|
|
@@ -2348,7 +2381,7 @@ var SCHEMA_VERSION = "1", EXIT_OK = 0, EXIT_REVIEW = 1, EXIT_ERROR = 2, readVers
|
|
|
2348
2381
|
nodes: Number(db.prepare("SELECT COUNT(*) c FROM nodes").get().c),
|
|
2349
2382
|
edges: Number(db.prepare("SELECT COUNT(*) c FROM edges").get().c),
|
|
2350
2383
|
blind_spots: Number(db.prepare("SELECT COUNT(*) c FROM blind_spots").get().c)
|
|
2351
|
-
}), healthBase, healthHead, diff3, healthWarnings, prodNodesAdded2, total3,
|
|
2384
|
+
}), healthBase, healthHead, diff3, healthWarnings, prodNodesAdded2, total3, affectedTestFiles, truncated = false, blindSpots = 0, affectedTests, bodyChanged2, structuralIds2, diffText, currentFile = "", diffLineCount2, changedFiles2, auxOnly, decision2, output;
|
|
2352
2385
|
var init_check_change = __esm(() => {
|
|
2353
2386
|
init_db();
|
|
2354
2387
|
init_proc();
|
|
@@ -2384,14 +2417,18 @@ var init_check_change = __esm(() => {
|
|
|
2384
2417
|
];
|
|
2385
2418
|
prodNodesAdded2 = diff3.nodesAdded.filter((n) => !TEST_RE3.test(n.file));
|
|
2386
2419
|
total3 = structuralTotal(diff3);
|
|
2420
|
+
affectedTestFiles = new Set;
|
|
2387
2421
|
for (const node of [...diff3.nodesAdded, ...diff3.renamed.map((r) => ({ id: `${r.file}#${r.to}`, kind: r.kind, name: r.to, file: r.file, line: 0 }))].slice(0, 15)) {
|
|
2388
2422
|
try {
|
|
2389
2423
|
const result = impact(dbB3, node.id, 2000);
|
|
2390
|
-
|
|
2424
|
+
for (const item of result.items)
|
|
2425
|
+
if (item.level === "tests")
|
|
2426
|
+
affectedTestFiles.add(item.file);
|
|
2391
2427
|
truncated ||= result.truncated;
|
|
2392
2428
|
blindSpots += result.blind_spot_count;
|
|
2393
2429
|
} catch {}
|
|
2394
2430
|
}
|
|
2431
|
+
affectedTests = affectedTestFiles.size;
|
|
2395
2432
|
bodyChanged2 = [];
|
|
2396
2433
|
structuralIds2 = new Set([
|
|
2397
2434
|
...diff3.nodesAdded.map((node) => node.id),
|
|
@@ -2442,6 +2479,7 @@ var init_check_change = __esm(() => {
|
|
|
2442
2479
|
recommended_actions: decision2.recommendedActions,
|
|
2443
2480
|
structural_changes: total3,
|
|
2444
2481
|
affected_test_files: affectedTests,
|
|
2482
|
+
affected_test_file_paths: [...affectedTestFiles].sort((a, b) => a.localeCompare(b)),
|
|
2445
2483
|
blind_spot_count: blindSpots,
|
|
2446
2484
|
graph_health: { base: healthBase, head: healthHead, warnings: healthWarnings },
|
|
2447
2485
|
truncated,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeblast",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Know what breaks before you merge — mutation-tested code graph with architecture, change & impact maps. Evidence on every edge. For humans and AI agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"impact-analysis",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"prepack": "bun run build",
|
|
40
40
|
"typecheck": "tsc -p .",
|
|
41
41
|
"agent-smoke": "bun run build && node eval/agent-workflow-smoke.mjs",
|
|
42
|
+
"evolution-check": "PYTHONPATH=. node eval/evolution-check.mjs",
|
|
42
43
|
"guidance-stability": "node eval/guidance-stability.mjs",
|
|
43
44
|
"incremental-equivalence": "bun run build && node eval/incremental-equivalence.mjs",
|
|
44
45
|
"offline-replay": "bun run build && node eval/offline-replay.mjs",
|