stata-code 0.6.1__tar.gz → 0.6.3__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.1 → stata_code-0.6.3}/CHANGELOG.md +141 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/PKG-INFO +12 -6
- {stata_code-0.6.1 → stata_code-0.6.3}/README.md +10 -5
- {stata_code-0.6.1 → stata_code-0.6.3}/SCHEMA.md +16 -19
- {stata_code-0.6.1 → stata_code-0.6.3}/pyproject.toml +2 -1
- {stata_code-0.6.1 → stata_code-0.6.3}/schema/run_result.schema.json +1 -1
- stata_code-0.6.3/scripts/check_versions.py +104 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/scripts/export_schema.py +4 -1
- stata_code-0.6.3/stata_code/__init__.py +221 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/_pool.py +197 -36
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/_runtime.py +13 -4
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/errors.py +17 -8
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/log_artifacts.py +20 -2
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/notebook.py +30 -11
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/run_index.py +27 -3
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/runner.py +63 -18
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/kernel/kernel.py +36 -11
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/mcp/server.py +194 -76
- stata_code-0.6.3/tests/conftest.py +51 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_cancel.py +3 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_mcp.py +208 -22
- stata_code-0.6.3/tests/test_mcp_stdio.py +163 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_pool.py +47 -0
- stata_code-0.6.3/tests/test_public_api.py +71 -0
- stata_code-0.6.1/stata_code/__init__.py +0 -102
- {stata_code-0.6.1 → stata_code-0.6.3}/.gitignore +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/LICENSE +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/LICENSE-POLICY.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/PUBLISHING.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/docs/design/hard_timeout.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/examples/01-basic-regression.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/examples/02-did-card-krueger.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/examples/03-graphs.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/examples/04-multi-session.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/examples/05-large-matrix.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/examples/README.md +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/__init__.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/_refs.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/core/schema.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/kernel/__init__.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/kernel/__main__.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/kernel/assets/logo-32x32.png +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/kernel/assets/logo-64x64.png +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/kernel/assets/logo-svg.svg +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/mcp/__init__.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/stata_code/mcp/__main__.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/__init__.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/fixtures/.gitkeep +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_errors.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_kernel.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_log_artifacts.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_notebook.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_notebook_phase2.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_run_index.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_runner.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_runtime_discovery.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_schema.py +0 -0
- {stata_code-0.6.1 → stata_code-0.6.3}/tests/test_schema_artifact.py +0 -0
|
@@ -6,6 +6,147 @@ to semver-major.minor for the result schema (see `SCHEMA.md` §6).
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.6.3 — 2026-05-10
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`RefNotFound` exception** — `get_log` / `get_graph` / `get_matrix` now
|
|
14
|
+
raise a typed `RefNotFound` (subclass of `KeyError`) carrying the bad
|
|
15
|
+
ref and a stable `kind` token (`unknown_log_ref` / `unknown_graph_ref` /
|
|
16
|
+
`unknown_matrix_ref`). MCP dispatch maps it to a typed error response
|
|
17
|
+
without string-parsing.
|
|
18
|
+
- **`NotebookError.kind` / `RunIndexError.kind`** — both classes now
|
|
19
|
+
expose a `kind` property so callers don't have to slice the message
|
|
20
|
+
prefix manually.
|
|
21
|
+
- **`SessionPool.list_session_info_detailed`** — partial-failure-aware
|
|
22
|
+
variant of `list_session_info()` that surfaces per-worker `warnings`
|
|
23
|
+
alongside the aggregated `sessions` list. The MCP `list_sessions`
|
|
24
|
+
tool's output schema now includes the optional `warnings` field.
|
|
25
|
+
- **`list_runs.requested_limit`** — echoes the original requested limit
|
|
26
|
+
when the server clamps it to `_LIMIT_MAX`, so a caller asking for
|
|
27
|
+
`limit=1000` can distinguish "scan was capped at 500 rows" from "the
|
|
28
|
+
manifest dir really has more than 500 rows".
|
|
29
|
+
- **Server capabilities resource now includes prompts.** Reading
|
|
30
|
+
`stata://server/capabilities` returns tools, resource templates, AND
|
|
31
|
+
prompts in a single document — clients no longer need a follow-up
|
|
32
|
+
`list_prompts` round-trip just to enumerate the full surface.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **Test hygiene** — a `tests/conftest.py` snapshot/restores `_refs._store`
|
|
37
|
+
per test and shuts the default subprocess pool down at session end.
|
|
38
|
+
Closes a class of intermittent cross-test failures caused by ref-store
|
|
39
|
+
pollution from earlier MCP / pool tests.
|
|
40
|
+
- **Subprocess cancellation race** — `SessionPool.execute()` now
|
|
41
|
+
re-checks `_cancel_pending` after `_get_or_spawn` so a `request_cancel`
|
|
42
|
+
that lands during worker spawn fires on the in-flight call instead of
|
|
43
|
+
the next one.
|
|
44
|
+
- **`stata_info` edition casing is now consistent** — the top-level
|
|
45
|
+
`edition` field mirrors `stata.edition` (the enum value, e.g. `MP`)
|
|
46
|
+
verbatim. Previously the pool path lowercased it to `mp` while the
|
|
47
|
+
in-process path emitted `MP`, so the same payload could disagree with
|
|
48
|
+
itself.
|
|
49
|
+
- **All MCP tool input schemas now declare `additionalProperties: false`.**
|
|
50
|
+
Typos like `originPath` (camelCase) or misspelled `log_lin_head` are
|
|
51
|
+
now rejected up-front with a typed validation error instead of silently
|
|
52
|
+
producing a wrong run.
|
|
53
|
+
- **`cancel_session` and `reset_session` output schemas split.** Each
|
|
54
|
+
tool now advertises only the fields it actually returns; the previous
|
|
55
|
+
shared schema overpromised on one side and underpromised on the other.
|
|
56
|
+
- **`list_resources` caps ref-backed entries at 256.** Long-lived
|
|
57
|
+
servers no longer return thousands of stale ref resources from
|
|
58
|
+
forgotten sessions — the most recently used 256 win.
|
|
59
|
+
- **Pystata edition init now preserves the full error trail.** When all
|
|
60
|
+
three editions (MP / SE / BE) fail, the `PystataNotAvailable` message
|
|
61
|
+
lists each attempt's error rather than collapsing to the last one.
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- **Jupyter kernel `implementation_version`** is now derived from
|
|
66
|
+
`stata_code.__version__` rather than a separate `0.2.0` literal.
|
|
67
|
+
- **Jupyter kernel mypy `Invalid base class`** error — the dynamic
|
|
68
|
+
`Kernel if _HAS_IPYKERNEL else object` base class confused mypy.
|
|
69
|
+
Hidden behind a `TYPE_CHECKING` gate now; runtime behavior unchanged.
|
|
70
|
+
- **`do_execute` / `do_inspect` signatures** are now LSP-compatible
|
|
71
|
+
with the latest `ipykernel.kernelbase.Kernel` (accepts `cell_meta`,
|
|
72
|
+
`cell_id`, `omit_sections`).
|
|
73
|
+
- **Schema `$id` URL** corrected from `stata_code` to `stata-code`
|
|
74
|
+
(matches the actual GitHub repository name).
|
|
75
|
+
- **VS Code MCP handshake** version is now read from `package.json`
|
|
76
|
+
via `resolveJsonModule`, removing the former fifth sync site.
|
|
77
|
+
`check_versions.py` still validates the literal form
|
|
78
|
+
when present, so reverting to a hardcoded string fails CI.
|
|
79
|
+
- **Release tag glob tightened** — `v[0-9]*.[0-9]*.[0-9]*` instead of
|
|
80
|
+
`v[0-9]*` so stray tags without semver-style dot separators no longer
|
|
81
|
+
trigger the release workflow.
|
|
82
|
+
- **Release pipeline now gates on ruff** so a direct push to `main`
|
|
83
|
+
cannot ship un-linted code.
|
|
84
|
+
- **Mypy CI now covers `stata_code/mcp` and `stata_code/kernel`** in
|
|
85
|
+
addition to `core`, with the optional `mcp` / `kernel` extras
|
|
86
|
+
installed so `Server`, `Tool`, and `Kernel` symbols resolve.
|
|
87
|
+
- **`COMMON_STATA_COMMANDS` deduplicated** — dropped the short forms
|
|
88
|
+
(`cap` / `qui` / `noi` / `mat` / `di`) that were producing
|
|
89
|
+
near-duplicate "did you mean" hits from `difflib`. The long forms
|
|
90
|
+
cover the same fuzzy-match neighbourhood.
|
|
91
|
+
- **`_unique_dir` / `_unique_file`** fall back to a UUID suffix after
|
|
92
|
+
998 collisions instead of raising `FileExistsError`. The original
|
|
93
|
+
behaviour blocked the run on conditions that almost always indicate a
|
|
94
|
+
filesystem issue rather than a name clash.
|
|
95
|
+
- **Dead code removed** — `_info_payload` (orphaned helper) in the MCP
|
|
96
|
+
server, `_truncate` in `notebook.py`, and the unused `index` / `source`
|
|
97
|
+
parameters on `_ensure_native_id`.
|
|
98
|
+
|
|
99
|
+
## 0.6.2 — 2026-05-08
|
|
100
|
+
|
|
101
|
+
Aggregated from the prior `Unreleased` section; covers 0.6.1 and 0.6.2.
|
|
102
|
+
|
|
103
|
+
### Added
|
|
104
|
+
|
|
105
|
+
- **Release version guard.** `scripts/check_versions.py` and the CI /
|
|
106
|
+
release workflows now verify that the Python package, MCP server, VS Code
|
|
107
|
+
package, VS Code MCP handshake, and release tag all use the same version.
|
|
108
|
+
- **VS Code MCP launch tests.** The extension's server-launch candidate
|
|
109
|
+
builder is now a pure tested module covering local `.venv` / `venv`
|
|
110
|
+
discovery, configured Python interpreters, inline command parsing, and
|
|
111
|
+
environment construction.
|
|
112
|
+
- **VS Code packaging smoke test.** The default CI now builds a VSIX artifact
|
|
113
|
+
with the same local `vsce` package command used by release packaging, so
|
|
114
|
+
package-manifest and `.vscodeignore` mistakes fail before release day.
|
|
115
|
+
- **VS Code extension bundling.** The extension now bundles its TypeScript
|
|
116
|
+
entrypoint with `esbuild`, excluding `node_modules` and test/build support
|
|
117
|
+
files from the shipped VSIX.
|
|
118
|
+
- **VS Code bundled dependency notices.** `THIRD_PARTY_NOTICES.md` now lists
|
|
119
|
+
the npm packages included in the bundled extension output and their license
|
|
120
|
+
terms.
|
|
121
|
+
- **PyPI publish verification.** The release workflow now polls PyPI's
|
|
122
|
+
per-version JSON endpoint after the official publish job, so trusted
|
|
123
|
+
publisher failures surface as a failed release run instead of being hidden
|
|
124
|
+
by `continue-on-error`.
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
|
|
128
|
+
- **Package-level Python API is subprocess-backed.** `stata_code.run()`,
|
|
129
|
+
`execute()`, and `is_available()` now go through the same worker pool as
|
|
130
|
+
the MCP server, preserving hard timeout behavior and avoiding caller-process
|
|
131
|
+
stdout redirection by `pystata`.
|
|
132
|
+
- **CI treats core type errors as blocking.** `mypy stata_code/core` is now a
|
|
133
|
+
hard failure, and the default test workflow also compiles and tests the VS
|
|
134
|
+
Code extension.
|
|
135
|
+
- **VS Code npm installs are locked.** The extension now ships
|
|
136
|
+
`package-lock.json`, and CI / release workflows use `npm ci` for reproducible
|
|
137
|
+
dependency installs.
|
|
138
|
+
- **VS Code bundle target matches the extension host floor.** The esbuild
|
|
139
|
+
target is `node18`, keeping the published bundle aligned with the current
|
|
140
|
+
`engines.vscode` lower bound.
|
|
141
|
+
- **Python 3.13 is in the support matrix.** CI now runs the no-Stata test
|
|
142
|
+
suite on Python 3.13, and package metadata advertises the 3.13 classifier.
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- **Cancelled in-flight runs report incomplete logs.** If a live worker is
|
|
147
|
+
killed by `cancel_session`, the synthetic cancelled result now marks
|
|
148
|
+
`log.complete=false`, matching timeout and adapter-crash behavior.
|
|
149
|
+
|
|
9
150
|
## [0.6.0] — 2026-05-08
|
|
10
151
|
|
|
11
152
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stata-code
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
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
|
|
@@ -37,7 +38,7 @@ Requires-Dist: mcp>=1.27; extra == 'mcp'
|
|
|
37
38
|
Description-Content-Type: text/markdown
|
|
38
39
|
|
|
39
40
|
<p align="center">
|
|
40
|
-
<img src="branding/logo/horizontal@1024.png" alt="stata-code logo" width="520" />
|
|
41
|
+
<img src="https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/logo/horizontal@1024.png" alt="stata-code logo" width="520" />
|
|
41
42
|
</p>
|
|
42
43
|
|
|
43
44
|
<p align="center">
|
|
@@ -59,7 +60,7 @@ Description-Content-Type: text/markdown
|
|
|
59
60
|
[](https://github.com/brycewang-stanford/stata-code)
|
|
60
61
|
|
|
61
62
|
<p align="center">
|
|
62
|
-
<img src="branding/github-instructions.png" alt="stata-code: agent-native Stata bridge — one Python core, multiple frontends (Jupyter kernel, MCP server, VS Code extension)" width="720" />
|
|
63
|
+
<img src="https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/github-instructions.png" alt="stata-code: agent-native Stata bridge — one Python core, multiple frontends (Jupyter kernel, MCP server, VS Code extension)" width="720" />
|
|
63
64
|
</p>
|
|
64
65
|
|
|
65
66
|
> Agent-native Stata bridge — **one Python core, multiple frontends**.
|
|
@@ -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. Current test suite:
|
|
87
|
+
**Status: v0.6 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. Current test suite: 329 passing tests across schema, runner, MCP, kernel, notebook, run-index, subprocess-pool, and VS Code modules. 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
|
|
|
@@ -348,14 +353,15 @@ stata_code/
|
|
|
348
353
|
│ ├── _refs.py # LRU ref store for log/graph/matrix payloads
|
|
349
354
|
│ ├── schema.py # Pydantic v2 models for the v1.0 result schema
|
|
350
355
|
│ ├── errors.py # rc → ErrorKind mapping + suggestion seeds
|
|
351
|
-
│
|
|
356
|
+
│ ├── runner.py # in-process execute(); collects everything via sfi
|
|
357
|
+
│ └── _pool.py # subprocess workers for public API / MCP hard timeouts
|
|
352
358
|
├── mcp/
|
|
353
359
|
│ └── server.py # MCP server (15 tools)
|
|
354
360
|
└── kernel/
|
|
355
361
|
└── kernel.py # Jupyter kernel
|
|
356
362
|
```
|
|
357
363
|
|
|
358
|
-
`runner.py` is the only place that
|
|
364
|
+
`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
365
|
|
|
360
366
|
---
|
|
361
367
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="branding/logo/horizontal@1024.png" alt="stata-code logo" width="520" />
|
|
2
|
+
<img src="https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/logo/horizontal@1024.png" alt="stata-code logo" width="520" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
[](https://github.com/brycewang-stanford/stata-code)
|
|
22
22
|
|
|
23
23
|
<p align="center">
|
|
24
|
-
<img src="branding/github-instructions.png" alt="stata-code: agent-native Stata bridge — one Python core, multiple frontends (Jupyter kernel, MCP server, VS Code extension)" width="720" />
|
|
24
|
+
<img src="https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/github-instructions.png" alt="stata-code: agent-native Stata bridge — one Python core, multiple frontends (Jupyter kernel, MCP server, VS Code extension)" width="720" />
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
27
|
> Agent-native Stata bridge — **one Python core, multiple frontends**.
|
|
@@ -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. Current test suite:
|
|
48
|
+
**Status: v0.6 (May 2026)** — the core, MCP server, Jupyter kernel, and VS Code extension work end-to-end against Stata 18 MP. Current test suite: 329 passing tests across schema, runner, MCP, kernel, notebook, run-index, subprocess-pool, and VS Code modules. 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
|
|
|
@@ -310,14 +314,15 @@ stata_code/
|
|
|
310
314
|
│ ├── _refs.py # LRU ref store for log/graph/matrix payloads
|
|
311
315
|
│ ├── schema.py # Pydantic v2 models for the v1.0 result schema
|
|
312
316
|
│ ├── errors.py # rc → ErrorKind mapping + suggestion seeds
|
|
313
|
-
│
|
|
317
|
+
│ ├── runner.py # in-process execute(); collects everything via sfi
|
|
318
|
+
│ └── _pool.py # subprocess workers for public API / MCP hard timeouts
|
|
314
319
|
├── mcp/
|
|
315
320
|
│ └── server.py # MCP server (15 tools)
|
|
316
321
|
└── kernel/
|
|
317
322
|
└── kernel.py # Jupyter kernel
|
|
318
323
|
```
|
|
319
324
|
|
|
320
|
-
`runner.py` is the only place that
|
|
325
|
+
`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
326
|
|
|
322
327
|
---
|
|
323
328
|
|
|
@@ -580,7 +580,6 @@ When v2 ships, v1 is supported by frontends for at least 6 months. Servers MAY e
|
|
|
580
580
|
Explicitly *not* in this version, to keep the surface small:
|
|
581
581
|
|
|
582
582
|
- **Streaming logs.** All output is batched at end-of-call. `log.complete: false` is reserved for this in v2. Streams (Stata vs Python vs Mata) may be separated under a future `log.streams` field.
|
|
583
|
-
- **Hard timeout enforcement / mid-Stata interrupt.** `cancel(session_id)` is implemented as a *cooperative* signal that short-circuits the next `execute()` call before pystata is invoked; it does not interrupt code that is already mid-`stata.run()`. Hard interruption requires a subprocess-based runtime (post-v0.2).
|
|
584
583
|
- **Distributed / remote sessions.** Sessions are per-process. `session_id` reserves `:` for future host-prefixing.
|
|
585
584
|
- **Authentication / authorization.** Local trusted environment is assumed.
|
|
586
585
|
- **Mata internals.** Mata code runs (`stata.run("mata: ...")`) but Mata-specific return values aren't surfaced beyond what `r()` carries.
|
|
@@ -596,7 +595,7 @@ Explicitly *not* in this version, to keep the surface small:
|
|
|
596
595
|
This section tracks how much of the schema is wired up in code. Not normative
|
|
597
596
|
— the contract above is the contract — but useful as a release checklist.
|
|
598
597
|
|
|
599
|
-
### Implemented
|
|
598
|
+
### Implemented through v0.6 (2026-05)
|
|
600
599
|
|
|
601
600
|
- Log `head` / `tail` / `truncated` / `complete` / `error_window` / `ref`
|
|
602
601
|
with an in-memory ref store backing `get_log`.
|
|
@@ -634,23 +633,21 @@ This section tracks how much of the schema is wired up in code. Not normative
|
|
|
634
633
|
- LRU eviction on the ref store (default cap 256) keeps long-running
|
|
635
634
|
producers from growing unboundedly.
|
|
636
635
|
|
|
637
|
-
- **
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
`
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
constraints, options considered, and an effort estimate are
|
|
653
|
-
written up in [`docs/design/hard_timeout.md`](docs/design/hard_timeout.md).
|
|
636
|
+
- **Subprocess-backed hard timeout and cancellation** via the public
|
|
637
|
+
package API, MCP `stata_run`, and the subprocess session pool.
|
|
638
|
+
`timeout_ms` returns `ok=false`, `rc=-2`, `error.kind="timeout"`
|
|
639
|
+
after terminating the worker. `cancel(session_id)` /
|
|
640
|
+
`clear_cancel(session_id)` / `is_cancel_pending(session_id)` and
|
|
641
|
+
MCP `cancel_session` return `ok=false`, `rc=-3`,
|
|
642
|
+
`error.kind="cancelled"`; an in-flight pool worker is terminated and a
|
|
643
|
+
not-yet-started run is short-circuited before Stata receives code.
|
|
644
|
+
|
|
645
|
+
### Still deferred
|
|
646
|
+
|
|
647
|
+
- **In-process hard timeout.** `stata_code.core.runner.execute()` still
|
|
648
|
+
runs inside the caller process and cannot preempt code already inside
|
|
649
|
+
`pystata`. Use the package-level `stata_code.run()` / `execute()` or
|
|
650
|
+
MCP server for subprocess-backed timeouts and cancellation.
|
|
654
651
|
- **Console fallback for Stata 11–16.** Earlier scaffold's
|
|
655
652
|
`ConsoleFallback` was deleted in v0.2 (it produced legacy
|
|
656
653
|
`StataResult` and didn't fit the new pipeline). v0.3 will reintroduce
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "stata-code"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.3"
|
|
8
8
|
description = "Agent-native Stata bridge — one core, multiple frontends (MCP, Jupyter, VSCode)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -21,6 +21,7 @@ classifiers = [
|
|
|
21
21
|
"Programming Language :: Python :: 3.10",
|
|
22
22
|
"Programming Language :: Python :: 3.11",
|
|
23
23
|
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
24
25
|
"Topic :: Scientific/Engineering :: Mathematics",
|
|
25
26
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
27
|
]
|
|
@@ -802,7 +802,7 @@
|
|
|
802
802
|
"type": "object"
|
|
803
803
|
}
|
|
804
804
|
},
|
|
805
|
-
"$id": "https://
|
|
805
|
+
"$id": "https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/schema/run_result.schema.json",
|
|
806
806
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
807
807
|
"additionalProperties": true,
|
|
808
808
|
"description": "Machine-readable JSON Schema for the v1.0 result envelope returned by stata_code.run(). The normative contract is SCHEMA.md; this file is auto-generated from stata_code.core.schema.RunResult and kept in sync by tests/test_schema_artifact.py.",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Verify that every release version literal is aligned."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _read(rel: str) -> str:
|
|
16
|
+
return ROOT.joinpath(rel).read_text(encoding="utf-8")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _extract(rel: str, pattern: str) -> str:
|
|
20
|
+
match = re.search(pattern, _read(rel), re.MULTILINE)
|
|
21
|
+
if match is None:
|
|
22
|
+
raise RuntimeError(f"could not find version in {rel}")
|
|
23
|
+
return match.group(1)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _tag_version(tag: str) -> str:
|
|
27
|
+
for prefix in ("vscode-v", "v"):
|
|
28
|
+
if tag.startswith(prefix):
|
|
29
|
+
return tag[len(prefix):]
|
|
30
|
+
raise RuntimeError(f"tag must start with v or vscode-v, got {tag!r}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main() -> int:
|
|
34
|
+
parser = argparse.ArgumentParser(
|
|
35
|
+
description="Check pyproject/Python/MCP/VS Code version literals."
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--tag",
|
|
39
|
+
help="Optional Git tag to compare against, e.g. vX.Y.Z or vscode-vX.Y.Z.",
|
|
40
|
+
)
|
|
41
|
+
args = parser.parse_args()
|
|
42
|
+
|
|
43
|
+
versions = {
|
|
44
|
+
"pyproject.toml": _extract(
|
|
45
|
+
"pyproject.toml", r'(?m)^\s*version\s*=\s*"([^"]+)"'
|
|
46
|
+
),
|
|
47
|
+
"stata_code/__init__.py": _extract(
|
|
48
|
+
"stata_code/__init__.py", r'(?m)^__version__\s*=\s*"([^"]+)"'
|
|
49
|
+
),
|
|
50
|
+
"stata_code/mcp/server.py": _extract(
|
|
51
|
+
"stata_code/mcp/server.py", r'(?m)^__version__\s*=\s*"([^"]+)"'
|
|
52
|
+
),
|
|
53
|
+
"vscode/package.json": json.loads(_read("vscode/package.json"))["version"],
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# mcpClient.ts used to carry a literal version; we now resolve it at
|
|
57
|
+
# build time via ``import { version } from "../package.json"``. If the
|
|
58
|
+
# import is present, there is no separate sync site. If someone later
|
|
59
|
+
# reverts to a literal, parse it back so the alignment check still
|
|
60
|
+
# catches drift.
|
|
61
|
+
#
|
|
62
|
+
# KNOWN LIMITATION: when the import is present this script does NOT
|
|
63
|
+
# also scan the file for a stray hardcoded literal alongside the
|
|
64
|
+
# import (e.g. a merge-conflict artifact). The check is import-OR-
|
|
65
|
+
# literal, not import-AND-no-stray-literal. The Python sync sites
|
|
66
|
+
# don't have that escape hatch — they're always literal-checked.
|
|
67
|
+
# If this asymmetry ever causes a bad release, tighten by failing
|
|
68
|
+
# whenever BOTH the import and a literal handshake string co-exist.
|
|
69
|
+
mcp_client_src = _read("vscode/src/mcpClient.ts")
|
|
70
|
+
if 'from "../package.json"' not in mcp_client_src:
|
|
71
|
+
match = re.search(
|
|
72
|
+
r'\{\s*name:\s*"stata-code-vscode",\s*version:\s*"([^"]+)"\s*\}',
|
|
73
|
+
mcp_client_src,
|
|
74
|
+
)
|
|
75
|
+
if match is None:
|
|
76
|
+
raise RuntimeError(
|
|
77
|
+
"vscode/src/mcpClient.ts no longer imports the version from "
|
|
78
|
+
"../package.json AND does not declare a literal — restore "
|
|
79
|
+
"either form."
|
|
80
|
+
)
|
|
81
|
+
versions["vscode/src/mcpClient.ts"] = match.group(1)
|
|
82
|
+
|
|
83
|
+
unique = sorted(set(versions.values()))
|
|
84
|
+
ok = len(unique) == 1
|
|
85
|
+
expected = unique[0] if ok else None
|
|
86
|
+
|
|
87
|
+
if args.tag:
|
|
88
|
+
tag_version = _tag_version(args.tag)
|
|
89
|
+
if expected != tag_version:
|
|
90
|
+
ok = False
|
|
91
|
+
versions[f"tag:{args.tag}"] = tag_version
|
|
92
|
+
|
|
93
|
+
if ok:
|
|
94
|
+
print(f"ok: all release versions are {expected}")
|
|
95
|
+
return 0
|
|
96
|
+
|
|
97
|
+
print("version mismatch:", file=sys.stderr)
|
|
98
|
+
for source, version in versions.items():
|
|
99
|
+
print(f" {source}: {version}", file=sys.stderr)
|
|
100
|
+
return 1
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
raise SystemExit(main())
|
|
@@ -31,7 +31,10 @@ def build_schema() -> dict:
|
|
|
31
31
|
schema = RunResult.model_json_schema()
|
|
32
32
|
# Stable, human-friendly framing for downstream consumers.
|
|
33
33
|
schema["$schema"] = "https://json-schema.org/draft/2020-12/schema"
|
|
34
|
-
schema["$id"] =
|
|
34
|
+
schema["$id"] = (
|
|
35
|
+
"https://raw.githubusercontent.com/brycewang-stanford/stata-code/"
|
|
36
|
+
"main/schema/run_result.schema.json"
|
|
37
|
+
)
|
|
35
38
|
schema["title"] = "stata_code RunResult (v1.0)"
|
|
36
39
|
schema["description"] = (
|
|
37
40
|
"Machine-readable JSON Schema for the v1.0 result envelope returned by "
|