stata-code 0.6.2__tar.gz → 0.6.4__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.6.2 → stata_code-0.6.4}/CHANGELOG.md +186 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/PKG-INFO +68 -15
- {stata_code-0.6.2 → stata_code-0.6.4}/PUBLISHING.md +45 -22
- {stata_code-0.6.2 → stata_code-0.6.4}/README.md +66 -14
- {stata_code-0.6.2 → stata_code-0.6.4}/SCHEMA.md +17 -20
- {stata_code-0.6.2 → stata_code-0.6.4}/docs/design/hard_timeout.md +19 -26
- {stata_code-0.6.2 → stata_code-0.6.4}/pyproject.toml +2 -1
- {stata_code-0.6.2 → stata_code-0.6.4}/schema/run_result.schema.json +1 -1
- stata_code-0.6.4/scripts/check_versions.py +104 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/scripts/export_schema.py +4 -1
- stata_code-0.6.4/stata_code/__init__.py +221 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/_pool.py +269 -50
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/_runtime.py +118 -16
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/errors.py +17 -8
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/log_artifacts.py +20 -2
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/notebook.py +30 -11
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/run_index.py +27 -3
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/runner.py +111 -58
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/kernel/kernel.py +36 -11
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/mcp/server.py +181 -77
- stata_code-0.6.4/tests/conftest.py +51 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_cancel.py +3 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_mcp.py +208 -22
- stata_code-0.6.4/tests/test_mcp_stdio.py +163 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_pool.py +109 -0
- stata_code-0.6.4/tests/test_public_api.py +71 -0
- stata_code-0.6.4/tests/test_runtime_discovery.py +232 -0
- stata_code-0.6.2/stata_code/__init__.py +0 -102
- stata_code-0.6.2/tests/test_runtime_discovery.py +0 -81
- {stata_code-0.6.2 → stata_code-0.6.4}/.gitignore +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/LICENSE +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/LICENSE-POLICY.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/examples/01-basic-regression.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/examples/02-did-card-krueger.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/examples/03-graphs.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/examples/04-multi-session.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/examples/05-large-matrix.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/examples/README.md +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/__init__.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/_refs.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/core/schema.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/kernel/__init__.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/kernel/__main__.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/kernel/assets/logo-32x32.png +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/kernel/assets/logo-64x64.png +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/kernel/assets/logo-svg.svg +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/mcp/__init__.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/stata_code/mcp/__main__.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/__init__.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/fixtures/.gitkeep +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_errors.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_kernel.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_log_artifacts.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_notebook.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_notebook_phase2.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_run_index.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_runner.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_schema.py +0 -0
- {stata_code-0.6.2 → stata_code-0.6.4}/tests/test_schema_artifact.py +0 -0
|
@@ -6,6 +6,192 @@ to semver-major.minor for the result schema (see `SCHEMA.md` §6).
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.6.4 — 2026-05-21
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Claude Code plugin marketplace manifest.** `.claude-plugin/marketplace.json`
|
|
14
|
+
+ `.claude-plugin/plugin.json` expose the repo as a single-plugin
|
|
15
|
+
marketplace, so users can install everything (MCP server config + agent
|
|
16
|
+
skill) with `claude plugin marketplace add brycewang-stanford/stata-code`
|
|
17
|
+
followed by `claude plugin install stata-code`.
|
|
18
|
+
- **`stata-code` agent skill.** `skills/stata-code/SKILL.md` teaches Claude
|
|
19
|
+
the v1.0 RunResult schema, the 15 MCP tools, the token-economy defaults,
|
|
20
|
+
the 32-kind error taxonomy, and the diagnose-only vs. fix-and-rerun
|
|
21
|
+
workflows. The plugin manifest auto-installs it alongside the MCP
|
|
22
|
+
server.
|
|
23
|
+
- **VS Code install-hint probe.** On activation the extension now resolves
|
|
24
|
+
the configured `stata-code-mcp` candidate list against `PATH` and any
|
|
25
|
+
workspace `.venv` / `venv`; if nothing matches, a one-time notification
|
|
26
|
+
offers to copy the `pip install "stata-code[mcp]"` command or open the
|
|
27
|
+
install docs. "Don't show again" pins the dismissal to the installed
|
|
28
|
+
extension version. Backed by a new pure module `serverProbe.ts` with
|
|
29
|
+
unit tests.
|
|
30
|
+
- **README multi-client section.** Cursor, Claude Desktop, Cline,
|
|
31
|
+
Continue, Windsurf, and Antigravity now have their config-file paths
|
|
32
|
+
spelled out next to the shared `stata-code-mcp` JSON snippet, plus
|
|
33
|
+
guidance for project-venv absolute paths and `uvx` setups.
|
|
34
|
+
- **README cell + section reference.** Documents that the VS Code
|
|
35
|
+
extension recognizes both `* %%` Jupyter-style cell markers and
|
|
36
|
+
`**#` … `**######` six-level section headings in `.do` files, and how
|
|
37
|
+
each interacts with the code-lens and Outline view.
|
|
38
|
+
- **Open VSX publish step.** `vscode-release.yml` now publishes the VSIX
|
|
39
|
+
to Open VSX on every `vscode-v*` tag. The step is gated on
|
|
40
|
+
`OVSX_PAT` being set at runtime and runs with `continue-on-error: true`,
|
|
41
|
+
so a missing or expired token never blocks the primary VS Code
|
|
42
|
+
Marketplace publish.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **Subprocess worker JSON protocol hardening.** Worker processes now keep
|
|
47
|
+
their private JSON protocol fds separate from real stdin/stdout and
|
|
48
|
+
redirect the real fd 0/1 pair to `os.devnull` before importing the
|
|
49
|
+
runner. The parent reader also ignores blank protocol noise while still
|
|
50
|
+
failing on non-empty non-JSON output. This prevents a pystata/Stata
|
|
51
|
+
initialization newline from surfacing as
|
|
52
|
+
`adapter_crash: worker emitted non-JSON: '\n'`.
|
|
53
|
+
|
|
54
|
+
## 0.6.3 — 2026-05-10
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **`RefNotFound` exception** — `get_log` / `get_graph` / `get_matrix` now
|
|
59
|
+
raise a typed `RefNotFound` (subclass of `KeyError`) carrying the bad
|
|
60
|
+
ref and a stable `kind` token (`unknown_log_ref` / `unknown_graph_ref` /
|
|
61
|
+
`unknown_matrix_ref`). MCP dispatch maps it to a typed error response
|
|
62
|
+
without string-parsing.
|
|
63
|
+
- **`NotebookError.kind` / `RunIndexError.kind`** — both classes now
|
|
64
|
+
expose a `kind` property so callers don't have to slice the message
|
|
65
|
+
prefix manually.
|
|
66
|
+
- **`SessionPool.list_session_info_detailed`** — partial-failure-aware
|
|
67
|
+
variant of `list_session_info()` that surfaces per-worker `warnings`
|
|
68
|
+
alongside the aggregated `sessions` list. The MCP `list_sessions`
|
|
69
|
+
tool's output schema now includes the optional `warnings` field.
|
|
70
|
+
- **`list_runs.requested_limit`** — echoes the original requested limit
|
|
71
|
+
when the server clamps it to `_LIMIT_MAX`, so a caller asking for
|
|
72
|
+
`limit=1000` can distinguish "scan was capped at 500 rows" from "the
|
|
73
|
+
manifest dir really has more than 500 rows".
|
|
74
|
+
- **Server capabilities resource now includes prompts.** Reading
|
|
75
|
+
`stata://server/capabilities` returns tools, resource templates, AND
|
|
76
|
+
prompts in a single document — clients no longer need a follow-up
|
|
77
|
+
`list_prompts` round-trip just to enumerate the full surface.
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
|
|
81
|
+
- **Test hygiene** — a `tests/conftest.py` snapshot/restores `_refs._store`
|
|
82
|
+
per test and shuts the default subprocess pool down at session end.
|
|
83
|
+
Closes a class of intermittent cross-test failures caused by ref-store
|
|
84
|
+
pollution from earlier MCP / pool tests.
|
|
85
|
+
- **Subprocess cancellation race** — `SessionPool.execute()` now
|
|
86
|
+
re-checks `_cancel_pending` after `_get_or_spawn` so a `request_cancel`
|
|
87
|
+
that lands during worker spawn fires on the in-flight call instead of
|
|
88
|
+
the next one.
|
|
89
|
+
- **`stata_info` edition casing is now consistent** — the top-level
|
|
90
|
+
`edition` field mirrors `stata.edition` (the enum value, e.g. `MP`)
|
|
91
|
+
verbatim. Previously the pool path lowercased it to `mp` while the
|
|
92
|
+
in-process path emitted `MP`, so the same payload could disagree with
|
|
93
|
+
itself.
|
|
94
|
+
- **All MCP tool input schemas now declare `additionalProperties: false`.**
|
|
95
|
+
Typos like `originPath` (camelCase) or misspelled `log_lin_head` are
|
|
96
|
+
now rejected up-front with a typed validation error instead of silently
|
|
97
|
+
producing a wrong run.
|
|
98
|
+
- **`cancel_session` and `reset_session` output schemas split.** Each
|
|
99
|
+
tool now advertises only the fields it actually returns; the previous
|
|
100
|
+
shared schema overpromised on one side and underpromised on the other.
|
|
101
|
+
- **`list_resources` caps ref-backed entries at 256.** Long-lived
|
|
102
|
+
servers no longer return thousands of stale ref resources from
|
|
103
|
+
forgotten sessions — the most recently used 256 win.
|
|
104
|
+
- **Pystata edition init now preserves the full error trail.** When all
|
|
105
|
+
three editions (MP / SE / BE) fail, the `PystataNotAvailable` message
|
|
106
|
+
lists each attempt's error rather than collapsing to the last one.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- **Jupyter kernel `implementation_version`** is now derived from
|
|
111
|
+
`stata_code.__version__` rather than a separate `0.2.0` literal.
|
|
112
|
+
- **Jupyter kernel mypy `Invalid base class`** error — the dynamic
|
|
113
|
+
`Kernel if _HAS_IPYKERNEL else object` base class confused mypy.
|
|
114
|
+
Hidden behind a `TYPE_CHECKING` gate now; runtime behavior unchanged.
|
|
115
|
+
- **`do_execute` / `do_inspect` signatures** are now LSP-compatible
|
|
116
|
+
with the latest `ipykernel.kernelbase.Kernel` (accepts `cell_meta`,
|
|
117
|
+
`cell_id`, `omit_sections`).
|
|
118
|
+
- **Schema `$id` URL** corrected from `stata_code` to `stata-code`
|
|
119
|
+
(matches the actual GitHub repository name).
|
|
120
|
+
- **VS Code MCP handshake** version is now read from `package.json`
|
|
121
|
+
via `resolveJsonModule`, removing the former fifth sync site.
|
|
122
|
+
`check_versions.py` still validates the literal form
|
|
123
|
+
when present, so reverting to a hardcoded string fails CI.
|
|
124
|
+
- **Release tag glob tightened** — `v[0-9]*.[0-9]*.[0-9]*` instead of
|
|
125
|
+
`v[0-9]*` so stray tags without semver-style dot separators no longer
|
|
126
|
+
trigger the release workflow.
|
|
127
|
+
- **Release pipeline now gates on ruff** so a direct push to `main`
|
|
128
|
+
cannot ship un-linted code.
|
|
129
|
+
- **Mypy CI now covers `stata_code/mcp` and `stata_code/kernel`** in
|
|
130
|
+
addition to `core`, with the optional `mcp` / `kernel` extras
|
|
131
|
+
installed so `Server`, `Tool`, and `Kernel` symbols resolve.
|
|
132
|
+
- **`COMMON_STATA_COMMANDS` deduplicated** — dropped the short forms
|
|
133
|
+
(`cap` / `qui` / `noi` / `mat` / `di`) that were producing
|
|
134
|
+
near-duplicate "did you mean" hits from `difflib`. The long forms
|
|
135
|
+
cover the same fuzzy-match neighbourhood.
|
|
136
|
+
- **`_unique_dir` / `_unique_file`** fall back to a UUID suffix after
|
|
137
|
+
998 collisions instead of raising `FileExistsError`. The original
|
|
138
|
+
behaviour blocked the run on conditions that almost always indicate a
|
|
139
|
+
filesystem issue rather than a name clash.
|
|
140
|
+
- **Dead code removed** — `_info_payload` (orphaned helper) in the MCP
|
|
141
|
+
server, `_truncate` in `notebook.py`, and the unused `index` / `source`
|
|
142
|
+
parameters on `_ensure_native_id`.
|
|
143
|
+
|
|
144
|
+
## 0.6.2 — 2026-05-08
|
|
145
|
+
|
|
146
|
+
Aggregated from the prior `Unreleased` section; covers 0.6.1 and 0.6.2.
|
|
147
|
+
|
|
148
|
+
### Added
|
|
149
|
+
|
|
150
|
+
- **Release version guard.** `scripts/check_versions.py` and the CI /
|
|
151
|
+
release workflows now verify that the Python package, MCP server, VS Code
|
|
152
|
+
package, VS Code MCP handshake, and release tag all use the same version.
|
|
153
|
+
- **VS Code MCP launch tests.** The extension's server-launch candidate
|
|
154
|
+
builder is now a pure tested module covering local `.venv` / `venv`
|
|
155
|
+
discovery, configured Python interpreters, inline command parsing, and
|
|
156
|
+
environment construction.
|
|
157
|
+
- **VS Code packaging smoke test.** The default CI now builds a VSIX artifact
|
|
158
|
+
with the same local `vsce` package command used by release packaging, so
|
|
159
|
+
package-manifest and `.vscodeignore` mistakes fail before release day.
|
|
160
|
+
- **VS Code extension bundling.** The extension now bundles its TypeScript
|
|
161
|
+
entrypoint with `esbuild`, excluding `node_modules` and test/build support
|
|
162
|
+
files from the shipped VSIX.
|
|
163
|
+
- **VS Code bundled dependency notices.** `THIRD_PARTY_NOTICES.md` now lists
|
|
164
|
+
the npm packages included in the bundled extension output and their license
|
|
165
|
+
terms.
|
|
166
|
+
- **PyPI publish verification.** The release workflow now polls PyPI's
|
|
167
|
+
per-version JSON endpoint after the official publish job, so trusted
|
|
168
|
+
publisher failures surface as a failed release run instead of being hidden
|
|
169
|
+
by `continue-on-error`.
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
|
|
173
|
+
- **Package-level Python API is subprocess-backed.** `stata_code.run()`,
|
|
174
|
+
`execute()`, and `is_available()` now go through the same worker pool as
|
|
175
|
+
the MCP server, preserving hard timeout behavior and avoiding caller-process
|
|
176
|
+
stdout redirection by `pystata`.
|
|
177
|
+
- **CI treats core type errors as blocking.** `mypy stata_code/core` is now a
|
|
178
|
+
hard failure, and the default test workflow also compiles and tests the VS
|
|
179
|
+
Code extension.
|
|
180
|
+
- **VS Code npm installs are locked.** The extension now ships
|
|
181
|
+
`package-lock.json`, and CI / release workflows use `npm ci` for reproducible
|
|
182
|
+
dependency installs.
|
|
183
|
+
- **VS Code bundle target matches the extension host floor.** The esbuild
|
|
184
|
+
target is `node18`, keeping the published bundle aligned with the current
|
|
185
|
+
`engines.vscode` lower bound.
|
|
186
|
+
- **Python 3.13 is in the support matrix.** CI now runs the no-Stata test
|
|
187
|
+
suite on Python 3.13, and package metadata advertises the 3.13 classifier.
|
|
188
|
+
|
|
189
|
+
### Fixed
|
|
190
|
+
|
|
191
|
+
- **Cancelled in-flight runs report incomplete logs.** If a live worker is
|
|
192
|
+
killed by `cancel_session`, the synthetic cancelled result now marks
|
|
193
|
+
`log.complete=false`, matching timeout and adapter-crash behavior.
|
|
194
|
+
|
|
9
195
|
## [0.6.0] — 2026-05-08
|
|
10
196
|
|
|
11
197
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stata-code
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
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
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
22
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
24
|
Requires-Python: >=3.10
|
|
@@ -83,7 +84,7 @@ Description-Content-Type: text/markdown
|
|
|
83
84
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
84
85
|
```
|
|
85
86
|
|
|
86
|
-
**Status: v0.6 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP.
|
|
87
|
+
**Status: v0.6 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. The test suite covers schema, runner, MCP, kernel, notebook, run-index, subprocess-pool, and VS Code modules; CI also checks linting, type safety, schema generation, package metadata, and VSIX packaging. License: **MIT**.
|
|
87
88
|
|
|
88
89
|
Two workflows v0.6 explicitly supports for end users:
|
|
89
90
|
|
|
@@ -145,6 +146,10 @@ See [`examples/`](examples/) for end-to-end cookbook entries: basic regression,
|
|
|
145
146
|
|
|
146
147
|
### As a Python Library
|
|
147
148
|
|
|
149
|
+
The package-level `run()` / `execute()` API uses the same subprocess-backed
|
|
150
|
+
runner as the MCP server, so long calls honor `timeout_ms` and `pystata`
|
|
151
|
+
stdout redirection stays isolated from the caller process.
|
|
152
|
+
|
|
148
153
|
```python
|
|
149
154
|
from stata_code import run
|
|
150
155
|
|
|
@@ -199,14 +204,34 @@ If you want the repair loop, say so explicitly. Otherwise, treat failed runs as
|
|
|
199
204
|
If you prefer not to `pip install stata-code` globally, run it ephemerally through [`uv`](https://github.com/astral-sh/uv):
|
|
200
205
|
|
|
201
206
|
```bash
|
|
202
|
-
claude mcp add stata-code --scope user -- uvx --from stata-code stata-code-mcp
|
|
207
|
+
claude mcp add stata-code --scope user -- uvx --from "stata-code[mcp]" stata-code-mcp
|
|
203
208
|
```
|
|
204
209
|
|
|
205
210
|
`uvx` will resolve and cache `stata-code` on first launch. Note: `pystata` is **not** on PyPI, so it still has to be locatable on the host. The runner adds the standard Stata install path (e.g. `/Applications/Stata/utilities/pystata` on macOS) to `sys.path` automatically; if your Stata lives elsewhere, set `PYTHONPATH` in the env block.
|
|
206
211
|
|
|
207
|
-
####
|
|
212
|
+
#### Claude Code via plugin marketplace
|
|
213
|
+
|
|
214
|
+
This repository also ships a Claude Code plugin manifest (`.claude-plugin/`). Once you've added the marketplace to your Claude Code config, two commands wire up both the MCP server and the agent skill that teaches Claude the v1.0 result schema:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
claude plugin marketplace add brycewang-stanford/stata-code
|
|
218
|
+
claude plugin install stata-code
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The plugin registers the `stata-code` MCP server and installs the [`stata-code` skill](skills/stata-code/SKILL.md) so Claude branches on `error.kind`, calls `get_log(ref)` lazily, and uses the notebook-edit tools without you re-explaining them every session.
|
|
222
|
+
|
|
223
|
+
#### Other MCP clients (Cursor / Claude Desktop / Cline / Continue / Windsurf / Antigravity)
|
|
208
224
|
|
|
209
|
-
|
|
225
|
+
Most non-Claude-Code MCP clients accept the same JSON snippet. Drop it into the client's MCP config file:
|
|
226
|
+
|
|
227
|
+
| Client | Config file |
|
|
228
|
+
| --- | --- |
|
|
229
|
+
| Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`; Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
230
|
+
| Cursor | `~/.cursor/mcp.json` (user) or `<workspace>/.cursor/mcp.json` (project) |
|
|
231
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
232
|
+
| Cline (VS Code) | settings: `cline.mcpServers` |
|
|
233
|
+
| Continue | `~/.continue/config.json` under `experimental.modelContextProtocolServers` |
|
|
234
|
+
| Antigravity / generic | `~/.claude/mcp.json` or whatever the client documents |
|
|
210
235
|
|
|
211
236
|
```json
|
|
212
237
|
{
|
|
@@ -218,12 +243,26 @@ For clients without a `mcp add` CLI, edit the config file directly (`~/.claude/m
|
|
|
218
243
|
}
|
|
219
244
|
```
|
|
220
245
|
|
|
221
|
-
Or
|
|
246
|
+
Or, when the binary is not on `PATH`, run it as a module:
|
|
222
247
|
|
|
223
248
|
```bash
|
|
224
249
|
python -m stata_code.mcp
|
|
225
250
|
```
|
|
226
251
|
|
|
252
|
+
When `stata-code-mcp` lives inside a project virtualenv (recommended for reproducibility), point the client at the absolute path:
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
{
|
|
256
|
+
"mcpServers": {
|
|
257
|
+
"stata-code": {
|
|
258
|
+
"command": "/abs/path/to/.venv/bin/stata-code-mcp"
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
For `uvx`-only setups, set `"command": "uvx"` and `"args": ["--from", "stata-code", "stata-code-mcp"]`.
|
|
265
|
+
|
|
227
266
|
The MCP server registers 15 tools:
|
|
228
267
|
|
|
229
268
|
| Tool | Purpose |
|
|
@@ -234,7 +273,7 @@ The MCP server registers 15 tools:
|
|
|
234
273
|
| `get_graph` | Fetch graph bytes behind a `graph://` ref (`ImageContent`) |
|
|
235
274
|
| `get_matrix` | Fetch matrix payloads behind a `matrix://` ref |
|
|
236
275
|
| `list_sessions` | Enumerate live sessions |
|
|
237
|
-
| `cancel_session` |
|
|
276
|
+
| `cancel_session` | Cancel a session; the subprocess-backed path terminates in-flight runs and short-circuits pending ones |
|
|
238
277
|
| `reset_session` | Drop a session's data |
|
|
239
278
|
| `notebook_outline` | Compact per-cell index of a `.ipynb` (cell_id, type, preview) |
|
|
240
279
|
| `notebook_get_cell` | One cell's full source plus a token-economic outputs summary |
|
|
@@ -299,7 +338,20 @@ The companion extension is on the Marketplace as [`brycewang-stanford.stata-code
|
|
|
299
338
|
code --install-extension brycewang-stanford.stata-code-vscode
|
|
300
339
|
```
|
|
301
340
|
|
|
302
|
-
Or open the **Extensions** sidebar in VS Code and search `stata-code`.
|
|
341
|
+
Or open the **Extensions** sidebar in VS Code and search `stata-code`. The extension is also available from [Open VSX](https://open-vsx.org/) so Cursor, Windsurf, and other VS Code-compatible editors can install it without going through the Microsoft Marketplace.
|
|
342
|
+
|
|
343
|
+
On first activation the extension probes for `stata-code-mcp` on `PATH` (and in any workspace `.venv` / `venv`). If nothing resolves, it shows a one-time install hint with the exact `pip install "stata-code[mcp]"` command — choose **Don't show again** to silence it for the installed extension version.
|
|
344
|
+
|
|
345
|
+
#### Cell and section conventions
|
|
346
|
+
|
|
347
|
+
The extension recognizes two complementary structural markers inside `.do` files. Either can be mixed in the same file; they do not conflict.
|
|
348
|
+
|
|
349
|
+
| Marker | Purpose | Example |
|
|
350
|
+
| --- | --- | --- |
|
|
351
|
+
| `* %% [title]` | Cell boundary. Each marker gets a **▶ Run Cell** code-lens; "Run Cell" submits the lines between this marker and the next one. Compatible with the Jupyter-style cell convention used by `kylebutts/vscode-stata`. | `* %% 02 model fit` |
|
|
352
|
+
| `**# title` … `**###### title` | Section heading, 1–6 levels deep. Each heading gets a **▶ Run Section** code-lens and contributes to the Outline view. "Run Section" submits the heading through the next equal- or higher-level heading, matching the hierarchical execution model from `ZihaoVistonWang.stata-all-in-one`. | `**## DiD specification` |
|
|
353
|
+
|
|
354
|
+
`program define … end` blocks are also surfaced in the Outline, nested under whichever section contains them.
|
|
303
355
|
|
|
304
356
|
The extension still requires the MCP extra on your system Python (`pip install "stata-code[mcp]"`), so that `stata-code-mcp` resolves on `PATH` and can import the MCP SDK. Stata 17+ and a valid Stata license are required as for any other frontend.
|
|
305
357
|
|
|
@@ -348,14 +400,15 @@ stata_code/
|
|
|
348
400
|
│ ├── _refs.py # LRU ref store for log/graph/matrix payloads
|
|
349
401
|
│ ├── schema.py # Pydantic v2 models for the v1.0 result schema
|
|
350
402
|
│ ├── errors.py # rc → ErrorKind mapping + suggestion seeds
|
|
351
|
-
│
|
|
403
|
+
│ ├── runner.py # in-process execute(); collects everything via sfi
|
|
404
|
+
│ └── _pool.py # subprocess workers for public API / MCP hard timeouts
|
|
352
405
|
├── mcp/
|
|
353
406
|
│ └── server.py # MCP server (15 tools)
|
|
354
407
|
└── kernel/
|
|
355
408
|
└── kernel.py # Jupyter kernel
|
|
356
409
|
```
|
|
357
410
|
|
|
358
|
-
`runner.py` is the only place that
|
|
411
|
+
`runner.py` is the only place that directly talks to `pystata`. The public Python API and MCP server route calls through `_pool.py`, whose workers call `runner.execute()` in an isolated subprocess; the Jupyter kernel uses the in-process runner for notebook interactivity.
|
|
359
412
|
|
|
360
413
|
---
|
|
361
414
|
|
|
@@ -391,7 +444,7 @@ stata_code/
|
|
|
391
444
|
- MCP server: 15 tools, including notebook navigation / search / atomic edits and the run-bundle index (`list_runs`)
|
|
392
445
|
- Jupyter kernel: rewired to the v1.0 pipeline, kernel logos bundled
|
|
393
446
|
- Matrix size cap + `get_matrix(ref)` for large matrices (>10k cells)
|
|
394
|
-
-
|
|
447
|
+
- Subprocess-backed hard timeout and cancellation for the public Python API and MCP server: `timeout_ms`, `cancel(session_id)`, and MCP `cancel_session`
|
|
395
448
|
- Per-cell repair loop on `.ipynb` via `notebook_outline` / `notebook_get_cell` / `notebook_edit_cell` with optimistic-concurrency `expected_source` guards and `origin_cell_id` echo on `RunResult`
|
|
396
449
|
- Persistent run bundles + `list_runs` query over `manifest.json` files (filter by cell / origin / session / since / ok)
|
|
397
450
|
- JSON Schema artifact auto-generated from `schema.py`: [`schema/run_result.schema.json`](schema/run_result.schema.json)
|
|
@@ -401,8 +454,8 @@ stata_code/
|
|
|
401
454
|
### Next Up
|
|
402
455
|
|
|
403
456
|
- Console fallback for Stata 11–16, re-implemented against the v1.0 schema
|
|
404
|
-
-
|
|
405
|
-
- Extra VS Code polish
|
|
457
|
+
- Decide whether to move the Jupyter kernel from the direct in-process runner to the subprocess pool, or keep documenting the current interactivity-first tradeoff
|
|
458
|
+
- Extra VS Code polish: extension-host end-to-end tests, first-run diagnostics, and command palette UX
|
|
406
459
|
- **v1.0** — Stable schema, broader Stata edition coverage
|
|
407
460
|
|
|
408
461
|
See [SCHEMA.md §7](SCHEMA.md) for explicitly out-of-scope items.
|
|
@@ -413,9 +466,9 @@ See [SCHEMA.md §7](SCHEMA.md) for explicitly out-of-scope items.
|
|
|
413
466
|
|
|
414
467
|
```bash
|
|
415
468
|
pip install -e ".[dev,mcp,kernel]"
|
|
416
|
-
pytest # full suite
|
|
469
|
+
pytest # full suite, including Stata tests when Stata is available
|
|
417
470
|
pytest -m "not stata_required" # CI subset; no Stata needed
|
|
418
|
-
pytest -m "stata_required" -v # Stata
|
|
471
|
+
pytest -m "stata_required" -v # real-Stata integration tests only
|
|
419
472
|
```
|
|
420
473
|
|
|
421
474
|
The `stata_required` marker tags the real-Stata integration tests. CI uses `pytest -m "not stata_required"` so it does not collect them. Locally without Stata, those tests skip cleanly with the `"pystata / Stata 17+ not available"` message.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
# Publishing `stata-code` to PyPI
|
|
1
|
+
# Publishing `stata-code` to TestPyPI and PyPI
|
|
2
2
|
|
|
3
|
-
This project publishes to PyPI via **GitHub Actions Trusted
|
|
4
|
-
There are **no API tokens** stored in GitHub repository
|
|
5
|
-
the OIDC identity of the workflow run
|
|
3
|
+
This project publishes to TestPyPI and PyPI via **GitHub Actions Trusted
|
|
4
|
+
Publishing** (OIDC). There are **no API tokens** stored in GitHub repository
|
|
5
|
+
secrets — each package index verifies the OIDC identity of the workflow run
|
|
6
|
+
instead.
|
|
6
7
|
|
|
7
8
|
The release pipeline is in [`.github/workflows/release.yml`](.github/workflows/release.yml).
|
|
8
9
|
|
|
@@ -28,25 +29,34 @@ Trusted Publishing has two modes:
|
|
|
28
29
|
|
|
29
30
|
Either path lands you in the same place after the first run.
|
|
30
31
|
|
|
31
|
-
### 2. Configure the Trusted
|
|
32
|
+
### 2. Configure the Trusted Publishers
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
PyPI and TestPyPI are separate package indexes, so configure both publisher
|
|
35
|
+
records independently:
|
|
34
36
|
|
|
35
|
-
|
|
|
36
|
-
| --- | --- |
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
| Site | Manage URL | Environment |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| PyPI | <https://pypi.org/manage/project/stata-code/settings/publishing/> | `pypi` |
|
|
40
|
+
| TestPyPI | <https://test.pypi.org/manage/project/stata-code/settings/publishing/> | `testpypi` |
|
|
41
|
+
|
|
42
|
+
Use the same GitHub publisher values on both sites:
|
|
43
|
+
|
|
44
|
+
- Owner: `brycewang-stanford`
|
|
45
|
+
- Repository name: `stata-code`
|
|
46
|
+
- Workflow filename: `release.yml`
|
|
47
|
+
- Environment name: `pypi` or `testpypi`, matching the site above
|
|
41
48
|
|
|
42
49
|
The environment name is **required** and must match the `environment.name`
|
|
43
|
-
declared in `release.yml
|
|
50
|
+
declared in `release.yml`. PyPI / TestPyPI use it as an extra constraint:
|
|
44
51
|
even a malicious workflow change in the repo cannot publish unless it runs
|
|
45
|
-
under
|
|
52
|
+
under the exact environment configured for that index.
|
|
53
|
+
|
|
54
|
+
### 3. Create the GitHub Environments
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
In the GitHub repo: **Settings → Environments → New environment**. Create both:
|
|
48
57
|
|
|
49
|
-
|
|
58
|
+
- `testpypi`
|
|
59
|
+
- `pypi`
|
|
50
60
|
|
|
51
61
|
Recommended hardening (all in the environment settings page):
|
|
52
62
|
|
|
@@ -66,25 +76,38 @@ The environment doesn't need any secrets — Trusted Publishing handles auth.
|
|
|
66
76
|
|
|
67
77
|
Once the one-time setup above is done, every release is just:
|
|
68
78
|
|
|
69
|
-
1. **Bump the version
|
|
70
|
-
|
|
79
|
+
1. **Bump the version everywhere**:
|
|
80
|
+
- `pyproject.toml` → `[project] version`
|
|
81
|
+
- `stata_code/__init__.py` → `__version__`
|
|
82
|
+
- `stata_code/mcp/server.py` → `__version__`
|
|
83
|
+
- `vscode/package.json` → `version`
|
|
84
|
+
- `vscode/package-lock.json` → root package `version`
|
|
85
|
+
2. **Run the version guard** before tagging:
|
|
86
|
+
```bash
|
|
87
|
+
python scripts/check_versions.py
|
|
88
|
+
```
|
|
89
|
+
3. **Update `CHANGELOG.md`**: move the `[Unreleased]` entries under a new
|
|
71
90
|
`## [X.Y.Z] - YYYY-MM-DD` heading, leaving an empty `[Unreleased]` shell
|
|
72
91
|
on top.
|
|
73
|
-
|
|
92
|
+
4. **Commit** the bump:
|
|
74
93
|
```bash
|
|
75
|
-
git add pyproject.toml CHANGELOG.md
|
|
94
|
+
git add pyproject.toml stata_code/__init__.py stata_code/mcp/server.py vscode/package.json vscode/package-lock.json CHANGELOG.md
|
|
76
95
|
git commit -m "release: vX.Y.Z"
|
|
77
96
|
```
|
|
78
|
-
|
|
97
|
+
5. **Tag and push**:
|
|
79
98
|
```bash
|
|
80
99
|
git tag vX.Y.Z
|
|
81
100
|
git push origin main
|
|
82
101
|
git push origin vX.Y.Z
|
|
83
102
|
```
|
|
84
|
-
|
|
103
|
+
6. Watch the **`release` workflow** under the Actions tab. It will:
|
|
85
104
|
- build the sdist + wheel
|
|
86
105
|
- run `twine check` on the artifacts
|
|
106
|
+
- publish to TestPyPI under the `testpypi` environment (no token needed)
|
|
87
107
|
- publish to PyPI under the `pypi` environment (no token needed)
|
|
108
|
+
- poll PyPI's per-version JSON endpoint so a failed trusted-publisher
|
|
109
|
+
publish marks the workflow run failed even though the publish job itself
|
|
110
|
+
is `continue-on-error`
|
|
88
111
|
- create a GitHub Release for the tag with the wheel + sdist attached and
|
|
89
112
|
auto-generated release notes
|
|
90
113
|
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
└─────────────┘ └────────────┘ └─────────────────┘
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
**Status: v0.6 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP.
|
|
48
|
+
**Status: v0.6 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. The test suite covers schema, runner, MCP, kernel, notebook, run-index, subprocess-pool, and VS Code modules; CI also checks linting, type safety, schema generation, package metadata, and VSIX packaging. License: **MIT**.
|
|
49
49
|
|
|
50
50
|
Two workflows v0.6 explicitly supports for end users:
|
|
51
51
|
|
|
@@ -107,6 +107,10 @@ See [`examples/`](examples/) for end-to-end cookbook entries: basic regression,
|
|
|
107
107
|
|
|
108
108
|
### As a Python Library
|
|
109
109
|
|
|
110
|
+
The package-level `run()` / `execute()` API uses the same subprocess-backed
|
|
111
|
+
runner as the MCP server, so long calls honor `timeout_ms` and `pystata`
|
|
112
|
+
stdout redirection stays isolated from the caller process.
|
|
113
|
+
|
|
110
114
|
```python
|
|
111
115
|
from stata_code import run
|
|
112
116
|
|
|
@@ -161,14 +165,34 @@ If you want the repair loop, say so explicitly. Otherwise, treat failed runs as
|
|
|
161
165
|
If you prefer not to `pip install stata-code` globally, run it ephemerally through [`uv`](https://github.com/astral-sh/uv):
|
|
162
166
|
|
|
163
167
|
```bash
|
|
164
|
-
claude mcp add stata-code --scope user -- uvx --from stata-code stata-code-mcp
|
|
168
|
+
claude mcp add stata-code --scope user -- uvx --from "stata-code[mcp]" stata-code-mcp
|
|
165
169
|
```
|
|
166
170
|
|
|
167
171
|
`uvx` will resolve and cache `stata-code` on first launch. Note: `pystata` is **not** on PyPI, so it still has to be locatable on the host. The runner adds the standard Stata install path (e.g. `/Applications/Stata/utilities/pystata` on macOS) to `sys.path` automatically; if your Stata lives elsewhere, set `PYTHONPATH` in the env block.
|
|
168
172
|
|
|
169
|
-
####
|
|
173
|
+
#### Claude Code via plugin marketplace
|
|
174
|
+
|
|
175
|
+
This repository also ships a Claude Code plugin manifest (`.claude-plugin/`). Once you've added the marketplace to your Claude Code config, two commands wire up both the MCP server and the agent skill that teaches Claude the v1.0 result schema:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
claude plugin marketplace add brycewang-stanford/stata-code
|
|
179
|
+
claude plugin install stata-code
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The plugin registers the `stata-code` MCP server and installs the [`stata-code` skill](skills/stata-code/SKILL.md) so Claude branches on `error.kind`, calls `get_log(ref)` lazily, and uses the notebook-edit tools without you re-explaining them every session.
|
|
183
|
+
|
|
184
|
+
#### Other MCP clients (Cursor / Claude Desktop / Cline / Continue / Windsurf / Antigravity)
|
|
170
185
|
|
|
171
|
-
|
|
186
|
+
Most non-Claude-Code MCP clients accept the same JSON snippet. Drop it into the client's MCP config file:
|
|
187
|
+
|
|
188
|
+
| Client | Config file |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`; Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
191
|
+
| Cursor | `~/.cursor/mcp.json` (user) or `<workspace>/.cursor/mcp.json` (project) |
|
|
192
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
193
|
+
| Cline (VS Code) | settings: `cline.mcpServers` |
|
|
194
|
+
| Continue | `~/.continue/config.json` under `experimental.modelContextProtocolServers` |
|
|
195
|
+
| Antigravity / generic | `~/.claude/mcp.json` or whatever the client documents |
|
|
172
196
|
|
|
173
197
|
```json
|
|
174
198
|
{
|
|
@@ -180,12 +204,26 @@ For clients without a `mcp add` CLI, edit the config file directly (`~/.claude/m
|
|
|
180
204
|
}
|
|
181
205
|
```
|
|
182
206
|
|
|
183
|
-
Or
|
|
207
|
+
Or, when the binary is not on `PATH`, run it as a module:
|
|
184
208
|
|
|
185
209
|
```bash
|
|
186
210
|
python -m stata_code.mcp
|
|
187
211
|
```
|
|
188
212
|
|
|
213
|
+
When `stata-code-mcp` lives inside a project virtualenv (recommended for reproducibility), point the client at the absolute path:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"mcpServers": {
|
|
218
|
+
"stata-code": {
|
|
219
|
+
"command": "/abs/path/to/.venv/bin/stata-code-mcp"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
For `uvx`-only setups, set `"command": "uvx"` and `"args": ["--from", "stata-code", "stata-code-mcp"]`.
|
|
226
|
+
|
|
189
227
|
The MCP server registers 15 tools:
|
|
190
228
|
|
|
191
229
|
| Tool | Purpose |
|
|
@@ -196,7 +234,7 @@ The MCP server registers 15 tools:
|
|
|
196
234
|
| `get_graph` | Fetch graph bytes behind a `graph://` ref (`ImageContent`) |
|
|
197
235
|
| `get_matrix` | Fetch matrix payloads behind a `matrix://` ref |
|
|
198
236
|
| `list_sessions` | Enumerate live sessions |
|
|
199
|
-
| `cancel_session` |
|
|
237
|
+
| `cancel_session` | Cancel a session; the subprocess-backed path terminates in-flight runs and short-circuits pending ones |
|
|
200
238
|
| `reset_session` | Drop a session's data |
|
|
201
239
|
| `notebook_outline` | Compact per-cell index of a `.ipynb` (cell_id, type, preview) |
|
|
202
240
|
| `notebook_get_cell` | One cell's full source plus a token-economic outputs summary |
|
|
@@ -261,7 +299,20 @@ The companion extension is on the Marketplace as [`brycewang-stanford.stata-code
|
|
|
261
299
|
code --install-extension brycewang-stanford.stata-code-vscode
|
|
262
300
|
```
|
|
263
301
|
|
|
264
|
-
Or open the **Extensions** sidebar in VS Code and search `stata-code`.
|
|
302
|
+
Or open the **Extensions** sidebar in VS Code and search `stata-code`. The extension is also available from [Open VSX](https://open-vsx.org/) so Cursor, Windsurf, and other VS Code-compatible editors can install it without going through the Microsoft Marketplace.
|
|
303
|
+
|
|
304
|
+
On first activation the extension probes for `stata-code-mcp` on `PATH` (and in any workspace `.venv` / `venv`). If nothing resolves, it shows a one-time install hint with the exact `pip install "stata-code[mcp]"` command — choose **Don't show again** to silence it for the installed extension version.
|
|
305
|
+
|
|
306
|
+
#### Cell and section conventions
|
|
307
|
+
|
|
308
|
+
The extension recognizes two complementary structural markers inside `.do` files. Either can be mixed in the same file; they do not conflict.
|
|
309
|
+
|
|
310
|
+
| Marker | Purpose | Example |
|
|
311
|
+
| --- | --- | --- |
|
|
312
|
+
| `* %% [title]` | Cell boundary. Each marker gets a **▶ Run Cell** code-lens; "Run Cell" submits the lines between this marker and the next one. Compatible with the Jupyter-style cell convention used by `kylebutts/vscode-stata`. | `* %% 02 model fit` |
|
|
313
|
+
| `**# title` … `**###### title` | Section heading, 1–6 levels deep. Each heading gets a **▶ Run Section** code-lens and contributes to the Outline view. "Run Section" submits the heading through the next equal- or higher-level heading, matching the hierarchical execution model from `ZihaoVistonWang.stata-all-in-one`. | `**## DiD specification` |
|
|
314
|
+
|
|
315
|
+
`program define … end` blocks are also surfaced in the Outline, nested under whichever section contains them.
|
|
265
316
|
|
|
266
317
|
The extension still requires the MCP extra on your system Python (`pip install "stata-code[mcp]"`), so that `stata-code-mcp` resolves on `PATH` and can import the MCP SDK. Stata 17+ and a valid Stata license are required as for any other frontend.
|
|
267
318
|
|
|
@@ -310,14 +361,15 @@ stata_code/
|
|
|
310
361
|
│ ├── _refs.py # LRU ref store for log/graph/matrix payloads
|
|
311
362
|
│ ├── schema.py # Pydantic v2 models for the v1.0 result schema
|
|
312
363
|
│ ├── errors.py # rc → ErrorKind mapping + suggestion seeds
|
|
313
|
-
│
|
|
364
|
+
│ ├── runner.py # in-process execute(); collects everything via sfi
|
|
365
|
+
│ └── _pool.py # subprocess workers for public API / MCP hard timeouts
|
|
314
366
|
├── mcp/
|
|
315
367
|
│ └── server.py # MCP server (15 tools)
|
|
316
368
|
└── kernel/
|
|
317
369
|
└── kernel.py # Jupyter kernel
|
|
318
370
|
```
|
|
319
371
|
|
|
320
|
-
`runner.py` is the only place that
|
|
372
|
+
`runner.py` is the only place that directly talks to `pystata`. The public Python API and MCP server route calls through `_pool.py`, whose workers call `runner.execute()` in an isolated subprocess; the Jupyter kernel uses the in-process runner for notebook interactivity.
|
|
321
373
|
|
|
322
374
|
---
|
|
323
375
|
|
|
@@ -353,7 +405,7 @@ stata_code/
|
|
|
353
405
|
- MCP server: 15 tools, including notebook navigation / search / atomic edits and the run-bundle index (`list_runs`)
|
|
354
406
|
- Jupyter kernel: rewired to the v1.0 pipeline, kernel logos bundled
|
|
355
407
|
- Matrix size cap + `get_matrix(ref)` for large matrices (>10k cells)
|
|
356
|
-
-
|
|
408
|
+
- Subprocess-backed hard timeout and cancellation for the public Python API and MCP server: `timeout_ms`, `cancel(session_id)`, and MCP `cancel_session`
|
|
357
409
|
- Per-cell repair loop on `.ipynb` via `notebook_outline` / `notebook_get_cell` / `notebook_edit_cell` with optimistic-concurrency `expected_source` guards and `origin_cell_id` echo on `RunResult`
|
|
358
410
|
- Persistent run bundles + `list_runs` query over `manifest.json` files (filter by cell / origin / session / since / ok)
|
|
359
411
|
- JSON Schema artifact auto-generated from `schema.py`: [`schema/run_result.schema.json`](schema/run_result.schema.json)
|
|
@@ -363,8 +415,8 @@ stata_code/
|
|
|
363
415
|
### Next Up
|
|
364
416
|
|
|
365
417
|
- Console fallback for Stata 11–16, re-implemented against the v1.0 schema
|
|
366
|
-
-
|
|
367
|
-
- Extra VS Code polish
|
|
418
|
+
- Decide whether to move the Jupyter kernel from the direct in-process runner to the subprocess pool, or keep documenting the current interactivity-first tradeoff
|
|
419
|
+
- Extra VS Code polish: extension-host end-to-end tests, first-run diagnostics, and command palette UX
|
|
368
420
|
- **v1.0** — Stable schema, broader Stata edition coverage
|
|
369
421
|
|
|
370
422
|
See [SCHEMA.md §7](SCHEMA.md) for explicitly out-of-scope items.
|
|
@@ -375,9 +427,9 @@ See [SCHEMA.md §7](SCHEMA.md) for explicitly out-of-scope items.
|
|
|
375
427
|
|
|
376
428
|
```bash
|
|
377
429
|
pip install -e ".[dev,mcp,kernel]"
|
|
378
|
-
pytest # full suite
|
|
430
|
+
pytest # full suite, including Stata tests when Stata is available
|
|
379
431
|
pytest -m "not stata_required" # CI subset; no Stata needed
|
|
380
|
-
pytest -m "stata_required" -v # Stata
|
|
432
|
+
pytest -m "stata_required" -v # real-Stata integration tests only
|
|
381
433
|
```
|
|
382
434
|
|
|
383
435
|
The `stata_required` marker tags the real-Stata integration tests. CI uses `pytest -m "not stata_required"` so it does not collect them. Locally without Stata, those tests skip cleanly with the `"pystata / Stata 17+ not available"` message.
|