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.
Files changed (47) hide show
  1. {stata_code-0.4.0 → stata_code-0.5.0}/.gitignore +13 -0
  2. {stata_code-0.4.0 → stata_code-0.5.0}/CHANGELOG.md +39 -0
  3. {stata_code-0.4.0 → stata_code-0.5.0}/PKG-INFO +33 -5
  4. {stata_code-0.4.0 → stata_code-0.5.0}/README.md +32 -4
  5. {stata_code-0.4.0 → stata_code-0.5.0}/SCHEMA.md +1 -1
  6. {stata_code-0.4.0 → stata_code-0.5.0}/pyproject.toml +1 -1
  7. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/__init__.py +1 -1
  8. stata_code-0.5.0/stata_code/kernel/assets/logo-32x32.png +0 -0
  9. stata_code-0.5.0/stata_code/kernel/assets/logo-64x64.png +0 -0
  10. stata_code-0.5.0/stata_code/kernel/assets/logo-svg.svg +41 -0
  11. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/kernel/kernel.py +15 -1
  12. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/mcp/server.py +6 -2
  13. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_kernel.py +32 -1
  14. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_mcp.py +4 -0
  15. {stata_code-0.4.0 → stata_code-0.5.0}/LICENSE +0 -0
  16. {stata_code-0.4.0 → stata_code-0.5.0}/LICENSE-POLICY.md +0 -0
  17. {stata_code-0.4.0 → stata_code-0.5.0}/PUBLISHING.md +0 -0
  18. {stata_code-0.4.0 → stata_code-0.5.0}/docs/design/hard_timeout.md +0 -0
  19. {stata_code-0.4.0 → stata_code-0.5.0}/examples/01-basic-regression.md +0 -0
  20. {stata_code-0.4.0 → stata_code-0.5.0}/examples/02-did-card-krueger.md +0 -0
  21. {stata_code-0.4.0 → stata_code-0.5.0}/examples/03-graphs.md +0 -0
  22. {stata_code-0.4.0 → stata_code-0.5.0}/examples/04-multi-session.md +0 -0
  23. {stata_code-0.4.0 → stata_code-0.5.0}/examples/05-large-matrix.md +0 -0
  24. {stata_code-0.4.0 → stata_code-0.5.0}/examples/README.md +0 -0
  25. {stata_code-0.4.0 → stata_code-0.5.0}/schema/run_result.schema.json +0 -0
  26. {stata_code-0.4.0 → stata_code-0.5.0}/scripts/export_schema.py +0 -0
  27. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/__init__.py +0 -0
  28. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/_pool.py +0 -0
  29. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/_refs.py +0 -0
  30. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/_runtime.py +0 -0
  31. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/errors.py +0 -0
  32. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/log_artifacts.py +0 -0
  33. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/runner.py +0 -0
  34. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/core/schema.py +0 -0
  35. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/kernel/__init__.py +0 -0
  36. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/kernel/__main__.py +0 -0
  37. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/mcp/__init__.py +0 -0
  38. {stata_code-0.4.0 → stata_code-0.5.0}/stata_code/mcp/__main__.py +0 -0
  39. {stata_code-0.4.0 → stata_code-0.5.0}/tests/__init__.py +0 -0
  40. {stata_code-0.4.0 → stata_code-0.5.0}/tests/fixtures/.gitkeep +0 -0
  41. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_cancel.py +0 -0
  42. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_errors.py +0 -0
  43. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_log_artifacts.py +0 -0
  44. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_pool.py +0 -0
  45. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_runner.py +0 -0
  46. {stata_code-0.4.0 → stata_code-0.5.0}/tests/test_schema.py +0 -0
  47. {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.4.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.2 (May 2026)** — the core, MCP server, and Jupyter kernel work end-to-end against Stata 18 MP. Current test suite: 144 passing tests (88 no-Stata unit tests + 56 real-Stata integration tests). License: **MIT**.
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.2 — May 2026)
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 (144 tests)
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.2(2026 年 5 月)** —— core、MCP serverJupyter kernel 已经可以在 Stata 18 MP 上端到端运行。当前测试:144 passing(88 个不需要 Stata 的单元测试 + 56 个真实 Stata 集成测试)。许可证:**MIT**。
419
+ **当前状态:v0.5(2026 年 5 月)** —— core、MCP serverJupyter 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.2 (May 2026)** — the core, MCP server, and Jupyter kernel work end-to-end against Stata 18 MP. Current test suite: 144 passing tests (88 no-Stata unit tests + 56 real-Stata integration tests). License: **MIT**.
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.2 — May 2026)
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 (144 tests)
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.2(2026 年 5 月)** —— core、MCP serverJupyter kernel 已经可以在 Stata 18 MP 上端到端运行。当前测试:144 passing(88 个不需要 Stata 的单元测试 + 56 个真实 Stata 集成测试)。许可证:**MIT**。
381
+ **当前状态:v0.5(2026 年 5 月)** —— core、MCP serverJupyter 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
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "stata-code"
7
- version = "0.4.0"
7
+ version = "0.5.0"
8
8
  description = "Agent-native Stata bridge — one core, multiple frontends (MCP, Jupyter, VSCode)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -58,7 +58,7 @@ from stata_code.core.schema import (
58
58
  # Convenience alias: `run(...)` == `execute(...)`.
59
59
  run = execute
60
60
 
61
- __version__ = "0.4.0"
61
+ __version__ = "0.5.0"
62
62
 
63
63
  __all__ = [
64
64
  # Primary entry points
@@ -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
- py_exec = Path(sys.executable).resolve()
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.4.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((tmp_path / "python").resolve()),
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