@adhd/apigen-python-env 0.1.1 → 0.1.3

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## 0.1.3 (2026-07-24)
2
+
3
+ This was a version bump only for apigen-python-env to align it with other projects, there were no code changes.
4
+
5
+ ## 0.1.2 (2026-07-23)
6
+
7
+
8
+ ### 🚀 Features
9
+
10
+ - **release:** nx release independent versioning + verify-dist-load publish gate (Agent 2)
11
+
12
+
13
+ ### 🩹 Fixes
14
+
15
+ - **agent:** update stale @adhd/agent-mcp-budget, agent-mcp-sanitize, agent-mcp-types references + clean tsconfig stale entries
16
+
17
+
18
+ ### ❤️ Thank You
19
+
20
+ - pseudosky
21
+
1
22
  ## 0.1.1 (2026-07-23)
2
23
 
3
24
 
package/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { ensurePythonEnv, resolvePythonPkgDir } from './lib/python-env';
2
2
  export type { IPythonEnv, IEnsurePythonEnvOptions } from './lib/python-env';
3
+ export { runExtractorEmitJson } from './lib/run-extractor';
package/index.js CHANGED
@@ -1,8 +1,10 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("node:fs"),I=require("node:os"),q=require("node:path"),F=require("node:crypto"),h=require("node:child_process");function S(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const r in t)if(r!=="default"){const i=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,i.get?i:{enumerable:!0,get:()=>t[r]})}}return e.default=t,Object.freeze(e)}const n=S(T),E=S(I),o=S(q);function k(t){const e=t??__dirname,r=o.resolve(e,"..","..","..","python");if(n.existsSync(o.join(r,"apigen_python")))return r;let i=e;for(let p=0;p<20;p++){const s=o.join(i,"packages","apigen","python");if(n.existsSync(o.join(s,"apigen_python")))return s;const u=o.dirname(i);if(u===i)break;i=u}return r}const N=["python3.13","python3.12","python3.11","python3"],d=[3,11];function M(t){const e=h.spawnSync(t,["-c",'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")'],{encoding:"utf8",timeout:15e3});if(e.status!==0||!e.stdout)return;const[r,i]=e.stdout.trim().split(".").map(Number);if(!(!Number.isFinite(r)||!Number.isFinite(i)))return[r,i]}function Y(){for(const t of N){const e=M(t);if(e&&(e[0]>d[0]||e[0]===d[0]&&e[1]>=d[1]))return t}throw new Error(`apigen-python-env: no Python >= ${d.join(".")} found on PATH (tried: ${N.join(", ")}). Install Python ${d.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`)}function G(t){return process.platform==="win32"?o.join(t,"Scripts","python.exe"):o.join(t,"bin","python3")}function B(t){const e=n.readFileSync(o.join(t,"pyproject.toml"));return F.createHash("sha256").update(e).digest("hex")}function $(t){try{const e=JSON.parse(n.readFileSync(t,"utf8"));if(typeof e.pyprojectHash=="string"&&Array.isArray(e.extras))return e}catch{}}function V(t,e,r){const i=Date.now()+e;for(;;)try{n.mkdirSync(t,{recursive:!1});break}catch{if(Date.now()>i){try{n.rmdirSync(t)}catch{}continue}h.spawnSync(process.execPath,["-e","setTimeout(()=>{}, 250)"],{timeout:5e3})}try{return r()}finally{try{n.rmdirSync(t)}catch{}}}function J(t={}){const e=k(),r=process.env.APIGEN_PYTHON;if(r){if(!n.existsSync(r))throw new Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${r}`);return{python:r,venvDir:"",pythonPkgDir:e}}const i=[...new Set(t.extras??[])].sort(),p=t.envHome??process.env.APIGEN_PYENV_HOME??o.join(E.homedir(),".adhd","apigen"),s=o.join(p,"pyvenv"),u=o.join(s,".apigen-stamp"),g=B(e),y=G(s),w=()=>{if(!n.existsSync(y))return!1;const c=$(u);return!c||c.pyprojectHash!==g?!1:i.every(f=>c.extras.includes(f))};if(w())return{python:y,venvDir:s,pythonPkgDir:e};n.mkdirSync(p,{recursive:!0});const H=o.join(p,"pyvenv.lock"),D=t.lockTimeoutMs??3e5;return V(H,D,()=>{if(w())return{python:y,venvDir:s,pythonPkgDir:e};const c=$(u),f=[...new Set([...(c==null?void 0:c.extras)??[],...i])].sort();n.rmSync(s,{recursive:!0,force:!0});const j=Y(),v=h.spawnSync(j,["-m","venv",s],{encoding:"utf8",timeout:12e4});if(v.status!==0)throw new Error(`apigen-python-env: "${j} -m venv" failed (exit ${v.status}):
2
- ${v.stderr}`);const P=o.join(e,"build");n.existsSync(P)&&n.rmSync(P,{recursive:!0,force:!0});for(const a of n.readdirSync(e))a.endsWith(".egg-info")&&n.rmSync(o.join(e,a),{recursive:!0,force:!0});const l=n.mkdtempSync(o.join(E.tmpdir(),"apigen-python-wheel-"));try{const a=h.spawnSync(y,["-m","pip","wheel","--no-deps","--wheel-dir",l,e],{encoding:"utf8",timeout:6e5});if(a.status!==0)throw new Error(`apigen-python-env: pip wheel failed (exit ${a.status}):
3
- ${a.stderr}
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const D=require("node:fs"),I=require("node:os"),q=require("node:path"),F=require("node:crypto"),h=require("node:child_process");function P(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const n in t)if(n!=="default"){const o=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,o.get?o:{enumerable:!0,get:()=>t[n]})}}return e.default=t,Object.freeze(e)}const r=P(D),b=P(I),i=P(q);function k(t){const e=t??__dirname,n=i.resolve(e,"..","..","..","python");if(r.existsSync(i.join(n,"apigen_python")))return n;let o=e;for(let u=0;u<20;u++){const c=i.join(o,"packages","apigen","python");if(r.existsSync(i.join(c,"apigen_python")))return c;const a=i.dirname(o);if(a===o)break;o=a}return n}const H=["python3.13","python3.12","python3.11","python3"],m=[3,11];function J(t){const e=h.spawnSync(t,["-c",'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")'],{encoding:"utf8",timeout:15e3});if(e.status!==0||!e.stdout)return;const[n,o]=e.stdout.trim().split(".").map(Number);if(!(!Number.isFinite(n)||!Number.isFinite(o)))return[n,o]}function M(){for(const t of H){const e=J(t);if(e&&(e[0]>m[0]||e[0]===m[0]&&e[1]>=m[1]))return t}throw new Error(`apigen-python-env: no Python >= ${m.join(".")} found on PATH (tried: ${H.join(", ")}). Install Python ${m.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`)}function Y(t){return process.platform==="win32"?i.join(t,"Scripts","python.exe"):i.join(t,"bin","python3")}function G(t){const e=r.readFileSync(i.join(t,"pyproject.toml"));return F.createHash("sha256").update(e).digest("hex")}function O(t){try{const e=JSON.parse(r.readFileSync(t,"utf8"));if(typeof e.pyprojectHash=="string"&&Array.isArray(e.extras))return e}catch{}}function B(t,e,n){const o=Date.now()+e;for(;;)try{r.mkdirSync(t,{recursive:!1});break}catch{if(Date.now()>o){try{r.rmdirSync(t)}catch{}continue}h.spawnSync(process.execPath,["-e","setTimeout(()=>{}, 250)"],{timeout:5e3})}try{return n()}finally{try{r.rmdirSync(t)}catch{}}}function V(t={}){const e=k(),n=process.env.APIGEN_PYTHON;if(n){if(!r.existsSync(n))throw new Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${n}`);return{python:n,venvDir:"",pythonPkgDir:e}}const o=[...new Set(t.extras??[])].sort(),u=t.envHome??process.env.APIGEN_PYENV_HOME??i.join(b.homedir(),".adhd","apigen"),c=i.join(u,"pyvenv"),a=i.join(c,".apigen-stamp"),d=G(e),p=Y(c),l=()=>{if(!r.existsSync(p))return!1;const s=O(a);return!s||s.pyprojectHash!==d?!1:o.every(y=>s.extras.includes(y))};if(l())return{python:p,venvDir:c,pythonPkgDir:e};r.mkdirSync(u,{recursive:!0});const v=i.join(u,"pyvenv.lock"),w=t.lockTimeoutMs??3e5;return B(v,w,()=>{if(l())return{python:p,venvDir:c,pythonPkgDir:e};const s=O(a),y=[...new Set([...(s==null?void 0:s.extras)??[],...o])].sort();r.rmSync(c,{recursive:!0,force:!0});const _=M(),j=h.spawnSync(_,["-m","venv",c],{encoding:"utf8",timeout:12e4});if(j.status!==0)throw new Error(`apigen-python-env: "${_} -m venv" failed (exit ${j.status}):
2
+ ${j.stderr}`);const x=i.join(e,"build");r.existsSync(x)&&r.rmSync(x,{recursive:!0,force:!0});for(const f of r.readdirSync(e))f.endsWith(".egg-info")&&r.rmSync(i.join(e,f),{recursive:!0,force:!0});const S=r.mkdtempSync(i.join(b.tmpdir(),"apigen-python-wheel-"));try{const f=h.spawnSync(p,["-m","pip","wheel","--no-deps","--wheel-dir",S,e],{encoding:"utf8",timeout:6e5});if(f.status!==0)throw new Error(`apigen-python-env: pip wheel failed (exit ${f.status}):
3
+ ${f.stderr}
4
4
  stdout:
5
- ${a.stdout}`);const _=n.readdirSync(l).filter(A=>A.endsWith(".whl"));if(_.length===0)throw new Error("apigen-python-env: pip wheel produced no .whl file");const b=o.join(l,_[0]),x=f.length?`${b}[${f.join(",")}]`:b,m=h.spawnSync(y,["-m","pip","install","--quiet","--disable-pip-version-check",x],{encoding:"utf8",timeout:6e5});if(m.status!==0)throw new Error(`apigen-python-env: pip install "${x}" failed (exit ${m.status}):
6
- ${m.stderr}
5
+ ${f.stdout}`);const E=r.readdirSync(S).filter(A=>A.endsWith(".whl"));if(E.length===0)throw new Error("apigen-python-env: pip wheel produced no .whl file");const $=i.join(S,E[0]),N=y.length?`${$}[${y.join(",")}]`:$,g=h.spawnSync(p,["-m","pip","install","--quiet","--disable-pip-version-check",N],{encoding:"utf8",timeout:6e5});if(g.status!==0)throw new Error(`apigen-python-env: pip install "${N}" failed (exit ${g.status}):
6
+ ${g.stderr}
7
7
  stdout:
8
- ${m.stdout}`)}finally{n.rmSync(l,{recursive:!0,force:!0})}const O={pyprojectHash:g,extras:f};return n.writeFileSync(u,JSON.stringify(O)),{python:y,venvDir:s,pythonPkgDir:e}})}exports.ensurePythonEnv=J;exports.resolvePythonPkgDir=k;
8
+ ${g.stdout}`)}finally{r.rmSync(S,{recursive:!0,force:!0})}const T={pyprojectHash:d,extras:y};return r.writeFileSync(a,JSON.stringify(T)),{python:p,venvDir:c,pythonPkgDir:e}})}function W(t,e,n,o,u){return new Promise((c,a)=>{var v,w;const d=h.spawn(t,["-m","apigen_python.extractor",n,"--namespace",o,"--emit-json"],{cwd:e,env:{...process.env,PYTHONPATH:e},stdio:["ignore","pipe","pipe"]});let p="",l="";(v=d.stdout)==null||v.on("data",s=>{p+=s.toString("utf8")}),(w=d.stderr)==null||w.on("data",s=>{l+=s.toString("utf8")}),d.on("error",a),d.on("exit",s=>{if(s!==0){a(new Error(`${u}: extractor --emit-json exited with code ${s}:
9
+ ${l}`));return}try{c(JSON.parse(p))}catch(y){a(new Error(`${u}: extractor --emit-json produced invalid JSON (${y.message}):
10
+ ${p}`))}})})}exports.ensurePythonEnv=V;exports.resolvePythonPkgDir=k;exports.runExtractorEmitJson=W;
package/index.mjs CHANGED
@@ -1,27 +1,27 @@
1
1
  import * as n from "node:fs";
