stata-code 0.4.0__tar.gz → 0.5.0__tar.gz
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.
- {stata_code-0.4.0 → stata_code-0.5.0}/.gitignore +13 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/CHANGELOG.md +39 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/PKG-INFO +33 -5
- {stata_code-0.4.0 → stata_code-0.5.0}/README.md +32 -4
- {stata_code-0.4.0 → stata_code-0.5.0}/SCHEMA.md +1 -1
- {stata_code-0.4.0 → stata_code-0.5.0}/pyproject.toml +1 -1
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/__init__.py +1 -1
- stata_code-0.5.0/stata_code/kernel/assets/logo-32x32.png +0 -0
- stata_code-0.5.0/stata_code/kernel/assets/logo-64x64.png +0 -0
- stata_code-0.5.0/stata_code/kernel/assets/logo-svg.svg +41 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/kernel/kernel.py +15 -1
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/mcp/server.py +6 -2
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_kernel.py +32 -1
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_mcp.py +4 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/LICENSE +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/LICENSE-POLICY.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/PUBLISHING.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/docs/design/hard_timeout.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/examples/01-basic-regression.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/examples/02-did-card-krueger.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/examples/03-graphs.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/examples/04-multi-session.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/examples/05-large-matrix.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/examples/README.md +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/schema/run_result.schema.json +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/scripts/export_schema.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/__init__.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/_pool.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/_refs.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/_runtime.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/errors.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/log_artifacts.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/runner.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/schema.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/kernel/__init__.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/kernel/__main__.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/mcp/__init__.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/mcp/__main__.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/__init__.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/fixtures/.gitkeep +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_cancel.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_errors.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_log_artifacts.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_pool.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_runner.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_schema.py +0 -0
- {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_schema_artifact.py +0 -0
|
@@ -223,3 +223,16 @@ log-files/
|
|
|
223
223
|
*.smcl
|
|
224
224
|
*.dta
|
|
225
225
|
!tests/fixtures/*.dta
|
|
226
|
+
|
|
227
|
+
# macOS
|
|
228
|
+
.DS_Store
|
|
229
|
+
**/.DS_Store
|
|
230
|
+
|
|
231
|
+
# VS Code workspace settings (contain user-machine absolute paths)
|
|
232
|
+
.vscode/
|
|
233
|
+
|
|
234
|
+
# Claude Code scratch (worktrees, transcripts)
|
|
235
|
+
.claude/
|
|
236
|
+
|
|
237
|
+
# Demo / scratch notebooks (real tests live under tests/)
|
|
238
|
+
demo-tests/*.ipynb
|
|
@@ -4,6 +4,45 @@ All notable changes to `stata-code` are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project adheres
|
|
5
5
|
to semver-major.minor for the result schema (see `SCHEMA.md` §6).
|
|
6
6
|
|
|
7
|
+
## [0.5.0] — 2026-05-08
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Bundled Jupyter kernel logos.** `stata-code-kernel install --user`
|
|
12
|
+
now copies `stata_code/kernel/assets/{logo-32x32.png,logo-64x64.png,
|
|
13
|
+
logo-svg.svg}` into the kernelspec source dir before
|
|
14
|
+
`KernelSpecManager().install_kernel_spec` runs. VS Code's Jupyter
|
|
15
|
+
extension filters out kernelspecs that lack logo files, so prior
|
|
16
|
+
releases were invisible in its kernel picker; v0.5 fixes that without
|
|
17
|
+
affecting JupyterLab or classic Jupyter (which both already worked).
|
|
18
|
+
- **TestPyPI publishing step in `release.yml`.** Tag `v*` now publishes
|
|
19
|
+
to TestPyPI (via OIDC trusted publishing, environment `testpypi`)
|
|
20
|
+
before publishing to PyPI proper. `continue-on-error: true` keeps
|
|
21
|
+
PyPI + GitHub Release on the happy path even when TestPyPI is
|
|
22
|
+
misconfigured. Setup mirrors the PyPI trusted publisher and is
|
|
23
|
+
documented in [CLAUDE.md](CLAUDE.md).
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`stata_run` tool description and README** clarify the boundary
|
|
28
|
+
between non-mutating execution and the optional agent "fix and
|
|
29
|
+
rerun" repair loop. The tool itself never rewrites your `.do` file
|
|
30
|
+
— but the submitted Stata code can still produce logs, graphs, and
|
|
31
|
+
output files as usual. Repair loops require explicit user opt-in;
|
|
32
|
+
failed runs are diagnostics first, not automatic rewrite permission.
|
|
33
|
+
- **VSCode MCP-client handshake version aligned to 0.5.0** (was a
|
|
34
|
+
stale 0.3.2 since the v0.3.2 release).
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **`install_kernel` no longer `.resolve()`s `sys.executable`.** On
|
|
39
|
+
macOS Homebrew venvs (and other layouts that use a `python` symlink
|
|
40
|
+
outside the venv's `bin/` to a Cellar-style real interpreter),
|
|
41
|
+
resolving the symlink pointed Jupyter at an interpreter that
|
|
42
|
+
couldn't import `stata_code`. The kernelspec now keeps the
|
|
43
|
+
unresolved `sys.executable`, so the venv's `python` (with
|
|
44
|
+
`stata_code` on its `sys.path`) launches the kernel.
|
|
45
|
+
|
|
7
46
|
## [0.4.0] — 2026-05-07
|
|
8
47
|
|
|
9
48
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stata-code
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Agent-native Stata bridge — one core, multiple frontends (MCP, Jupyter, VSCode)
|
|
5
5
|
Project-URL: Homepage, https://github.com/brycewang-stanford/stata-code
|
|
6
6
|
Project-URL: Repository, https://github.com/brycewang-stanford/stata-code
|
|
@@ -59,7 +59,12 @@ Description-Content-Type: text/markdown
|
|
|
59
59
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
**Status: v0.
|
|
62
|
+
**Status: v0.5 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. Current test suite: 218 passing tests across schema, runner, MCP, kernel, and ref-store modules. License: **MIT**.
|
|
63
|
+
|
|
64
|
+
Two workflows v0.5 explicitly supports for end users:
|
|
65
|
+
|
|
66
|
+
- **Run Stata code from a Jupyter notebook.** `pip install "stata-code[kernel]"` + `stata-code-kernel install --user` registers a **Stata** kernel that the Jupyter Notebook UI, JupyterLab, and the VS Code Jupyter extension all pick up by name. Cells render Stata logs, graphs, and warnings inline (the kernel logo bundled in v0.5 makes it appear in VS Code's kernel picker too). See [As a Jupyter Kernel](#as-a-jupyter-kernel).
|
|
67
|
+
- **Optional agent "fix and rerun" loop.** `stata_run` returns typed `error.kind/line/context` plus `suggestions` on every failure. By default Claude Code only reports diagnostics — but if you explicitly say "fix this and rerun until it passes", the agent uses the same fields to edit your `.do` file and re-call `stata_run` until the run is green. The repair loop is **opt-in**: failed runs are diagnostics first, not automatic rewrite permission. See [Error Recovery in Agent Workflows](#error-recovery-in-agent-workflows).
|
|
63
68
|
|
|
64
69
|
---
|
|
65
70
|
|
|
@@ -156,6 +161,15 @@ claude mcp add stata-code --scope project -- stata-code-mcp
|
|
|
156
161
|
|
|
157
162
|
Then launch `claude` and type `/mcp` to confirm `stata-code` shows up with its 8 tools (`stata_run`, `stata_info`, `get_log`, `get_graph`, `get_matrix`, `list_sessions`, `cancel_session`, `reset_session`).
|
|
158
163
|
|
|
164
|
+
#### Error Recovery in Agent Workflows
|
|
165
|
+
|
|
166
|
+
`stata_run` does not rewrite the source `.do` file or change code on its own. It executes the submitted Stata code, so that code may still create logs, graphs, tables, or other outputs as usual. When Stata fails, `stata_run` returns typed diagnostics (`error.kind`, `error.message`, `error.line`, `error.context`) plus best-effort `suggestions`. That supports two distinct Claude Code workflows:
|
|
167
|
+
|
|
168
|
+
- For "run this do-file" or "verify this code", Claude can report the failure and suggested next steps without changing source files.
|
|
169
|
+
- For "fix this and rerun until it passes", Claude can use the same structured error fields to edit the `.do` file, call `stata_run` again, and iterate.
|
|
170
|
+
|
|
171
|
+
If you want the repair loop, say so explicitly. Otherwise, treat failed runs as diagnostics first, not as automatic permission to rewrite code.
|
|
172
|
+
|
|
159
173
|
#### `uvx` (no global pip install)
|
|
160
174
|
|
|
161
175
|
If you prefer not to `pip install stata-code` globally, run it ephemerally through [`uv`](https://github.com/astral-sh/uv):
|
|
@@ -314,7 +328,7 @@ stata_code/
|
|
|
314
328
|
|
|
315
329
|
## Roadmap
|
|
316
330
|
|
|
317
|
-
### Done (v0.
|
|
331
|
+
### Done (through v0.5 — May 2026)
|
|
318
332
|
|
|
319
333
|
- v1.0 result schema ([SCHEMA.md](SCHEMA.md))
|
|
320
334
|
- `pystata`-based runner with native-typed `r()`, `e()`, and matrices
|
|
@@ -347,7 +361,7 @@ See [SCHEMA.md §7](SCHEMA.md) for explicitly out-of-scope items.
|
|
|
347
361
|
|
|
348
362
|
```bash
|
|
349
363
|
pip install -e ".[dev,mcp,kernel]"
|
|
350
|
-
pytest # full suite (
|
|
364
|
+
pytest # full suite (218 tests)
|
|
351
365
|
pytest -m "not stata_required" # CI subset; no Stata needed
|
|
352
366
|
pytest -m "stata_required" -v # Stata-only integration tests
|
|
353
367
|
```
|
|
@@ -402,7 +416,12 @@ The Stata tooling landscape that this project builds on and learns from is surve
|
|
|
402
416
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
403
417
|
```
|
|
404
418
|
|
|
405
|
-
**当前状态:v0.
|
|
419
|
+
**当前状态:v0.5(2026 年 5 月)** —— core、MCP server、Jupyter kernel、VS Code 扩展都已经在 Stata 18 MP 上端到端跑通。测试套件:218 个 passing tests,覆盖 schema、runner、MCP、kernel 和 ref-store。许可证:**MIT**。
|
|
420
|
+
|
|
421
|
+
v0.5 明确支持的两种用户工作流:
|
|
422
|
+
|
|
423
|
+
- **在 Jupyter notebook 里跑 Stata 代码。** `pip install "stata-code[kernel]"` + `stata-code-kernel install --user` 会注册一个名为 **Stata** 的 kernel,Jupyter Notebook、JupyterLab、以及 VS Code 的 Jupyter 扩展都能在 kernel 选择器里看到它。Cell 里直接写 Stata 命令,日志、图形和警告会内联渲染(v0.5 把 kernel logo 一起打包进 PyPI wheel,VS Code 的 Jupyter kernel picker 也能正常显示)。详见下文 [作为 Jupyter kernel](#作为-jupyter-kernel)。
|
|
424
|
+
- **可选的 agent「修复并重跑」循环。** `stata_run` 在每次失败时都会返回结构化的 `error.kind/line/context` 和 `suggestions`。默认情况下 Claude Code 只把它当作诊断信息上报;但如果你明确说「帮我修到跑通」「修复并反复运行直到成功」,agent 就会用同一组字段去改 `.do` 文件、再调 `stata_run`,直到代码通过。这个修复循环是 **opt-in** 的:默认失败 = 诊断,不是自动改写授权。详见下文 [Agent 工作流里的报错恢复](#agent-工作流里的报错恢复)。
|
|
406
425
|
|
|
407
426
|
---
|
|
408
427
|
|
|
@@ -498,6 +517,15 @@ claude mcp add stata-code --scope project -- stata-code-mcp
|
|
|
498
517
|
|
|
499
518
|
接着运行 `claude`,输入 `/mcp` 确认 `stata-code` 出现并带有 8 个工具(`stata_run`, `stata_info`, `get_log`, `get_graph`, `get_matrix`, `list_sessions`, `cancel_session`, `reset_session`)。
|
|
500
519
|
|
|
520
|
+
#### Agent 工作流里的报错恢复
|
|
521
|
+
|
|
522
|
+
`stata_run` 不会自行改写源 `.do` 文件或替你改代码。它执行提交的 Stata 代码,所以代码本身仍可能照常生成日志、图形、表格或其他输出。Stata 报错时,`stata_run` 返回结构化诊断(`error.kind`, `error.message`, `error.line`, `error.context`)和尽力生成的 `suggestions`。这支持两种不同的 Claude Code 工作流:
|
|
523
|
+
|
|
524
|
+
- 如果你说的是「运行这个 do-file」或「验证这段代码」,Claude 可以只报告失败原因和建议的下一步,不修改源文件。
|
|
525
|
+
- 如果你明确说「帮我修到跑通」或「修复并反复运行直到成功」,Claude 可以基于同一组结构化错误字段修改 `.do` 文件,再调用 `stata_run` 继续迭代。
|
|
526
|
+
|
|
527
|
+
如果需要自动修复循环,请明确说出来。否则,失败的运行应先被视为诊断结果,而不是自动改写代码的授权。
|
|
528
|
+
|
|
501
529
|
#### 用 `uvx`(不必全局 pip install)
|
|
502
530
|
|
|
503
531
|
如果不想全局 `pip install stata-code`,可以用 [`uv`](https://github.com/astral-sh/uv) 临时运行:
|
|
@@ -21,7 +21,12 @@
|
|
|
21
21
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
**Status: v0.
|
|
24
|
+
**Status: v0.5 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. Current test suite: 218 passing tests across schema, runner, MCP, kernel, and ref-store modules. License: **MIT**.
|
|
25
|
+
|
|
26
|
+
Two workflows v0.5 explicitly supports for end users:
|
|
27
|
+
|
|
28
|
+
- **Run Stata code from a Jupyter notebook.** `pip install "stata-code[kernel]"` + `stata-code-kernel install --user` registers a **Stata** kernel that the Jupyter Notebook UI, JupyterLab, and the VS Code Jupyter extension all pick up by name. Cells render Stata logs, graphs, and warnings inline (the kernel logo bundled in v0.5 makes it appear in VS Code's kernel picker too). See [As a Jupyter Kernel](#as-a-jupyter-kernel).
|
|
29
|
+
- **Optional agent "fix and rerun" loop.** `stata_run` returns typed `error.kind/line/context` plus `suggestions` on every failure. By default Claude Code only reports diagnostics — but if you explicitly say "fix this and rerun until it passes", the agent uses the same fields to edit your `.do` file and re-call `stata_run` until the run is green. The repair loop is **opt-in**: failed runs are diagnostics first, not automatic rewrite permission. See [Error Recovery in Agent Workflows](#error-recovery-in-agent-workflows).
|
|
25
30
|
|
|
26
31
|
---
|
|
27
32
|
|
|
@@ -118,6 +123,15 @@ claude mcp add stata-code --scope project -- stata-code-mcp
|
|
|
118
123
|
|
|
119
124
|
Then launch `claude` and type `/mcp` to confirm `stata-code` shows up with its 8 tools (`stata_run`, `stata_info`, `get_log`, `get_graph`, `get_matrix`, `list_sessions`, `cancel_session`, `reset_session`).
|
|
120
125
|
|
|
126
|
+
#### Error Recovery in Agent Workflows
|
|
127
|
+
|
|
128
|
+
`stata_run` does not rewrite the source `.do` file or change code on its own. It executes the submitted Stata code, so that code may still create logs, graphs, tables, or other outputs as usual. When Stata fails, `stata_run` returns typed diagnostics (`error.kind`, `error.message`, `error.line`, `error.context`) plus best-effort `suggestions`. That supports two distinct Claude Code workflows:
|
|
129
|
+
|
|
130
|
+
- For "run this do-file" or "verify this code", Claude can report the failure and suggested next steps without changing source files.
|
|
131
|
+
- For "fix this and rerun until it passes", Claude can use the same structured error fields to edit the `.do` file, call `stata_run` again, and iterate.
|
|
132
|
+
|
|
133
|
+
If you want the repair loop, say so explicitly. Otherwise, treat failed runs as diagnostics first, not as automatic permission to rewrite code.
|
|
134
|
+
|
|
121
135
|
#### `uvx` (no global pip install)
|
|
122
136
|
|
|
123
137
|
If you prefer not to `pip install stata-code` globally, run it ephemerally through [`uv`](https://github.com/astral-sh/uv):
|
|
@@ -276,7 +290,7 @@ stata_code/
|
|
|
276
290
|
|
|
277
291
|
## Roadmap
|
|
278
292
|
|
|
279
|
-
### Done (v0.
|
|
293
|
+
### Done (through v0.5 — May 2026)
|
|
280
294
|
|
|
281
295
|
- v1.0 result schema ([SCHEMA.md](SCHEMA.md))
|
|
282
296
|
- `pystata`-based runner with native-typed `r()`, `e()`, and matrices
|
|
@@ -309,7 +323,7 @@ See [SCHEMA.md §7](SCHEMA.md) for explicitly out-of-scope items.
|
|
|
309
323
|
|
|
310
324
|
```bash
|
|
311
325
|
pip install -e ".[dev,mcp,kernel]"
|
|
312
|
-
pytest # full suite (
|
|
326
|
+
pytest # full suite (218 tests)
|
|
313
327
|
pytest -m "not stata_required" # CI subset; no Stata needed
|
|
314
328
|
pytest -m "stata_required" -v # Stata-only integration tests
|
|
315
329
|
```
|
|
@@ -364,7 +378,12 @@ The Stata tooling landscape that this project builds on and learns from is surve
|
|
|
364
378
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
365
379
|
```
|
|
366
380
|
|
|
367
|
-
**当前状态:v0.
|
|
381
|
+
**当前状态:v0.5(2026 年 5 月)** —— core、MCP server、Jupyter kernel、VS Code 扩展都已经在 Stata 18 MP 上端到端跑通。测试套件:218 个 passing tests,覆盖 schema、runner、MCP、kernel 和 ref-store。许可证:**MIT**。
|
|
382
|
+
|
|
383
|
+
v0.5 明确支持的两种用户工作流:
|
|
384
|
+
|
|
385
|
+
- **在 Jupyter notebook 里跑 Stata 代码。** `pip install "stata-code[kernel]"` + `stata-code-kernel install --user` 会注册一个名为 **Stata** 的 kernel,Jupyter Notebook、JupyterLab、以及 VS Code 的 Jupyter 扩展都能在 kernel 选择器里看到它。Cell 里直接写 Stata 命令,日志、图形和警告会内联渲染(v0.5 把 kernel logo 一起打包进 PyPI wheel,VS Code 的 Jupyter kernel picker 也能正常显示)。详见下文 [作为 Jupyter kernel](#作为-jupyter-kernel)。
|
|
386
|
+
- **可选的 agent「修复并重跑」循环。** `stata_run` 在每次失败时都会返回结构化的 `error.kind/line/context` 和 `suggestions`。默认情况下 Claude Code 只把它当作诊断信息上报;但如果你明确说「帮我修到跑通」「修复并反复运行直到成功」,agent 就会用同一组字段去改 `.do` 文件、再调 `stata_run`,直到代码通过。这个修复循环是 **opt-in** 的:默认失败 = 诊断,不是自动改写授权。详见下文 [Agent 工作流里的报错恢复](#agent-工作流里的报错恢复)。
|
|
368
387
|
|
|
369
388
|
---
|
|
370
389
|
|
|
@@ -460,6 +479,15 @@ claude mcp add stata-code --scope project -- stata-code-mcp
|
|
|
460
479
|
|
|
461
480
|
接着运行 `claude`,输入 `/mcp` 确认 `stata-code` 出现并带有 8 个工具(`stata_run`, `stata_info`, `get_log`, `get_graph`, `get_matrix`, `list_sessions`, `cancel_session`, `reset_session`)。
|
|
462
481
|
|
|
482
|
+
#### Agent 工作流里的报错恢复
|
|
483
|
+
|
|
484
|
+
`stata_run` 不会自行改写源 `.do` 文件或替你改代码。它执行提交的 Stata 代码,所以代码本身仍可能照常生成日志、图形、表格或其他输出。Stata 报错时,`stata_run` 返回结构化诊断(`error.kind`, `error.message`, `error.line`, `error.context`)和尽力生成的 `suggestions`。这支持两种不同的 Claude Code 工作流:
|
|
485
|
+
|
|
486
|
+
- 如果你说的是「运行这个 do-file」或「验证这段代码」,Claude 可以只报告失败原因和建议的下一步,不修改源文件。
|
|
487
|
+
- 如果你明确说「帮我修到跑通」或「修复并反复运行直到成功」,Claude 可以基于同一组结构化错误字段修改 `.do` 文件,再调用 `stata_run` 继续迭代。
|
|
488
|
+
|
|
489
|
+
如果需要自动修复循环,请明确说出来。否则,失败的运行应先被视为诊断结果,而不是自动改写代码的授权。
|
|
490
|
+
|
|
463
491
|
#### 用 `uvx`(不必全局 pip install)
|
|
464
492
|
|
|
465
493
|
如果不想全局 `pip install stata-code`,可以用 [`uv`](https://github.com/astral-sh/uv) 临时运行:
|
|
@@ -389,7 +389,7 @@ Populated iff `ok: false`. The schema's most important contribution to agent UX:
|
|
|
389
389
|
}
|
|
390
390
|
```
|
|
391
391
|
|
|
392
|
-
Suggestions are best-effort; agents should treat them as hints, not directives. The `kind` enum below documents what suggestions are typically populated.
|
|
392
|
+
Suggestions are best-effort; agents should treat them as hints, not directives. A suggestion is not consent to mutate source files or silently retry changed code; consumers should apply fixes automatically only in workflows where the user requested repair or approved iteration. The `kind` enum below documents what suggestions are typically populated.
|
|
393
393
|
|
|
394
394
|
**`kind` enum (v1.0):**
|
|
395
395
|
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#8B1E2D"/>
|
|
5
|
+
<stop offset="1" stop-color="#5A1220"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="bar" x1="0" y1="0" x2="1" y2="0">
|
|
8
|
+
<stop offset="0" stop-color="#F5E9D2" stop-opacity="0.55"/>
|
|
9
|
+
<stop offset="0.5" stop-color="#F5E9D2"/>
|
|
10
|
+
<stop offset="1" stop-color="#F5E9D2" stop-opacity="0.55"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
</defs>
|
|
13
|
+
|
|
14
|
+
<rect width="64" height="64" rx="12" fill="url(#bg)"/>
|
|
15
|
+
|
|
16
|
+
<g stroke="url(#bar)" stroke-width="3" stroke-linecap="round" fill="none">
|
|
17
|
+
<line x1="14" y1="32" x2="50" y2="32"/>
|
|
18
|
+
<line x1="14" y1="24" x2="14" y2="40" stroke="#F5E9D2"/>
|
|
19
|
+
<line x1="50" y1="24" x2="50" y2="40" stroke="#F5E9D2"/>
|
|
20
|
+
</g>
|
|
21
|
+
|
|
22
|
+
<g>
|
|
23
|
+
<circle cx="32" cy="19" r="1.2" fill="#F5E9D2"/>
|
|
24
|
+
<line x1="32" y1="20" x2="32" y2="24" stroke="#F5E9D2" stroke-width="1.2" stroke-linecap="round"/>
|
|
25
|
+
<rect x="24" y="24" width="16" height="14" rx="3" fill="#F5E9D2"/>
|
|
26
|
+
<circle cx="28.5" cy="30" r="1.5" fill="#5A1220"/>
|
|
27
|
+
<circle cx="35.5" cy="30" r="1.5" fill="#5A1220"/>
|
|
28
|
+
<circle cx="28.5" cy="30" r="0.45" fill="#F5E9D2"/>
|
|
29
|
+
<circle cx="35.5" cy="30" r="0.45" fill="#F5E9D2"/>
|
|
30
|
+
<line x1="29.5" y1="34.5" x2="34.5" y2="34.5" stroke="#5A1220" stroke-width="1.3" stroke-linecap="round"/>
|
|
31
|
+
</g>
|
|
32
|
+
|
|
33
|
+
<g fill="#F5E9D2">
|
|
34
|
+
<circle cx="22" cy="14" r="1.3" opacity="0.55"/>
|
|
35
|
+
<circle cx="44" cy="50" r="1.3" opacity="0.55"/>
|
|
36
|
+
<circle cx="42" cy="13" r="0.9" opacity="0.4"/>
|
|
37
|
+
<circle cx="22" cy="51" r="0.9" opacity="0.4"/>
|
|
38
|
+
<circle cx="52" cy="11" r="0.7" opacity="0.3"/>
|
|
39
|
+
<circle cx="12" cy="53" r="0.7" opacity="0.3"/>
|
|
40
|
+
</g>
|
|
41
|
+
</svg>
|
|
@@ -13,12 +13,18 @@ Install via `python -m stata_code.kernel install --user`.
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
+
import shutil
|
|
16
17
|
import sys
|
|
17
18
|
import traceback
|
|
18
19
|
from pathlib import Path
|
|
19
20
|
from tempfile import TemporaryDirectory
|
|
20
21
|
from typing import Any
|
|
21
22
|
|
|
23
|
+
# Bundled kernelspec resources (logo files) shipped alongside this module.
|
|
24
|
+
# Copied into the kernelspec dir at install time so VS Code's Jupyter extension
|
|
25
|
+
# lists the kernel in its picker — it filters out kernelspecs without logos.
|
|
26
|
+
ASSETS_DIR = Path(__file__).parent / "assets"
|
|
27
|
+
|
|
22
28
|
try:
|
|
23
29
|
from ipykernel.kernelbase import Kernel
|
|
24
30
|
|
|
@@ -262,7 +268,11 @@ def install_kernel(user: bool = True, system: bool = False) -> None:
|
|
|
262
268
|
"""
|
|
263
269
|
from jupyter_client.kernelspec import KernelSpecManager
|
|
264
270
|
|
|
265
|
-
|
|
271
|
+
# Do not .resolve() — on macOS Homebrew venvs, .venv/bin/python is a symlink
|
|
272
|
+
# to the underlying system Python; resolving it bypasses the venv and the
|
|
273
|
+
# kernel fails to find stata_code. sys.executable already points to the
|
|
274
|
+
# interpreter currently running this install command, which is what we want.
|
|
275
|
+
py_exec = Path(sys.executable)
|
|
266
276
|
kernel_json = {
|
|
267
277
|
"argv": [
|
|
268
278
|
str(py_exec),
|
|
@@ -280,6 +290,10 @@ def install_kernel(user: bool = True, system: bool = False) -> None:
|
|
|
280
290
|
with TemporaryDirectory(prefix="stata_code_kernel_") as td:
|
|
281
291
|
src_dir = Path(td)
|
|
282
292
|
(src_dir / "kernel.json").write_text(json.dumps(kernel_json, indent=2))
|
|
293
|
+
if ASSETS_DIR.is_dir():
|
|
294
|
+
for asset in ASSETS_DIR.iterdir():
|
|
295
|
+
if asset.is_file():
|
|
296
|
+
shutil.copy2(asset, src_dir / asset.name)
|
|
283
297
|
dest = KernelSpecManager().install_kernel_spec(
|
|
284
298
|
str(src_dir),
|
|
285
299
|
kernel_name="stata",
|
|
@@ -43,7 +43,7 @@ from stata_code.core.runner import (
|
|
|
43
43
|
is_cancel_pending,
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
__version__ = "0.
|
|
46
|
+
__version__ = "0.5.0"
|
|
47
47
|
|
|
48
48
|
APP: Any = Server("stata-code") if _MCP_AVAILABLE else None
|
|
49
49
|
|
|
@@ -63,7 +63,11 @@ def _tool_definitions() -> list[Tool]:
|
|
|
63
63
|
"error (typed), log (head+tail+ref by default), results.r/e "
|
|
64
64
|
"(scalars/macros/matrices, native types), dataset metadata, "
|
|
65
65
|
"graphs, warnings, and capabilities. Use the structured "
|
|
66
|
-
"fields rather than parsing the log."
|
|
66
|
+
"fields rather than parsing the log. On ok=false, surface "
|
|
67
|
+
"error.kind/message/line/suggestions. Use suggestions for "
|
|
68
|
+
"iterative debug/fix loops only when the user asked for that "
|
|
69
|
+
"or approved changes; for run/validate-only requests, report "
|
|
70
|
+
"diagnostics without rewriting source code."
|
|
67
71
|
),
|
|
68
72
|
inputSchema={
|
|
69
73
|
"type": "object",
|
|
@@ -221,7 +221,7 @@ class TestInstallKernel:
|
|
|
221
221
|
"replace": True,
|
|
222
222
|
"spec": {
|
|
223
223
|
"argv": [
|
|
224
|
-
str(
|
|
224
|
+
str(tmp_path / "python"),
|
|
225
225
|
"-m",
|
|
226
226
|
"stata_code.kernel",
|
|
227
227
|
"-f",
|
|
@@ -234,6 +234,37 @@ class TestInstallKernel:
|
|
|
234
234
|
}
|
|
235
235
|
]
|
|
236
236
|
|
|
237
|
+
def test_install_kernel_copies_bundled_logos(self, tmp_path):
|
|
238
|
+
"""install_kernel should copy bundled logo assets into the kernelspec."""
|
|
239
|
+
from stata_code.kernel.kernel import ASSETS_DIR, install_kernel
|
|
240
|
+
|
|
241
|
+
captured_files: dict[str, bytes] = {}
|
|
242
|
+
|
|
243
|
+
class DummyKernelSpecManager:
|
|
244
|
+
def install_kernel_spec(
|
|
245
|
+
self,
|
|
246
|
+
source_dir: str,
|
|
247
|
+
*,
|
|
248
|
+
kernel_name: str,
|
|
249
|
+
user: bool,
|
|
250
|
+
replace: bool,
|
|
251
|
+
) -> str:
|
|
252
|
+
for child in Path(source_dir).iterdir():
|
|
253
|
+
if child.is_file():
|
|
254
|
+
captured_files[child.name] = child.read_bytes()
|
|
255
|
+
return str(tmp_path / "kernels" / kernel_name)
|
|
256
|
+
|
|
257
|
+
with patch(
|
|
258
|
+
"jupyter_client.kernelspec.KernelSpecManager",
|
|
259
|
+
return_value=DummyKernelSpecManager(),
|
|
260
|
+
):
|
|
261
|
+
install_kernel(user=True)
|
|
262
|
+
|
|
263
|
+
for asset in ASSETS_DIR.iterdir():
|
|
264
|
+
if asset.is_file():
|
|
265
|
+
assert asset.name in captured_files, f"missing {asset.name}"
|
|
266
|
+
assert captured_files[asset.name] == asset.read_bytes()
|
|
267
|
+
|
|
237
268
|
def test_install_kernel_system_not_user(self, tmp_path):
|
|
238
269
|
"""system=True should pass user=False to Jupyter's installer."""
|
|
239
270
|
from stata_code.kernel.kernel import install_kernel
|
|
@@ -44,6 +44,10 @@ class TestToolRegistry:
|
|
|
44
44
|
assert schema["type"] == "object"
|
|
45
45
|
assert "code" in schema["properties"]
|
|
46
46
|
assert "code" in schema["required"]
|
|
47
|
+
assert "ok=false" in run.description
|
|
48
|
+
assert "iterative debug/fix loops" in run.description
|
|
49
|
+
assert "run/validate-only requests" in run.description
|
|
50
|
+
assert "without rewriting source code" in run.description
|
|
47
51
|
# Token-economy options are exposed
|
|
48
52
|
assert "include_graphs" in schema["properties"]
|
|
49
53
|
assert "include_full_log" in schema["properties"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|