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.
- {stata_code-0.9.1 → stata_code-0.12.0}/CHANGELOG.md +267 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/PKG-INFO +243 -35
- stata_code-0.9.1/README.md → stata_code-0.12.0/README.en.md +242 -34
- stata_code-0.12.0/README.md +724 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/SCHEMA.md +118 -33
- {stata_code-0.9.1 → stata_code-0.12.0}/docs/competitive-landscape.md +58 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/docs/industry-leader-roadmap.md +1 -1
- stata_code-0.12.0/docs/quickstart.zh.md +126 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/pyproject.toml +5 -2
- {stata_code-0.9.1 → stata_code-0.12.0}/schema/run_result.schema.json +88 -0
- stata_code-0.12.0/scripts/build_standalone.py +81 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/__init__.py +77 -1
- stata_code-0.12.0/stata_code/cli.py +799 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/_pool.py +109 -9
- stata_code-0.12.0/stata_code/core/console.py +818 -0
- stata_code-0.12.0/stata_code/core/daemon.py +570 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/errors.py +82 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/estimation.py +132 -36
- stata_code-0.12.0/stata_code/core/jobs.py +200 -0
- stata_code-0.12.0/stata_code/core/lint.py +246 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/log_artifacts.py +59 -1
- stata_code-0.12.0/stata_code/core/policy.py +375 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/runner.py +636 -95
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/schema.py +61 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/doctor.py +22 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/kernel.py +6 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/mcp/server.py +468 -16
- stata_code-0.12.0/stata_code/mcp_setup.py +174 -0
- stata_code-0.12.0/tests/test_agent_ergonomics.py +867 -0
- stata_code-0.12.0/tests/test_benchmark.py +59 -0
- stata_code-0.12.0/tests/test_cli.py +213 -0
- stata_code-0.12.0/tests/test_console.py +304 -0
- stata_code-0.12.0/tests/test_daemon.py +423 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_errors.py +5 -1
- stata_code-0.12.0/tests/test_lint.py +89 -0
- stata_code-0.12.0/tests/test_lint_mcp.py +67 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_mcp.py +82 -134
- stata_code-0.12.0/tests/test_mcp_transport.py +51 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_new_tools.py +8 -6
- stata_code-0.12.0/tests/test_policy.py +156 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_runner.py +153 -6
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_runner_helpers.py +109 -17
- stata_code-0.9.1/stata_code/cli.py +0 -85
- stata_code-0.9.1/tests/test_mcp_stdio.py +0 -163
- {stata_code-0.9.1 → stata_code-0.12.0}/.gitignore +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/LICENSE +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/LICENSE-POLICY.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/PUBLISHING.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/docs/design/hard_timeout.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/01-basic-regression.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/02-did-card-krueger.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/03-graphs.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/04-multi-session.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/05-large-matrix.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/06-cross-stack-parity-audit.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/07-data-mcp-handoff.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/examples/README.md +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/scripts/build_skill_zip.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/scripts/check_github_actions.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/scripts/check_versions.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/scripts/export_schema.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/__main__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/__init__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/_refs.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/_runtime.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/handoff.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/notebook.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/provenance.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/core/run_index.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/__init__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/__main__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/assets/logo-32x32.png +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/assets/logo-64x64.png +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/kernel/assets/logo-svg.svg +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/mcp/__init__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/stata_code/mcp/__main__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/__init__.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/conftest.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/fixtures/.gitkeep +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_bugfix_regressions.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_cancel.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_doctor.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_estimation.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_github_actions.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_handoff.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_kernel.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_log_artifacts.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_mcp_kernel_extra.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_method_prompts.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_notebook.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_notebook_phase2.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_pool.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_pool_refs_extra.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_provenance.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_public_api.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_real_stata.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_release_versions.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_run_index.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_runtime_discovery.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_schema.py +0 -0
- {stata_code-0.9.1 → stata_code-0.12.0}/tests/test_schema_artifact.py +0 -0
- {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,
|