stata-code 0.9.1__tar.gz → 0.12.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 (102) hide show
  1. {stata_code-0.9.1 → stata_code-0.12.0}/CHANGELOG.md +267 -0
  2. {stata_code-0.9.1 → stata_code-0.12.0}/PKG-INFO +243 -35
  3. stata_code-0.9.1/README.md → stata_code-0.12.0/README.en.md +242 -34
  4. stata_code-0.12.0/README.md +724 -0
  5. {stata_code-0.9.1 → stata_code-0.12.0}/SCHEMA.md +118 -33
  6. {stata_code-0.9.1 → stata_code-0.12.0}/docs/competitive-landscape.md +58 -0
  7. {stata_code-0.9.1 → stata_code-0.12.0}/docs/industry-leader-roadmap.md +1 -1
  8. stata_code-0.12.0/docs/quickstart.zh.md +126 -0
  9. {stata_code-0.9.1 → stata_code-0.12.0}/pyproject.toml +5 -2
  10. {stata_code-0.9.1 → stata_code-0.12.0}/schema/run_result.schema.json +88 -0
  11. stata_code-0.12.0/scripts/build_standalone.py +81 -0
  12. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/__init__.py +77 -1
  13. stata_code-0.12.0/stata_code/cli.py +799 -0
  14. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/_pool.py +109 -9
  15. stata_code-0.12.0/stata_code/core/console.py +818 -0
  16. stata_code-0.12.0/stata_code/core/daemon.py +570 -0
  17. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/errors.py +82 -0
  18. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/estimation.py +132 -36
  19. stata_code-0.12.0/stata_code/core/jobs.py +200 -0
  20. stata_code-0.12.0/stata_code/core/lint.py +246 -0
  21. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/log_artifacts.py +59 -1
  22. stata_code-0.12.0/stata_code/core/policy.py +375 -0
  23. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/runner.py +636 -95
  24. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/schema.py +61 -0
  25. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/doctor.py +22 -0
  26. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/kernel.py +6 -0
  27. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/mcp/server.py +468 -16
  28. stata_code-0.12.0/stata_code/mcp_setup.py +174 -0
  29. stata_code-0.12.0/tests/test_agent_ergonomics.py +867 -0
  30. stata_code-0.12.0/tests/test_benchmark.py +59 -0
  31. stata_code-0.12.0/tests/test_cli.py +213 -0
  32. stata_code-0.12.0/tests/test_console.py +304 -0
  33. stata_code-0.12.0/tests/test_daemon.py +423 -0
  34. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_errors.py +5 -1
  35. stata_code-0.12.0/tests/test_lint.py +89 -0
  36. stata_code-0.12.0/tests/test_lint_mcp.py +67 -0
  37. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_mcp.py +82 -134
  38. stata_code-0.12.0/tests/test_mcp_transport.py +51 -0
  39. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_new_tools.py +8 -6
  40. stata_code-0.12.0/tests/test_policy.py +156 -0
  41. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_runner.py +153 -6
  42. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_runner_helpers.py +109 -17
  43. stata_code-0.9.1/stata_code/cli.py +0 -85
  44. stata_code-0.9.1/tests/test_mcp_stdio.py +0 -163
  45. {stata_code-0.9.1 → stata_code-0.12.0}/.gitignore +0 -0
  46. {stata_code-0.9.1 → stata_code-0.12.0}/LICENSE +0 -0
  47. {stata_code-0.9.1 → stata_code-0.12.0}/LICENSE-POLICY.md +0 -0
  48. {stata_code-0.9.1 → stata_code-0.12.0}/PUBLISHING.md +0 -0
  49. {stata_code-0.9.1 → stata_code-0.12.0}/docs/design/hard_timeout.md +0 -0
  50. {stata_code-0.9.1 → stata_code-0.12.0}/examples/01-basic-regression.md +0 -0
  51. {stata_code-0.9.1 → stata_code-0.12.0}/examples/02-did-card-krueger.md +0 -0
  52. {stata_code-0.9.1 → stata_code-0.12.0}/examples/03-graphs.md +0 -0
  53. {stata_code-0.9.1 → stata_code-0.12.0}/examples/04-multi-session.md +0 -0
  54. {stata_code-0.9.1 → stata_code-0.12.0}/examples/05-large-matrix.md +0 -0
  55. {stata_code-0.9.1 → stata_code-0.12.0}/examples/06-cross-stack-parity-audit.md +0 -0
  56. {stata_code-0.9.1 → stata_code-0.12.0}/examples/07-data-mcp-handoff.md +0 -0
  57. {stata_code-0.9.1 → stata_code-0.12.0}/examples/README.md +0 -0
  58. {stata_code-0.9.1 → stata_code-0.12.0}/scripts/build_skill_zip.py +0 -0
  59. {stata_code-0.9.1 → stata_code-0.12.0}/scripts/check_github_actions.py +0 -0
  60. {stata_code-0.9.1 → stata_code-0.12.0}/scripts/check_versions.py +0 -0
  61. {stata_code-0.9.1 → stata_code-0.12.0}/scripts/export_schema.py +0 -0
  62. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/__main__.py +0 -0
  63. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/__init__.py +0 -0
  64. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/_refs.py +0 -0
  65. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/_runtime.py +0 -0
  66. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/handoff.py +0 -0
  67. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/notebook.py +0 -0
  68. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/provenance.py +0 -0
  69. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/run_index.py +0 -0
  70. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/__init__.py +0 -0
  71. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/__main__.py +0 -0
  72. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/assets/logo-32x32.png +0 -0
  73. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/assets/logo-64x64.png +0 -0
  74. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/assets/logo-svg.svg +0 -0
  75. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/mcp/__init__.py +0 -0
  76. {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/mcp/__main__.py +0 -0
  77. {stata_code-0.9.1 → stata_code-0.12.0}/tests/__init__.py +0 -0
  78. {stata_code-0.9.1 → stata_code-0.12.0}/tests/conftest.py +0 -0
  79. {stata_code-0.9.1 → stata_code-0.12.0}/tests/fixtures/.gitkeep +0 -0
  80. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_bugfix_regressions.py +0 -0
  81. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_cancel.py +0 -0
  82. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_doctor.py +0 -0
  83. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_estimation.py +0 -0
  84. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_github_actions.py +0 -0
  85. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_handoff.py +0 -0
  86. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_kernel.py +0 -0
  87. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_log_artifacts.py +0 -0
  88. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_mcp_kernel_extra.py +0 -0
  89. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_method_prompts.py +0 -0
  90. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_notebook.py +0 -0
  91. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_notebook_phase2.py +0 -0
  92. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_pool.py +0 -0
  93. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_pool_refs_extra.py +0 -0
  94. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_provenance.py +0 -0
  95. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_public_api.py +0 -0
  96. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_real_stata.py +0 -0
  97. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_release_versions.py +0 -0
  98. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_run_index.py +0 -0
  99. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_runtime_discovery.py +0 -0
  100. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_schema.py +0 -0
  101. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_schema_artifact.py +0 -0
  102. {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_skill_package.py +0 -0
@@ -6,6 +6,273 @@ to semver-major.minor for the result schema (see `SCHEMA.md` §6).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 0.12.0 — 2026-07-28
10
+
11
+ Adds a resident session daemon so the CLI can keep data in memory across
12
+ invocations, and fixes a VS Code regression introduced by 0.11.0's payload
13
+ defaults.
14
+
15
+ ### Added
16
+
17
+ #### Resident session daemon — state across CLI invocations
18
+
19
+ The subprocess pool already kept one Stata worker alive per session, but a plain
20
+ `stata-code run` owned that pool and tore it down on exit, so two consecutive CLI
21
+ calls could not share data in memory. The new `daemon` subcommand holds the pool
22
+ in a resident process behind a Unix socket:
23
+
24
+ ```bash
25
+ stata-code run --daemon -e 'sysuse auto, clear' -e 'gen z = price/1000'
26
+ stata-code run --daemon -e 'summarize z' # new process, z is still loaded
27
+ ```
28
+
29
+ - **`stata-code run --daemon`** routes the run through the daemon, starting it on
30
+ demand. `--socket` overrides the path. Graph refs are resolved back over the
31
+ socket, so `--graphs DIR` keeps working.
32
+ - **`stata-code daemon start | stop | restart | status`** for explicit control;
33
+ `status --json` is machine-readable.
34
+ - **Idle retirement** after 30 minutes by default (`--idle-timeout`, `0` disables)
35
+ so a forgotten daemon does not hold a Stata license slot.
36
+ - **Unix socket only, never TCP** — mode 0600 inside a mode-0700 directory. The
37
+ command-safety guard still applies to everything the daemon runs.
38
+ - **Requires the pystata backend.** `--backend console` is stateless batch
39
+ execution, so combining it with `--daemon` is a hard error rather than a silent
40
+ no-op.
41
+ - Falls back to a short hashed `/tmp` socket path when the natural location would
42
+ exceed the platform's ~104-byte `sun_path` limit; every entry point derives the
43
+ same fallback, so clients still find the daemon.
44
+
45
+ #### VS Code Outputs panel now lists what every run wrote
46
+
47
+ The panel read only `log.files.output_paths` — the archived copies inside a run
48
+ bundle — so it stayed empty unless the caller had opted into
49
+ `persist_log_files`. It now also reads `result.outputs`, the files a run wrote
50
+ in its working directory (reported on every run since 0.11.0), shown with their
51
+ size and listed *ahead* of bundle copies, since the working-directory file is
52
+ the one you want to open. Nodes carry an `origin` of `workdir` or `bundle`, and
53
+ an overwritten file says so in its tooltip.
54
+
55
+ ### Fixed
56
+
57
+ - **VS Code: r()/e() matrices displayed as `0x0` and opened empty.** 0.11.0
58
+ made `include_results: "scalars"` the server default, which returns each
59
+ matrix as a `matrix://` stub with `rows` / `cols` elided (the true shape moved
60
+ to `n_rows` / `n_cols`). The extension's sidebar derives its dimension label
61
+ from `rows.length` / `cols.length` and renders `matrix.values` directly, so
62
+ every matrix showed `0x0` and exported an empty table. The extension now
63
+ requests `include_results: "full"` — an editor is a human surface with no
64
+ token budget to defend, matching what the Jupyter kernel already did. The
65
+ argument builder moved to a `vscode`-free `runArgs.ts` so the behaviour is
66
+ covered by unit tests.
67
+ - Documentation: the error taxonomy was described as "32 kinds" in `README.md`,
68
+ `README.en.md`, and `SCHEMA.md` while `ErrorKind` has had 34 members (the
69
+ English README's prose already said 34, contradicting its own table).
70
+ - Documentation: both READMEs listed "Stata 17+" as a hard install requirement,
71
+ which contradicted the console backend's documented Stata 13+ support.
72
+ - `README.md` was missing the command-line, client-setup, and command-safety
73
+ sections that `README.en.md` has had since 0.11.0.
74
+ - Documentation: `SKILL.md` and the agent reference library still described the
75
+ pre-0.11 surface — 18 tools, 31 error kinds, no mention of matrix stubs,
76
+ background runs, `result.outputs`, or `error.source_file`. Counts in every doc
77
+ are now checked against the code.
78
+
79
+ ### Internal
80
+
81
+ - `_collect_returns` no longer takes a `request_id` or creates `matrix://` refs.
82
+ Nothing passed it — neither the production path nor any test — and ref
83
+ creation belongs to `_project_returns`, which owns the payload budget.
84
+ - `test_varname_not_found_emits_did_you_mean` failed once and could not be
85
+ reproduced. Its fuzzy match draws candidates from `dataset.variables`, so a
86
+ lost `auto.dta` in the shared in-process Stata degrades the suggestion for
87
+ reasons unrelated to the matching logic. The assertion was **split**, not
88
+ loosened: a precondition check now reports which of the two it was.
89
+
90
+ ## 0.11.0 — 2026-07-28
91
+
92
+ An agent-ergonomics release, driven by a report from an agent that used the MCP
93
+ server to write a full empirical paper. Each item below is a cost that agent
94
+ actually paid.
95
+
96
+ **Minor, not patch:** `include_results` defaults to `"scalars"`, so `r()` / `e()`
97
+ matrices now arrive as `matrix://` stubs instead of inline values. Pass
98
+ `include_results="full"` for the previous shape. `results.estimation` is
99
+ unaffected — and is now *more* accurate, since two silent numeric bugs in it are
100
+ fixed. The Jupyter kernel and the `stata-code run` CLI keep `"full"`.
101
+
102
+ ### Agent-ergonomics pass
103
+
104
+ #### Result payloads are now bounded (and correct)
105
+
106
+ - **`include_results`** (`"none" | "scalars" | "full"`, default **`"scalars"`**).
107
+ A single estimation used to encode the same numbers four times over — `e(b)`,
108
+ `e(V)`'s row/column labels, `e(beta)`, and `r(table)` — on top of
109
+ `results.estimation`. Under the new default, scalars and macros stay inline
110
+ and every matrix becomes a `matrix://` stub carrying only its shape
111
+ (`n_rows` / `n_cols`); values and labels remain retrievable with
112
+ `get_matrix(ref)`. A 123-term regression's envelope drops from ~57 KB to
113
+ ~28 KB. **This is a behaviour change** — pass `include_results="full"` for
114
+ the previous shape. The Jupyter kernel keeps `"full"`, since a notebook has
115
+ no token budget to defend.
116
+ - **`include_estimation`** (`"none" | "summary" | "full"`, default `"full"`)
117
+ and **`max_coefficients`**. `"summary"` keeps the model-level block and
118
+ diagnostics but drops per-term rows — the right setting for specifications
119
+ dominated by `i.year i.firm` nuisance terms. `estimation.n_coefficients`
120
+ always reports the model's true term count and
121
+ `estimation.coefficients_truncated` flags any cut, so trimmed output can
122
+ never be mistaken for a smaller model.
123
+
124
+ #### Fixed: two silent numeric-correctness bugs
125
+
126
+ - **Standard errors were blanked whenever `e(V)` was returned by reference.**
127
+ Any model whose VCV exceeded the inline cell cap (roughly >100 terms) came
128
+ back with `se`, `statistic`, `p_value` and both CI bounds `null` for *every*
129
+ coefficient, while still reporting `source: "e_b_v"` as though inference had
130
+ been computed. The estimation builder now resolves `matrix://` refs, so the
131
+ wire representation no longer degrades the numbers. `e(b)` by reference is
132
+ resolved too, where it previously suppressed the estimation block entirely.
133
+ - **`r()` did not survive to the next call.** The runner's own probes are all
134
+ r-class (`graph dir` before a run, `graph export` after), so the canonical
135
+ two-call pattern — `summarize price`, then `display r(mean)` — read back a
136
+ missing value. All internal housekeeping now runs inside a Stata
137
+ `_return hold` / `_return restore` pair. Pre-existing; the new `log query`
138
+ probe would have widened it to runs with `include_graphs="none"`.
139
+ - **Stata's missing values leaked as `8.988e+307`.** `sfi` returns system
140
+ missing (`.`) and extended missings (`.a`–`.z`) as ordinary doubles at or
141
+ above `2^1023`. These reached the wire unconverted in `r()`/`e()` scalars and
142
+ in every matrix cell — an omitted base level's standard error arrived as a
143
+ number an agent would format into a table. All numerics now normalize to
144
+ `null`, matching what SCHEMA.md already required of scalars.
145
+
146
+ #### Errors inside `do`-files are now located
147
+
148
+ - `error.line` and `error.context` are resolved **inside the invoked script**.
149
+ A failing `do "analysis.do"` previously produced `line: null`, empty
150
+ before/after context, and `message: "end of do-file"` — Stata's epilogue
151
+ rather than the diagnosis. The transcript parser now skips structural
152
+ boilerplate (`end of do-file`, `--Break--`), folds `///` continuation
153
+ fragments back into one logical command, and resolves the failing command
154
+ against the script on disk. New `error.source_file` names the file that
155
+ `error.line` indexes into.
156
+ - **A failed run now produces a log.** pystata raises the whole transcript as
157
+ its exception message and leaves stdout empty, so failures used to come back
158
+ with no `log.head`, no `log://` ref and nothing for `search_log` to search —
159
+ exactly when the transcript matters most.
160
+
161
+ #### A failed run can no longer poison its session
162
+
163
+ - New **`auto_close_logs`** (default `true`) closes log handles that a *failed*
164
+ run opened. A script aborting between `log using` and `log close` previously
165
+ left the handle dangling, and every subsequent run in that session died with
166
+ r(604) — an error about a different run, with no suggestions attached.
167
+ Handles opened by earlier runs are left alone; a `log_closed` warning records
168
+ what was closed.
169
+ - r(604) and r(606) are now the typed `ErrorKind.LOG_STATE` with Stata's
170
+ official labels and rc-specific fixes (`capture log close _all` for 604,
171
+ `capture log close` guarding for 606), and `recovery.retriable = true`.
172
+
173
+ #### Long runs no longer block the caller
174
+
175
+ - **`timeout_ms` is an advertised `stata_run` argument.** It was enforced but
176
+ not exposed, so passing it was an input-validation error.
177
+ - **`run_in_background`** returns a `job_id` immediately; poll with the new
178
+ **`stata_run_status`** tool (`wait_ms` blocks up to 60 s instead of
179
+ busy-polling) and enumerate with **`list_background_runs`**. Intended for
180
+ bootstraps, permutation tests and grouped estimation loops.
181
+ - **Fixed: the worker lock was acquired without a deadline**, so a call queued
182
+ behind a long run blocked indefinitely no matter what `timeout_ms` said.
183
+ `timeout_ms` now budgets the whole call, queueing included, and contention
184
+ returns the new `rc=-5` / `error.kind="session_busy"` — distinct from a
185
+ timeout because nothing was submitted to Stata and the healthy worker is
186
+ *not* killed.
187
+
188
+ #### Inline graphs are visible again
189
+
190
+ - `include_graphs: "inline"` now delivers graph bytes as MCP `ImageContent`
191
+ blocks instead of base64 inside a JSON string. The old form was unreadable to
192
+ a vision-capable client and was pure token cost. `graphs[].inline` is cleared
193
+ from the structured body so the bytes cross the wire once, and
194
+ `inline_delivered` records the outcome. At most 4 images per response (the
195
+ rest stay reachable via `get_graph(ref)`, reported as an
196
+ `inline_graphs_truncated` warning); `pdf` is never sent as an image block.
197
+
198
+ #### Generated files are reported
199
+
200
+ - New top-level **`outputs`** lists files a run created or modified in its
201
+ working directory (`esttab` tables, exported graphs, saved `.dta`), with
202
+ `path` / `bytes` / `created`. Previously this required
203
+ `persist_log_files=true` *and* `origin_path` — a dependency that was not
204
+ obvious from `persist_generated_files` defaulting to `true`, so the field was
205
+ always `null` in practice. Controlled by the new `track_output_files`
206
+ (default `true`); working directories above 5,000 files skip detection and
207
+ say so with an `output_tracking_skipped` warning rather than reporting a
208
+ partial answer.
209
+
210
+ ### Added
211
+
212
+ - The VS Code extension now accepts Stata's familiar `Ctrl+D` shortcut
213
+ (`Cmd+D` on macOS) for running the selection or current line, while retaining
214
+ `Cmd/Ctrl+Enter`. The extension README also documents how to customize the
215
+ `stataCode.runSelection` keybinding and resolve conflicts.
216
+
217
+ ## 0.10.0 — 2026-07-24
218
+
219
+ Surface-coverage and safety additions so every Stata usage scenario — MCP,
220
+ Jupyter, VS Code, and now a plain Bash/terminal — routes through the same typed
221
+ engine, and so an autonomous agent loop cannot escape to the OS. Also broadens
222
+ execution to **Stata 13+ without pystata** (console backend) and adds a
223
+ zero-Python standalone binary and one-click VS Code onboarding. The default
224
+ README is now Chinese (`README.md`); the English README moves to `README.en.md`.
225
+
226
+ ### Added
227
+
228
+ - **Command-safety guard** (`stata_code.core.policy`). OS-escape / file-deletion
229
+ commands (`shell`, `winexec`, `erase`, `rm`, `rmdir`, and the `!` shell escape)
230
+ are screened out of submitted code *before* Stata runs, at both the
231
+ subprocess-pool boundary and the in-process runner. A blocked run returns
232
+ `ok=false`, `rc=-4`, `error.kind="policy_blocked"` (a new 32nd `ErrorKind`)
233
+ without touching Stata. Configurable from the environment so it crosses the
234
+ worker boundary: `STATA_CODE_COMMAND_POLICY` (`enforce` default / `warn` /
235
+ `off`), `STATA_CODE_POLICY_ALLOW`, `STATA_CODE_POLICY_BLOCK`. It is a guard
236
+ rail, not a sandbox.
237
+ - **`stata-code run`** — execute a `.do` file, one or more `-e` snippets, or
238
+ stdin through the subprocess pool and print the `RunResult` (text summary or
239
+ `--json`), with `--session`, `--timeout-ms`, `--full-log`, and `--graphs DIR`.
240
+ Exit code is `0` on success, `1` on a Stata/adapter error. This is the
241
+ Bash / plain-terminal surface: any agent that can shell out gets the full
242
+ structured error loop without MCP.
243
+ - **`stata-code setup`** — opt-in, config-mutating counterpart to `doctor`.
244
+ Writes the `stata-code` MCP server entry into Claude Code (`.mcp.json`),
245
+ Cursor (`.cursor/mcp.json`), and VS Code (`.vscode/mcp.json`), preserving other
246
+ servers and backing up any file it overwrites (`--dry-run`, `--python`,
247
+ `--json`). Codex (TOML) and Claude Desktop are emitted as copy-paste snippets.
248
+ - **Static do-file linting** (`stata_code.core.lint`), exposed as the `lint_do`
249
+ MCP tool (19th tool) and `stata-code lint`. A Stata-free syntactic check —
250
+ unbalanced braces, a `program` / `mata` / `python` block with no `end`, a stray
251
+ `end`, and a dangling `///` — so an agent can catch a class of mistakes before
252
+ spending a run. Advisory: a clean result is not a correctness guarantee.
253
+ - Public API: `lint_code`, `LintFinding`, `CommandPolicy`, `Violation`,
254
+ `policy_from_env`.
255
+ - **Console (batch) backend** (`stata_code.core.console`, `Backend.CONSOLE`).
256
+ Drives the Stata command-line executable in batch mode and parses the log plus
257
+ a marker-delimited results dump into the same v1.0 `RunResult` — typed
258
+ `r()`/`e()` scalars and macros, the estimation matrices (`e(b)`/`e(V)`/
259
+ `r(table)`), the error taxonomy, warnings, and dataset metadata. Works with
260
+ **Stata 13+** and **no pystata**. Exposed as `stata_code.run_console()`,
261
+ `stata-code run --backend {auto,pystata,console}`, and a `doctor` check. Stateless
262
+ per call; graphs not captured yet. Public API adds `run_console`,
263
+ `console_available`, `find_stata_cli`, `ConsoleNotAvailable`.
264
+ - **Zero-Python standalone binary** — `scripts/build_standalone.py` (PyInstaller)
265
+ and a CI workflow template (`packaging/standalone.github-workflow.yml`, copy to
266
+ `.github/workflows/`) build a self-contained `stata-code` executable per OS.
267
+ Paired with `--backend console` it needs no Python on the target machine.
268
+ - **One-click VS Code onboarding** — when the MCP server is missing, the extension
269
+ offers to create a workspace `.venv` and install the package; also available as
270
+ the command-palette entry "Stata: Set Up MCP Server (create .venv)".
271
+ - **Benchmark harness** (`benchmarks/`) — a tool-agnostic scaffold measuring
272
+ iterations-to-correct and tokens for typed vs. raw-log execution, with an offline
273
+ mock runner wired end-to-end and CI-covered.
274
+ - Chinese quickstart ([docs/quickstart.zh.md](docs/quickstart.zh.md)).
275
+
9
276
  ## 0.9.1 — 2026-07-22
10
277
 
11
278
  Quality-hardening pass: correctness fixes from an adversarial code review,