2
- import * as E from "node:os";
2
+ import * as H from "node:os";
3
3
  import * as r from "node:path";
4
- import { createHash as D } from "node:crypto";
5
- import { spawnSync as d } from "node:child_process";
6
- function I(e) {
4
+ import { createHash as T } from "node:crypto";
5
+ import { spawnSync as l, spawn as I } from "node:child_process";
6
+ function O(e) {
7
7
  const t = e ?? __dirname, o = r.resolve(t, "..", "..", "..", "python");
8
8
  if (n.existsSync(r.join(o, "apigen_python")))
9
9
  return o;
10
10
  let i = t;
11
- for (let a = 0; a < 20; a++) {
12
- const s = r.join(i, "packages", "apigen", "python");
13
- if (n.existsSync(r.join(s, "apigen_python")))
14
- return s;
15
- const u = r.dirname(i);
16
- if (u === i)
11
+ for (let u = 0; u < 20; u++) {
12
+ const c = r.join(i, "packages", "apigen", "python");
13
+ if (n.existsSync(r.join(c, "apigen_python")))
14
+ return c;
15
+ const a = r.dirname(i);
16
+ if (a === i)
17
17
  break;
18
- i = u;
18
+ i = a;
19
19
  }
20
20
  return o;
21
21
  }
22
- const N = ["python3.13", "python3.12", "python3.11", "python3"], h = [3, 11];
23
- function T(e) {
24
- const t = d(e, ["-c", 'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")'], {
22
+ const _ = ["python3.13", "python3.12", "python3.11", "python3"], m = [3, 11];
23
+ function D(e) {
24
+ const t = l(e, ["-c", 'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")'], {
25
25
  encoding: "utf8",
26
26
  timeout: 15e3
27
27
  });
@@ -32,21 +32,21 @@ function T(e) {
32
32
  return [o, i];
33
33
  }
34
34
  function F() {
35
- for (const e of N) {
36
- const t = T(e);
37
- if (t && (t[0] > h[0] || t[0] === h[0] && t[1] >= h[1]))
35
+ for (const e of _) {
36
+ const t = D(e);
37
+ if (t && (t[0] > m[0] || t[0] === m[0] && t[1] >= m[1]))
38
38
  return e;
39
39
  }
40
40
  throw new Error(
41
- `apigen-python-env: no Python >= ${h.join(".")} found on PATH (tried: ${N.join(", ")}). Install Python ${h.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`
41
+ `apigen-python-env: no Python >= ${m.join(".")} found on PATH (tried: ${_.join(", ")}). Install Python ${m.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`
42
42
  );
43
43
  }
44
- function O(e) {
44
+ function Y(e) {
45
45
  return process.platform === "win32" ? r.join(e, "Scripts", "python.exe") : r.join(e, "bin", "python3");
46
46
  }
47
- function Y(e) {
47
+ function J(e) {
48
48
  const t = n.readFileSync(r.join(e, "pyproject.toml"));
49
- return D("sha256").update(t).digest("hex");
49
+ return T("sha256").update(t).digest("hex");
50
50
  }
51
51
  function k(e) {
52
52
  try {
@@ -70,7 +70,7 @@ function G(e, t, o) {
70
70
  }
71
71
  continue;
72
72
  }
73
- d(process.execPath, ["-e", "setTimeout(()=>{}, 250)"], { timeout: 5e3 });
73
+ l(process.execPath, ["-e", "setTimeout(()=>{}, 250)"], { timeout: 5e3 });
74
74
  }
75
75
  try {
76
76
  return o();
@@ -82,74 +82,111 @@ function G(e, t, o) {
82
82
  }
83
83
  }
84
84
  function V(e = {}) {
85
- const t = I(), o = process.env.APIGEN_PYTHON;
85
+ const t = O(), o = process.env.APIGEN_PYTHON;
86
86
  if (o) {
87
87
  if (!n.existsSync(o))
88
88
  throw new Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${o}`);
89
89
  return { python: o, venvDir: "", pythonPkgDir: t };
90
90
  }
91
- const i = [...new Set(e.extras ?? [])].sort(), a = e.envHome ?? process.env.APIGEN_PYENV_HOME ?? r.join(E.homedir(), ".adhd", "apigen"), s = r.join(a, "pyvenv"), u = r.join(s, ".apigen-stamp"), w = Y(t), y = O(s), S = () => {
92
- if (!n.existsSync(y))
91
+ const i = [...new Set(e.extras ?? [])].sort(), u = e.envHome ?? process.env.APIGEN_PYENV_HOME ?? r.join(H.homedir(), ".adhd", "apigen"), c = r.join(u, "pyvenv"), a = r.join(c, ".apigen-stamp"), d = J(t), p = Y(c), h = () => {
92
+ if (!n.existsSync(p))
93
93
  return !1;
94
- const c = k(u);
95
- return !c || c.pyprojectHash !== w ? !1 : i.every((f) => c.extras.includes(f));
94
+ const s = k(a);
95
+ return !s || s.pyprojectHash !== d ? !1 : i.every((f) => s.extras.includes(f));
96
96
  };
97
- if (S())
98
- return { python: y, venvDir: s, pythonPkgDir: t };
99
- n.mkdirSync(a, { recursive: !0 });
100
- const H = r.join(a, "pyvenv.lock"), _ = e.lockTimeoutMs ?? 3e5;
101
- return G(H, _, () => {
102
- if (S())
103
- return { python: y, venvDir: s, pythonPkgDir: t };
104
- const c = k(u), f = [.../* @__PURE__ */ new Set([...(c == null ? void 0 : c.extras) ?? [], ...i])].sort();
105
- n.rmSync(s, { recursive: !0, force: !0 });
106
- const g = F(), v = d(g, ["-m", "venv", s], { encoding: "utf8", timeout: 12e4 });
107
- if (v.status !== 0)
97
+ if (h())
98
+ return { python: p, venvDir: c, pythonPkgDir: t };
99
+ n.mkdirSync(u, { recursive: !0 });
100
+ const v = r.join(u, "pyvenv.lock"), w = e.lockTimeoutMs ?? 3e5;
101
+ return G(v, w, () => {
102
+ if (h())
103
+ return { python: p, venvDir: c, pythonPkgDir: t };
104
+ const s = k(a), f = [.../* @__PURE__ */ new Set([...(s == null ? void 0 : s.extras) ?? [], ...i])].sort();
105
+ n.rmSync(c, { recursive: !0, force: !0 });
106
+ const x = F(), j = l(x, ["-m", "venv", c], { encoding: "utf8", timeout: 12e4 });
107
+ if (j.status !== 0)
108
108
  throw new Error(
109
- `apigen-python-env: "${g} -m venv" failed (exit ${v.status}):
110
- ${v.stderr}`
109
+ `apigen-python-env: "${x} -m venv" failed (exit ${j.status}):
110
+ ${j.stderr}`
111
111
  );
112
- const j = r.join(t, "build");
113
- n.existsSync(j) && n.rmSync(j, { recursive: !0, force: !0 });
114
- for (const p of n.readdirSync(t))
115
- p.endsWith(".egg-info") && n.rmSync(r.join(t, p), { recursive: !0, force: !0 });
116
- const m = n.mkdtempSync(r.join(E.tmpdir(), "apigen-python-wheel-"));
112
+ const $ = r.join(t, "build");
113
+ n.existsSync($) && n.rmSync($, { recursive: !0, force: !0 });
114
+ for (const y of n.readdirSync(t))
115
+ y.endsWith(".egg-info") && n.rmSync(r.join(t, y), { recursive: !0, force: !0 });
116
+ const S = n.mkdtempSync(r.join(H.tmpdir(), "apigen-python-wheel-"));
117
117
  try {
118
- const p = d(
119
- y,
120
- ["-m", "pip", "wheel", "--no-deps", "--wheel-dir", m, t],
118
+ const y = l(
119
+ p,
120
+ ["-m", "pip", "wheel", "--no-deps", "--wheel-dir", S, t],
121
121
  { encoding: "utf8", timeout: 6e5 }
122
122
  );
123
- if (p.status !== 0)
123
+ if (y.status !== 0)
124
124
  throw new Error(
125
- `apigen-python-env: pip wheel failed (exit ${p.status}):
126
- ${p.stderr}
125
+ `apigen-python-env: pip wheel failed (exit ${y.status}):
126
+ ${y.stderr}
127
127
  stdout:
128
- ${p.stdout}`
128
+ ${y.stdout}`
129
129
  );
130
- const P = n.readdirSync(m).filter((A) => A.endsWith(".whl"));
130
+ const P = n.readdirSync(S).filter((b) => b.endsWith(".whl"));
131
131
  if (P.length === 0)
132
132
  throw new Error("apigen-python-env: pip wheel produced no .whl file");
133
- const x = r.join(m, P[0]), $ = f.length ? `${x}[${f.join(",")}]` : x, l = d(
134
- y,
135
- ["-m", "pip", "install", "--quiet", "--disable-pip-version-check", $],
133
+ const E = r.join(S, P[0]), N = f.length ? `${E}[${f.join(",")}]` : E, g = l(
134
+ p,
135
+ ["-m", "pip", "install", "--quiet", "--disable-pip-version-check", N],
136
136
  { encoding: "utf8", timeout: 6e5 }
137
137
  );
138
- if (l.status !== 0)
138
+ if (g.status !== 0)
139
139
  throw new Error(
140
- `apigen-python-env: pip install "${$}" failed (exit ${l.status}):
141
- ${l.stderr}
140
+ `apigen-python-env: pip install "${N}" failed (exit ${g.status}):
141
+ ${g.stderr}
142
142
  stdout:
143
- ${l.stdout}`
143
+ ${g.stdout}`
144
144
  );
145
145
  } finally {
146
- n.rmSync(m, { recursive: !0, force: !0 });
146
+ n.rmSync(S, { recursive: !0, force: !0 });
147
147
  }
148
- const b = { pyprojectHash: w, extras: f };
149
- return n.writeFileSync(u, JSON.stringify(b)), { python: y, venvDir: s, pythonPkgDir: t };
148
+ const A = { pyprojectHash: d, extras: f };
149
+ return n.writeFileSync(a, JSON.stringify(A)), { python: p, venvDir: c, pythonPkgDir: t };
150
+ });
151
+ }
152
+ function q(e, t, o, i, u) {
153
+ return new Promise((c, a) => {
154
+ var v, w;
155
+ const d = I(
156
+ e,
157
+ ["-m", "apigen_python.extractor", o, "--namespace", i, "--emit-json"],
158
+ {
159
+ cwd: t,
160
+ env: { ...process.env, PYTHONPATH: t },
161
+ stdio: ["ignore", "pipe", "pipe"]
162
+ }
163
+ );
164
+ let p = "", h = "";
165
+ (v = d.stdout) == null || v.on("data", (s) => {
166
+ p += s.toString("utf8");
167
+ }), (w = d.stderr) == null || w.on("data", (s) => {
168
+ h += s.toString("utf8");
169
+ }), d.on("error", a), d.on("exit", (s) => {
170
+ if (s !== 0) {
171
+ a(new Error(`${u}: extractor --emit-json exited with code ${s}:
172
+ ${h}`));
173
+ return;
174
+ }
175
+ try {
176
+ c(JSON.parse(p));
177
+ } catch (f) {
178
+ a(
179
+ new Error(
180
+ `${u}: extractor --emit-json produced invalid JSON (${f.message}):
181
+ ${p}`
182
+ )
183
+ );
184
+ }
185
+ });
150
186
  });
151
187
  }
152
188
  export {
153
189
  V as ensurePythonEnv,
154
- I as resolvePythonPkgDir
190
+ O as resolvePythonPkgDir,
191
+ q as runExtractorEmitJson
155
192
  };
@@ -0,0 +1,20 @@
1
+ import { Operation } from '@adhd/apigen-core-client';
2
+
3
+ /**
4
+ * Runs `python -m apigen_python.extractor --emit-json` to completion and
5
+ * parses its stdout into `Operation[]` — phase 1 of the py-flask / py-grpc
6
+ * two-phase spawn (extract-only, then `project()`, then serve). This is a
7
+ * short-lived process: it exits as soon as extraction finishes, well before
8
+ * the actual server process is spawned.
9
+ *
10
+ * @param python - Absolute path (or bare name, e.g. `'python3'`) of the
11
+ * interpreter to spawn.
12
+ * @param pythonPkgDir - Absolute path to `packages/apigen/python` (used as
13
+ * both `cwd` and `PYTHONPATH` for the subprocess).
14
+ * @param modulePath - Absolute path to the `.py` module to extract from.
15
+ * @param namespace - Namespace passed to the extractor's `--namespace` flag.
16
+ * @param label - Short caller identifier (e.g. `'py-flask'`, `'py-grpc'`)
17
+ * prefixed onto error messages so failures are traceable
18
+ * to their caller.
19
+ */
20
+ export declare function runExtractorEmitJson(python: string, pythonPkgDir: string, modulePath: string, namespace: string, label: string): Promise<Operation[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhd/apigen-python-env",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "main": "./index.js",
5
5
  "module": "./index.mjs",
6
6
  "types": "./index.d.ts",
@@ -11,6 +11,9 @@
11
11
  "venv",
12
12
  "provisioning"
13
13
  ],
14
+ "dependencies": {
15
+ "@adhd/apigen-core-client": "^0.1.3"
16
+ },
14
17
  "publishConfig": {
15
18
  "access": "public"
16
19
  }