@voiden/runner 2.3.0-beta.13 → 2.3.0-beta.15
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 +33 -0
- package/bundled-runners/simple-assertions-runner.js +1 -1
- package/bundled-runners/versions.json +8 -8
- package/dist/envFile.d.ts +26 -0
- package/dist/envFile.d.ts.map +1 -1
- package/dist/envFile.js +81 -1
- package/dist/envFile.js.map +1 -1
- package/dist/envProfiles.d.ts +29 -0
- package/dist/envProfiles.d.ts.map +1 -0
- package/dist/envProfiles.js +151 -0
- package/dist/envProfiles.js.map +1 -0
- package/dist/index.js +33 -6
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/mcpServing.d.ts +17 -5
- package/dist/mcpServing.d.ts.map +1 -1
- package/dist/mcpServing.js +41 -6
- package/dist/mcpServing.js.map +1 -1
- package/dist/plugins/electronAppState.d.ts +24 -0
- package/dist/plugins/electronAppState.d.ts.map +1 -0
- package/dist/plugins/electronAppState.js +67 -0
- package/dist/plugins/electronAppState.js.map +1 -0
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +13 -1
- package/dist/plugins/loader.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
3
3
|
All notable changes to `@voiden/runner` are documented here. This package is
|
|
4
4
|
versioned and released independently of the Voiden desktop app.
|
|
5
5
|
|
|
6
|
+
## v2.3.0-beta.15 - 2026-09-07
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- Two new fixed MCP tools, alongside the existing `list_void_files`/`list_requests`/`run_request`/
|
|
10
|
+
`write_result` — `list_environments` and `select_environment` (`mcpServing.ts`, exposed by
|
|
11
|
+
`voiden-runner mcp serve`/`mcp install`; `@voiden/mcp` is unaffected, see below). `list_environments`
|
|
12
|
+
discovers every env profile in the project (`.voiden/env-{profile}-public/private.yaml`, or the
|
|
13
|
+
`default` profile's unsuffixed files) and, for each, either its YAML environment hierarchy as
|
|
14
|
+
dotted paths (e.g. `"staging"`, `"staging.eu"` for a nested child) or — if that profile has no YAML
|
|
15
|
+
environments — the plain `.env*` file(s) it falls back to. `select_environment` resolves a chosen
|
|
16
|
+
profile (+ optional dotted environment path within it) and makes its variables the default base
|
|
17
|
+
layer for every `run_request` call for the rest of the session; an explicit `envFile`/`envVars` on
|
|
18
|
+
a given `run_request` call still overrides it for that call only. Returns variable *keys* only, not
|
|
19
|
+
values — `env-*-private.yaml` can hold real secrets, and echoing them into a tool-call response
|
|
20
|
+
that likely ends up in the calling agent's own transcript is an avoidable exposure `run_request`'s
|
|
21
|
+
existing `envVars` param doesn't already create.
|
|
22
|
+
- `envFile.ts`: exported `parseYamlEnv`, added and exported `listYamlEnvironmentNames` (full nested
|
|
23
|
+
environment tree as dotted paths) and `findEnvironmentByPath` (resolves a tree by exact dotted
|
|
24
|
+
path rather than searching for a bare key anywhere — needed because two different parents can each
|
|
25
|
+
have a same-named child, e.g. `staging.eu` vs `prod.eu`; only a full-path walk tells them apart).
|
|
26
|
+
- New `envProfiles.ts` — headless profile discovery/resolution (no Electron dependency), a
|
|
27
|
+
deliberately simplified port of `apps/electron/src/main/env.ts`'s profile logic, same precedent as
|
|
28
|
+
`plugins/voiden-mcp-tool/src/lib/toolCapability.ts`'s `loadProjectEnvironmentVars`.
|
|
29
|
+
- Note: `@voiden/mcp` does not call `registerFixedTools` at all today (a pre-existing gap, not
|
|
30
|
+
changed by this release) — none of the 6 fixed tools, old or new, currently reach connections made
|
|
31
|
+
through that package, only `voiden-runner mcp serve`/`mcp install`.
|
|
32
|
+
|
|
33
|
+
## v2.3.0-beta.14 - 2026-08-26
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- `plugin list`'s core-plugin status badge now checks whether a `runner.js` actually exists (bundled in this package install, or cached in `~/.voiden/extensions/<id>/runner.js`), not just whether the plugin is enabled in `~/.voiden/plugins.json`. Previously it could report "✓ enabled" for a plugin with no usable runner anywhere — exactly the state `loadEnabledPlugins()` treats as unavailable at request-run time (`activePlugins: []`, "not installed" errors from `run_request`) — so the two disagreed with no way to tell why. Now shows "not installed [no runner]" in that case, matching what actually gets loaded.
|
|
37
|
+
- A `linkedBlock`/`linkedFile` pointer node could get resolved as if it *were* the target content instead of the real block it points to, when its own `uid` collided with the `blockUid` being searched for (e.g. a hand-authored file that copied a block's `uid` onto the wrapper instead of generating a fresh one, most likely when linking a block into the same file it lives in). `resolveLinkedBlocks`/`resolveLinkedFiles` now exclude `linkedBlock`/`linkedFile` nodes from ever matching as resolved content — a colliding `uid` now resolves to the real block if one still carries it, or is left unresolved, instead of silently substituting the pointer itself. `@voiden/executors` bumped to `0.1.9`.
|
|
38
|
+
|
|
6
39
|
## v2.3.0-beta.13 - 2026-08-21
|
|
7
40
|
|
|
8
41
|
### Fixed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var y=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var A=(r,e)=>()=>(r&&(e=r(r=0)),e);var w=(r,e)=>{for(var t in e)y(r,t,{get:e[t],enumerable:!0})},D=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of R(e))!T.call(r,s)&&s!==t&&y(r,s,{get:()=>e[s],enumerable:!(n=C(e,s))||n.enumerable});return r};var
|
|
1
|
+
"use strict";var y=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var A=(r,e)=>()=>(r&&(e=r(r=0)),e);var w=(r,e)=>{for(var t in e)y(r,t,{get:e[t],enumerable:!0})},D=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of R(e))!T.call(r,s)&&s!==t&&y(r,s,{get:()=>e[s],enumerable:!(n=C(e,s))||n.enumerable});return r};var W=r=>D(y({},"__esModule",{value:!0}),r);function v(r,e){let t=r.trim();if(t==="status"||t==="statusCode")return e.response.status;if(t==="statusText")return e.response.statusText;if(t==="responseTime"||t==="duration")return e.response.timing?.duration||0;if(t.startsWith("requestHeader.")||t.startsWith("requestHeaders.")){let s=t.split(".")[1];return e.request?.headers.find(i=>i.key.toLowerCase()===s.toLowerCase())?.value}if(t.startsWith("header.")||t.startsWith("headers.")){let n=t.split("."),s=n[1];if(s.toLowerCase()==="set-cookie"){let i=(0,x.parseCookies)(e.response.headers);if(n.length===2)return i;let c=n.slice(2).join(".");return l(i,c)}return e.response.headers.find(i=>i.key.toLowerCase()===s.toLowerCase())?.value}if(t==="body"||t==="response.body")return e.response.body;if(t.startsWith("body.")||t.startsWith("response.body.")){let n=t.replace(/^(response\.)?body\./,"");return l(e.response.body,n)}if(t.startsWith("response.")){let n=t.replace(/^response\./,"");return l(e.response,n)}return l(e.response.body,t)}function l(r,e){if(!r)return;let t=e.split(/\.|\[/).map(s=>s.replace(/\]$/,"")),n=r;for(let s of t){if(n==null)return;/^\d+$/.test(s)?n=n[parseInt(s,10)]:n=n[s]}return n}function E(r,e){try{if(r.enabled===!1)return{assertion:r,passed:!0,actualValue:null,error:"Skipped (disabled)"};let t=F(r.field),n=t.field,s=t.operator||r.operator||"equals",o=r.expectedValue,i=v(n,e),c=L(s,i,o);return{assertion:r,passed:c,actualValue:i}}catch(t){return{assertion:r,passed:!1,actualValue:null,error:t.message||String(t)}}}function F(r){let e=["equals","eq","==","===","not-equals","ne","!=","!==","contains","includes","not-contains","not-includes","starts-with","startswith","ends-with","endswith","matches","regex","exists","is-defined","not-exists","is-null","is-undefined","greater-than","gt",">","less-than","lt","<","greater-equal","gte",">=","less-equal","lte","<=","is-empty","empty","not-empty","is-truthy","truthy","is-falsy","falsy","type-is","typeof"],t=r.trim().split(/\s+/);if(t.length>=2){let n=t[t.length-1].toLowerCase();if(e.includes(n))return{field:t.slice(0,-1).join(" "),operator:n}}return{field:r.trim(),operator:null}}function L(r,e,t){switch(r.toLowerCase().trim()){case"equals":case"eq":case"==":case"===":return e==null?!1:String(e)===t;case"not-equals":case"ne":case"!=":case"!==":return e==null?!1:String(e)!==t;case"contains":case"includes":return e==null?!1:String(e).includes(t);case"not-contains":case"not-includes":return e==null?!1:!String(e).includes(t);case"starts-with":case"startswith":return e==null?!1:String(e).startsWith(t);case"ends-with":case"endswith":return e==null?!1:String(e).endsWith(t);case"matches":case"regex":if(e==null)return!1;try{return new RegExp(t).test(String(e))}catch{return!1}case"exists":case"is-defined":return e!=null;case"not-exists":case"is-null":case"is-undefined":return e==null;case"greater-than":case"gt":case">":{let s=Number(e),o=Number(t);return!isNaN(s)&&!isNaN(o)&&s>o}case"less-than":case"lt":case"<":{let s=Number(e),o=Number(t);return!isNaN(s)&&!isNaN(o)&&s<o}case"greater-equal":case"gte":case">=":{let s=Number(e),o=Number(t);return!isNaN(s)&&!isNaN(o)&&s>=o}case"less-equal":case"lte":case"<=":{let s=Number(e),o=Number(t);return!isNaN(s)&&!isNaN(o)&&s<=o}case"is-empty":case"empty":return e==null?!1:Array.isArray(e)?e.length===0:typeof e=="string"?e==="":typeof e=="object"?Object.keys(e).length===0:!1;case"not-empty":return e==null?!1:Array.isArray(e)?e.length>0:typeof e=="string"?e!=="":typeof e=="object"?Object.keys(e).length>0:!0;case"is-truthy":case"truthy":return!!e;case"is-falsy":case"falsy":return!e;case"type-is":case"typeof":return typeof e===t.toLowerCase();default:throw new Error(`Unknown operator: ${r}`)}}function S(r,e){return r.map(t=>E(t,e))}var x,q=A(()=>{"use strict";x=require("@voiden/sdk/shared")});var N={};w(N,{postProcessAssertionsHook:()=>P});function O(r){let e=[];if(!r||!r.content)return e;function t(n){if(n.type==="assertions-table"){let s=j(n);e.push(...s)}n.content&&Array.isArray(n.content)&&n.content.forEach(s=>t(s))}return t(r),e}function j(r){let e=[];try{if(r.attrs&&Array.isArray(r.attrs.rows)){let s=r.attrs.rows;for(let o of s)!o.description&&!o.field&&!o.operator&&!o.expectedValue||o.enabled!==!1&&e.push({description:o.description||"",field:o.field||"",operator:o.operator||"equals",expectedValue:o.expectedValue||"",enabled:!0});return e}let t=Array.isArray(r.content)?r.content.find(s=>s.type==="table"||s.type==="assertions-table"):null;if(!t)return e;let n=t.rows||t.content||[];for(let s=0;s<n.length;s++){let o=n[s];if(Array.isArray(o.row)){if(o.attrs?.disabled===!0)continue;let[a,h,g,b]=o.row;if(!a&&!h&&!g&&!b)continue;e.push({description:String(a||"").trim(),field:String(h||"").trim(),operator:String(g||"equals").trim()||"equals",expectedValue:String(b||"").trim(),enabled:!0});continue}if(o.type!=="tableRow"||o.attrs&&o.attrs.disabled===!0)continue;let i=o.content||[];if(i.length<4)continue;let c=f(i[0]).trim(),p=f(i[1]).trim(),d=f(i[2]).trim(),u=f(i[3]).trim();!c&&!p&&!d&&!u||!(!(i.length>=5)||H(i[4]))||e.push({description:c,field:p,operator:d||"equals",expectedValue:u,enabled:!0})}}catch(t){console.error("Error extracting assertions from table:",t)}return e}function f(r){return r?r.type==="text"?r.text||"":r.content&&Array.isArray(r.content)?r.content.map(e=>f(e)).join(""):"":""}function H(r){if(!r||!r.content)return!0;let e=r.content.find(t=>t.type==="checkbox");return e&&e.attrs?e.attrs.checked!==!1:!0}async function P(r){let{requestState:e,responseState:t,metadata:n}=r;try{let s=e?.metadata?.editorDocument||n?.requestDocument||n?.editorDocument;if(!s)return;let o=O(s);if(o.length===0)return;let i=(typeof window<"u"?window:void 0)?.electron?.env?.replaceVariables;if(i)for(let a of o)a.expectedValue&&a.expectedValue.includes("{{")&&(a.expectedValue=await i(a.expectedValue)),a.field&&a.field.includes("{{")&&(a.field=await i(a.field));let c=t.body;if(typeof c=="string"&&c.trim())try{c=JSON.parse(c)}catch{}let p={response:{status:t.status,statusText:t.statusText,headers:t.headers||[],body:c,contentType:t.contentType,timing:t.timing},request:{headers:t.requestMeta?.headers||[]}},d=S(o,p),u=d.filter(a=>a.passed).length,m=d.filter(a=>!a.passed).length;t.metadata||(t.metadata={}),t.metadata.assertionResults={results:d,totalAssertions:o.length,passedAssertions:u,failedAssertions:m}}catch(s){console.error("[Simple Assertions] Error in post-process assertions hook:",s)}}var k=A(()=>{"use strict";q()});var J={};w(J,{default:()=>z});module.exports=W(J);var $=r=>({onload(){r.pipeline.registerHook("pre-processing",async e=>{e.editor&&(e.requestState.metadata||(e.requestState.metadata={}),e.requestState.metadata.editorDocument=e.editor.getJSON())},5),r.pipeline.registerHook("post-processing",async e=>{let{postProcessAssertionsHook:t}=await Promise.resolve().then(()=>(k(),N));await t(e)},15),r.pipeline.registerHook("post-processing",async e=>{let t=e.responseState?.metadata?.assertionResults;if(t?.results?.length){e.responseState.metadata||(e.responseState.metadata={}),Array.isArray(e.responseState.metadata.reportEntries)||(e.responseState.metadata.reportEntries=[]);for(let n of t.results){let s=n.assertion?.description?.trim()||`${n.assertion?.field??""} ${n.assertion?.operator??""} ${n.assertion?.expectedValue??""}`.trim();e.responseState.metadata.reportEntries.push({type:"assertion",message:s||"Assertion",passed:n.passed,actual:n.actualValue,expected:n.assertion?.expectedValue,operator:n.assertion?.operator})}}},50)}}),z=$;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"simple-assertions": "1.0
|
|
3
|
-
"voiden-advanced-auth": "2.0.
|
|
4
|
-
"voiden-faker": "1.1.
|
|
5
|
-
"voiden-graphql": "1.0.
|
|
6
|
-
"voiden-mcp-client": "0.1.
|
|
7
|
-
"voiden-mcp-tool": "0.1.
|
|
8
|
-
"voiden-rest-api": "1.4.
|
|
2
|
+
"simple-assertions": "1.1.0",
|
|
3
|
+
"voiden-advanced-auth": "2.0.8",
|
|
4
|
+
"voiden-faker": "1.1.1",
|
|
5
|
+
"voiden-graphql": "1.0.7",
|
|
6
|
+
"voiden-mcp-client": "0.1.1",
|
|
7
|
+
"voiden-mcp-tool": "0.1.1",
|
|
8
|
+
"voiden-rest-api": "1.4.12",
|
|
9
9
|
"voiden-scripting": "1.1.6",
|
|
10
|
-
"voiden-sockets-grpcs": "1.1.
|
|
10
|
+
"voiden-sockets-grpcs": "1.1.7"
|
|
11
11
|
}
|
package/dist/envFile.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structurally merges two parsed YAML env trees (e.g. a profile's public +
|
|
3
|
+
* private content) — `b`'s `variables:` win over `a`'s per node on key
|
|
4
|
+
* conflict (matches the app's own public/private precedence, see env.ts's
|
|
5
|
+
* loadYamlEnvironments), `children:` are merged recursively rather than one
|
|
6
|
+
* replacing the other wholesale, so a child defined only in `a` still shows
|
|
7
|
+
* up even if `b` also defines siblings under the same parent.
|
|
8
|
+
*/
|
|
9
|
+
export declare function mergeYamlEnvTrees(a: unknown, b: unknown): Record<string, unknown>;
|
|
1
10
|
/**
|
|
2
11
|
* `environmentName`, when given, scopes YAML loading to exactly one named
|
|
3
12
|
* environment (e.g. "dev") instead of the default "flatten every
|
|
@@ -10,4 +19,21 @@
|
|
|
10
19
|
* treated as an error, since there's genuinely nothing to scope to.
|
|
11
20
|
*/
|
|
12
21
|
export declare function loadEnvFile(envPath: string, environmentName?: string): Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Navigates a tree by an exact dotted path (as produced by
|
|
24
|
+
* listYamlEnvironmentNames, e.g. "staging.eu") rather than searching for a
|
|
25
|
+
* bare key anywhere — unlike findEnvironment above (kept as-is for the
|
|
26
|
+
* CLI's existing --environment <name> flag, which intentionally matches by
|
|
27
|
+
* bare name wherever it occurs), a dotted path must resolve deterministically:
|
|
28
|
+
* two different parents can each have a child literally named "eu", and
|
|
29
|
+
* only a full-path walk tells them apart. Same inheritance order (each
|
|
30
|
+
* segment's own variables merge on top of everything above it).
|
|
31
|
+
*/
|
|
32
|
+
export declare function findEnvironmentByPath(tree: Record<string, unknown>, dottedPath: string): Record<string, string> | null;
|
|
33
|
+
/** Every named environment in the tree, at any depth, as dotted paths
|
|
34
|
+
* (e.g. "staging", "staging.eu") — unlike topLevelEnvironmentNames, this
|
|
35
|
+
* IS meant to show the full nested shape (used by list_environments to
|
|
36
|
+
* show a profile's environment hierarchy, not just an error hint). */
|
|
37
|
+
export declare function listYamlEnvironmentNames(content: string): string[];
|
|
38
|
+
export declare function parseYamlEnv(content: string, environmentName?: string): Record<string, string>;
|
|
13
39
|
//# sourceMappingURL=envFile.d.ts.map
|
package/dist/envFile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envFile.d.ts","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"AASA;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS7F"}
|
|
1
|
+
{"version":3,"file":"envFile.d.ts","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"AASA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqBjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS7F;AA6DD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAWtH;AAED;;;uEAGuE;AACvE,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBlE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsC9F"}
|
package/dist/envFile.js
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import { extname } from 'path';
|
|
3
3
|
import YAML from 'yaml';
|
|
4
|
+
/**
|
|
5
|
+
* Structurally merges two parsed YAML env trees (e.g. a profile's public +
|
|
6
|
+
* private content) — `b`'s `variables:` win over `a`'s per node on key
|
|
7
|
+
* conflict (matches the app's own public/private precedence, see env.ts's
|
|
8
|
+
* loadYamlEnvironments), `children:` are merged recursively rather than one
|
|
9
|
+
* replacing the other wholesale, so a child defined only in `a` still shows
|
|
10
|
+
* up even if `b` also defines siblings under the same parent.
|
|
11
|
+
*/
|
|
12
|
+
export function mergeYamlEnvTrees(a, b) {
|
|
13
|
+
const treeA = a && typeof a === 'object' && !Array.isArray(a) ? a : {};
|
|
14
|
+
const treeB = b && typeof b === 'object' && !Array.isArray(b) ? b : {};
|
|
15
|
+
const keys = new Set([...Object.keys(treeA), ...Object.keys(treeB)]);
|
|
16
|
+
const result = {};
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
const nodeA = treeA[key];
|
|
19
|
+
const nodeB = treeB[key];
|
|
20
|
+
const isNodeA = nodeA != null && typeof nodeA === 'object' && !Array.isArray(nodeA);
|
|
21
|
+
const isNodeB = nodeB != null && typeof nodeB === 'object' && !Array.isArray(nodeB);
|
|
22
|
+
if (!isNodeA && !isNodeB) {
|
|
23
|
+
result[key] = nodeB ?? nodeA;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const a2 = (isNodeA ? nodeA : {});
|
|
27
|
+
const b2 = (isNodeB ? nodeB : {});
|
|
28
|
+
result[key] = {
|
|
29
|
+
variables: { ...(a2.variables ?? {}), ...(b2.variables ?? {}) },
|
|
30
|
+
...(a2.children || b2.children
|
|
31
|
+
? { children: mergeYamlEnvTrees(a2.children ?? {}, b2.children ?? {}) }
|
|
32
|
+
: {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
4
37
|
/**
|
|
5
38
|
* `environmentName`, when given, scopes YAML loading to exactly one named
|
|
6
39
|
* environment (e.g. "dev") instead of the default "flatten every
|
|
@@ -78,7 +111,54 @@ function topLevelEnvironmentNames(tree) {
|
|
|
78
111
|
.filter(([, value]) => value != null && typeof value === 'object' && !Array.isArray(value))
|
|
79
112
|
.map(([key]) => key);
|
|
80
113
|
}
|
|
81
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Navigates a tree by an exact dotted path (as produced by
|
|
116
|
+
* listYamlEnvironmentNames, e.g. "staging.eu") rather than searching for a
|
|
117
|
+
* bare key anywhere — unlike findEnvironment above (kept as-is for the
|
|
118
|
+
* CLI's existing --environment <name> flag, which intentionally matches by
|
|
119
|
+
* bare name wherever it occurs), a dotted path must resolve deterministically:
|
|
120
|
+
* two different parents can each have a child literally named "eu", and
|
|
121
|
+
* only a full-path walk tells them apart. Same inheritance order (each
|
|
122
|
+
* segment's own variables merge on top of everything above it).
|
|
123
|
+
*/
|
|
124
|
+
export function findEnvironmentByPath(tree, dottedPath) {
|
|
125
|
+
let current = tree;
|
|
126
|
+
let resolved = {};
|
|
127
|
+
for (const segment of dottedPath.split('.')) {
|
|
128
|
+
const value = current[segment];
|
|
129
|
+
if (value === null || value === undefined || Array.isArray(value) || typeof value !== 'object')
|
|
130
|
+
return null;
|
|
131
|
+
const node = value;
|
|
132
|
+
resolved = { ...resolved, ...ownVariables(node) };
|
|
133
|
+
current = (node.children ?? {});
|
|
134
|
+
}
|
|
135
|
+
return resolved;
|
|
136
|
+
}
|
|
137
|
+
/** Every named environment in the tree, at any depth, as dotted paths
|
|
138
|
+
* (e.g. "staging", "staging.eu") — unlike topLevelEnvironmentNames, this
|
|
139
|
+
* IS meant to show the full nested shape (used by list_environments to
|
|
140
|
+
* show a profile's environment hierarchy, not just an error hint). */
|
|
141
|
+
export function listYamlEnvironmentNames(content) {
|
|
142
|
+
const parsed = YAML.parse(content);
|
|
143
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
144
|
+
return [];
|
|
145
|
+
const names = [];
|
|
146
|
+
const walk = (tree, prefix) => {
|
|
147
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
148
|
+
if (value === null || value === undefined || Array.isArray(value) || typeof value !== 'object')
|
|
149
|
+
continue;
|
|
150
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
151
|
+
names.push(path);
|
|
152
|
+
const node = value;
|
|
153
|
+
if (node.children != null && typeof node.children === 'object') {
|
|
154
|
+
walk(node.children, path);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
walk(parsed, '');
|
|
159
|
+
return names;
|
|
160
|
+
}
|
|
161
|
+
export function parseYamlEnv(content, environmentName) {
|
|
82
162
|
const parsed = YAML.parse(content);
|
|
83
163
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
84
164
|
return {};
|
package/dist/envFile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envFile.js","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"envFile.js","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless env-profile discovery/resolution for the `list_environments`/
|
|
3
|
+
* `select_environment` fixed MCP tools (mcpServing.ts). A deliberately
|
|
4
|
+
* simplified port of apps/electron/src/main/env.ts's profile logic — same
|
|
5
|
+
* precedent as plugins/voiden-mcp-tool/src/lib/toolCapability.ts's
|
|
6
|
+
* loadProjectEnvironmentVars, which already does this for its own narrower
|
|
7
|
+
* needs. No Electron dependency (this package is a standalone CLI/library),
|
|
8
|
+
* no UI "active profile" state, no nested sub-project scanning, no legacy
|
|
9
|
+
* dotted `.env.foo.bar` hierarchy chain — see mcpServing.ts's callers for
|
|
10
|
+
* what's actually needed here.
|
|
11
|
+
*/
|
|
12
|
+
export interface EnvProfileInfo {
|
|
13
|
+
name: string;
|
|
14
|
+
source: 'yaml' | 'legacy-dotenv';
|
|
15
|
+
/** Present only when source === 'yaml' and the file actually exists. */
|
|
16
|
+
publicFile?: string;
|
|
17
|
+
privateFile?: string;
|
|
18
|
+
/** Dotted environment paths (e.g. "staging", "staging.eu") — only when source === 'yaml'. */
|
|
19
|
+
environments?: string[];
|
|
20
|
+
/** Discovered .env* files (project root + .voiden/) — only when source === 'legacy-dotenv'. */
|
|
21
|
+
dotEnvFiles?: string[];
|
|
22
|
+
}
|
|
23
|
+
export declare function discoverEnvProfiles(projectRoot: string): EnvProfileInfo[];
|
|
24
|
+
/** Resolves the final variable map for one profile (+ optional named
|
|
25
|
+
* environment within it). Throws if the profile doesn't exist or the
|
|
26
|
+
* named environment isn't found in it (same "available: ..." style error
|
|
27
|
+
* envFile.ts's own parseYamlEnv already throws for an unknown name). */
|
|
28
|
+
export declare function resolveEnvProfile(projectRoot: string, profile: string, environmentName?: string): Record<string, string>;
|
|
29
|
+
//# sourceMappingURL=envProfiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envProfiles.d.ts","sourceRoot":"","sources":["../src/envProfiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,eAAe,CAAA;IAChC,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAoDD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,EAAE,CAyBzE;AAED;;;yEAGyE;AACzE,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4CxB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless env-profile discovery/resolution for the `list_environments`/
|
|
3
|
+
* `select_environment` fixed MCP tools (mcpServing.ts). A deliberately
|
|
4
|
+
* simplified port of apps/electron/src/main/env.ts's profile logic — same
|
|
5
|
+
* precedent as plugins/voiden-mcp-tool/src/lib/toolCapability.ts's
|
|
6
|
+
* loadProjectEnvironmentVars, which already does this for its own narrower
|
|
7
|
+
* needs. No Electron dependency (this package is a standalone CLI/library),
|
|
8
|
+
* no UI "active profile" state, no nested sub-project scanning, no legacy
|
|
9
|
+
* dotted `.env.foo.bar` hierarchy chain — see mcpServing.ts's callers for
|
|
10
|
+
* what's actually needed here.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { parseYamlEnv, listYamlEnvironmentNames, mergeYamlEnvTrees, findEnvironmentByPath } from './envFile.js';
|
|
15
|
+
import YAML from 'yaml';
|
|
16
|
+
const VOIDEN_DIR = '.voiden';
|
|
17
|
+
const PROFILE_FILE_PATTERN = /^env-([a-z0-9-]+)-(public|private)\.yaml$/;
|
|
18
|
+
function profileFileNames(projectRoot, profile) {
|
|
19
|
+
const dir = join(projectRoot, VOIDEN_DIR);
|
|
20
|
+
if (profile === 'default') {
|
|
21
|
+
return { publicFile: join(dir, 'env-public.yaml'), privateFile: join(dir, 'env-private.yaml') };
|
|
22
|
+
}
|
|
23
|
+
return { publicFile: join(dir, `env-${profile}-public.yaml`), privateFile: join(dir, `env-${profile}-private.yaml`) };
|
|
24
|
+
}
|
|
25
|
+
/** Mirrors env.ts's discoverProfiles — scan .voiden/ for named profile
|
|
26
|
+
* files, "default" always included even with no files on disk yet. */
|
|
27
|
+
function discoverProfileNames(projectRoot) {
|
|
28
|
+
const names = new Set(['default']);
|
|
29
|
+
const dir = join(projectRoot, VOIDEN_DIR);
|
|
30
|
+
let entries;
|
|
31
|
+
try {
|
|
32
|
+
entries = readdirSync(dir);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return Array.from(names);
|
|
36
|
+
}
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const match = PROFILE_FILE_PATTERN.exec(entry);
|
|
39
|
+
if (match)
|
|
40
|
+
names.add(match[1]);
|
|
41
|
+
}
|
|
42
|
+
return Array.from(names);
|
|
43
|
+
}
|
|
44
|
+
function readIfExists(path) {
|
|
45
|
+
return existsSync(path) ? readFileSync(path, 'utf-8') : undefined;
|
|
46
|
+
}
|
|
47
|
+
/** project root + .voiden/, non-recursive — same scope as env.ts's
|
|
48
|
+
* loadProjectEnv fallback, minus the dotted-chain hierarchy machinery
|
|
49
|
+
* (out of scope here, see the plan's "Not doing" section). */
|
|
50
|
+
function discoverDotEnvFiles(projectRoot) {
|
|
51
|
+
const dirs = [projectRoot, join(projectRoot, VOIDEN_DIR)];
|
|
52
|
+
const found = [];
|
|
53
|
+
for (const dir of dirs) {
|
|
54
|
+
let entries;
|
|
55
|
+
try {
|
|
56
|
+
entries = readdirSync(dir);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
if (entry.startsWith('.env'))
|
|
63
|
+
found.push(join(dir, entry));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return found;
|
|
67
|
+
}
|
|
68
|
+
export function discoverEnvProfiles(projectRoot) {
|
|
69
|
+
return discoverProfileNames(projectRoot).map((name) => {
|
|
70
|
+
const { publicFile, privateFile } = profileFileNames(projectRoot, name);
|
|
71
|
+
const publicContent = readIfExists(publicFile);
|
|
72
|
+
const privateContent = readIfExists(privateFile);
|
|
73
|
+
if (publicContent || privateContent) {
|
|
74
|
+
const merged = mergeYamlEnvTrees(publicContent ? YAML.parse(publicContent) : {}, privateContent ? YAML.parse(privateContent) : {});
|
|
75
|
+
const environments = listYamlEnvironmentNames(YAML.stringify(merged));
|
|
76
|
+
if (environments.length > 0) {
|
|
77
|
+
return {
|
|
78
|
+
name,
|
|
79
|
+
source: 'yaml',
|
|
80
|
+
...(publicContent ? { publicFile } : {}),
|
|
81
|
+
...(privateContent ? { privateFile } : {}),
|
|
82
|
+
environments,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { name, source: 'legacy-dotenv', dotEnvFiles: discoverDotEnvFiles(projectRoot) };
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Resolves the final variable map for one profile (+ optional named
|
|
90
|
+
* environment within it). Throws if the profile doesn't exist or the
|
|
91
|
+
* named environment isn't found in it (same "available: ..." style error
|
|
92
|
+
* envFile.ts's own parseYamlEnv already throws for an unknown name). */
|
|
93
|
+
export function resolveEnvProfile(projectRoot, profile, environmentName) {
|
|
94
|
+
const profiles = discoverEnvProfiles(projectRoot);
|
|
95
|
+
const info = profiles.find((p) => p.name === profile);
|
|
96
|
+
if (!info) {
|
|
97
|
+
throw new Error(`Unknown profile "${profile}". Available: ${profiles.map((p) => p.name).join(', ')}`);
|
|
98
|
+
}
|
|
99
|
+
if (info.source === 'legacy-dotenv') {
|
|
100
|
+
const env = {};
|
|
101
|
+
for (const path of info.dotEnvFiles ?? []) {
|
|
102
|
+
try {
|
|
103
|
+
Object.assign(env, parseDotEnvLoose(readFileSync(path, 'utf-8')));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// A malformed .env* file shouldn't block resolving the others —
|
|
107
|
+
// select_environment's job is "best available", not strict parsing.
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return env;
|
|
111
|
+
}
|
|
112
|
+
const { publicFile, privateFile } = profileFileNames(projectRoot, profile);
|
|
113
|
+
const publicContent = readIfExists(publicFile) ?? '';
|
|
114
|
+
const privateContent = readIfExists(privateFile) ?? '';
|
|
115
|
+
const merged = mergeYamlEnvTrees(publicContent ? YAML.parse(publicContent) : {}, privateContent ? YAML.parse(privateContent) : {});
|
|
116
|
+
if (environmentName) {
|
|
117
|
+
// Path-based, not envFile.ts's own bare-name findEnvironment — that one
|
|
118
|
+
// searches for a matching key ANYWHERE in the tree (fine for the CLI's
|
|
119
|
+
// simpler --environment <name> flag), but list_environments returns
|
|
120
|
+
// full dotted paths specifically to disambiguate same-named children
|
|
121
|
+
// under different parents (e.g. "staging.eu" vs "prod.eu") — only a
|
|
122
|
+
// full-path walk resolves the right one.
|
|
123
|
+
const resolved = findEnvironmentByPath(merged, environmentName);
|
|
124
|
+
if (!resolved) {
|
|
125
|
+
const available = listYamlEnvironmentNames(YAML.stringify(merged));
|
|
126
|
+
throw new Error(`Environment "${environmentName}" not found in profile "${profile}". Available: ${available.join(', ')}`);
|
|
127
|
+
}
|
|
128
|
+
return resolved;
|
|
129
|
+
}
|
|
130
|
+
return parseYamlEnv(YAML.stringify(merged));
|
|
131
|
+
}
|
|
132
|
+
/** Same shape as envFile.ts's private parseDotEnv, duplicated rather than
|
|
133
|
+
* exported from there since that one throws on a malformed line (correct
|
|
134
|
+
* for an explicit --env <path>) where discovery here wants best-effort. */
|
|
135
|
+
function parseDotEnvLoose(content) {
|
|
136
|
+
const env = {};
|
|
137
|
+
for (const rawLine of content.split('\n')) {
|
|
138
|
+
const line = rawLine.trim();
|
|
139
|
+
if (!line || line.startsWith('#'))
|
|
140
|
+
continue;
|
|
141
|
+
const eq = line.indexOf('=');
|
|
142
|
+
if (eq === -1)
|
|
143
|
+
continue;
|
|
144
|
+
const key = line.slice(0, eq).trim();
|
|
145
|
+
if (!key)
|
|
146
|
+
continue;
|
|
147
|
+
env[key] = line.slice(eq + 1).trim().replace(/^["']|["']$/g, '');
|
|
148
|
+
}
|
|
149
|
+
return env;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=envProfiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envProfiles.js","sourceRoot":"","sources":["../src/envProfiles.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1213,6 +1213,15 @@ pluginCmd
|
|
|
1213
1213
|
else if (record !== undefined && !record.enabled) {
|
|
1214
1214
|
statusBadge = chalk.yellow(' · disabled');
|
|
1215
1215
|
}
|
|
1216
|
+
else if (!hasCoreRunner(def.name)) {
|
|
1217
|
+
// "enabled" (the plugins.json bit, or no record = default-enabled) is not the
|
|
1218
|
+
// same as "usable" — loadEnabledPlugins() also requires an actual runner.js,
|
|
1219
|
+
// bundled in this package install or cached in ~/.voiden/extensions/. Reporting
|
|
1220
|
+
// "✓ enabled" here regardless would silently disagree with what run_request /
|
|
1221
|
+
// the MCP server can actually load, which is exactly the confusing state this
|
|
1222
|
+
// command exists to surface.
|
|
1223
|
+
statusBadge = chalk.gray(' not installed [no runner]');
|
|
1224
|
+
}
|
|
1216
1225
|
else {
|
|
1217
1226
|
statusBadge = chalk.green(' ✓ enabled');
|
|
1218
1227
|
}
|
|
@@ -1298,12 +1307,24 @@ mcpCmd
|
|
|
1298
1307
|
.option('--claude', 'Install for Claude Code only')
|
|
1299
1308
|
.option('--codex', 'Install for Codex only')
|
|
1300
1309
|
.option('-p, --project <path>', 'Project directory to register the MCP server against', '.')
|
|
1301
|
-
.option('--local-server <path>', 'Use `node <path> mcp serve` instead of `npx -y @voiden/runner mcp serve` — for testing against a local build')
|
|
1310
|
+
.option('--local-server <path>', 'Use `node <path> mcp serve` instead of `npx -y @voiden/runner@<this version> mcp serve` — for testing against a local build')
|
|
1302
1311
|
.action((opts) => {
|
|
1303
1312
|
const targets = resolveMcpTargets(opts);
|
|
1313
|
+
// Pin to the exact version of this CLI the user is running `mcp install`
|
|
1314
|
+
// from — never a bare, unpinned `npx -y @voiden/runner`. Unpinned resolves
|
|
1315
|
+
// to whatever npm's "latest" dist-tag happens to point at, which can sit
|
|
1316
|
+
// far behind the actively-developed prerelease line this MCP tooling
|
|
1317
|
+
// actually lives on (e.g. "latest" stuck on a stable 2.2.0 cut from
|
|
1318
|
+
// before write_result/list_requests/the plugin registry existed, while
|
|
1319
|
+
// real fixes ship under the "beta" tag) — every agent session would
|
|
1320
|
+
// silently run that stale version forever, with no way to notice short of
|
|
1321
|
+
// diffing tool output against what this CLI's own docs say it does.
|
|
1322
|
+
// Pinning to what's actually installed right now is deterministic: it's
|
|
1323
|
+
// exactly what was tested when `mcp install` ran, and picks up newer
|
|
1324
|
+
// fixes the moment the user updates this CLI and re-runs `mcp install`.
|
|
1304
1325
|
const serverCommand = opts.localServer
|
|
1305
1326
|
? { command: 'node', args: [resolve(opts.localServer), 'mcp', 'serve', resolve(opts.project)] }
|
|
1306
|
-
:
|
|
1327
|
+
: { command: 'npx', args: ['-y', `@voiden/runner@${pkg.version}`, 'mcp', 'serve', resolve(opts.project)] };
|
|
1307
1328
|
const installed = installMcpIntegration(opts.project, targets, MCP_SKILL_MARKDOWN, serverCommand);
|
|
1308
1329
|
if (installed.length === 0) {
|
|
1309
1330
|
console.log(chalk.yellow(' Nothing to install.'));
|
|
@@ -1313,9 +1334,12 @@ mcpCmd
|
|
|
1313
1334
|
for (const target of installed) {
|
|
1314
1335
|
console.log(chalk.green(` ✓ ${target === 'claude' ? 'Claude Code' : 'Codex'}`) + chalk.gray(` — skill installed, fixed-tools MCP server registered for ${resolve(opts.project)}`));
|
|
1315
1336
|
}
|
|
1316
|
-
if (
|
|
1337
|
+
if (opts.localServer) {
|
|
1317
1338
|
console.log(chalk.gray(` Using local build: node ${serverCommand.args[0]}`));
|
|
1318
1339
|
}
|
|
1340
|
+
else {
|
|
1341
|
+
console.log(chalk.gray(` Pinned to this CLI's version: @voiden/runner@${pkg.version}`));
|
|
1342
|
+
}
|
|
1319
1343
|
console.log();
|
|
1320
1344
|
console.log(chalk.gray(' Restart Claude Code / Codex (or run /mcp) to pick up the new server.'));
|
|
1321
1345
|
});
|
|
@@ -1415,6 +1439,9 @@ mcpCmd
|
|
|
1415
1439
|
// Shared across calls so {{process.xxx}} runtime variables chain the
|
|
1416
1440
|
// same way they do for the stdio path and for @voiden/mcp.
|
|
1417
1441
|
const runtimeVars = {};
|
|
1442
|
+
// Set by select_environment, read by run_request as its base env layer
|
|
1443
|
+
// — shared by reference across calls the same way runtimeVars is.
|
|
1444
|
+
const selectedEnv = { vars: {} };
|
|
1418
1445
|
if (opts.http) {
|
|
1419
1446
|
const port = Number(opts.port);
|
|
1420
1447
|
const host = opts.host;
|
|
@@ -1426,7 +1453,7 @@ mcpCmd
|
|
|
1426
1453
|
const httpServer = createHttpServer(async (req, res) => {
|
|
1427
1454
|
try {
|
|
1428
1455
|
const requestServer = new McpServer({ name: 'voiden-runner', version: '1.0.0' });
|
|
1429
|
-
registerFixedTools(requestServer, projectRoot, runtimeVars, activePlugins);
|
|
1456
|
+
registerFixedTools(requestServer, projectRoot, runtimeVars, activePlugins, selectedEnv);
|
|
1430
1457
|
registerToolsFromDecisions(requestServer, decisions, env, runtimeVars, activePlugins, commitSha, projectRoot);
|
|
1431
1458
|
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
1432
1459
|
await requestServer.connect(transport);
|
|
@@ -1447,7 +1474,7 @@ mcpCmd
|
|
|
1447
1474
|
});
|
|
1448
1475
|
httpServer.listen(port, host, () => {
|
|
1449
1476
|
console.error(chalk.green(` ✓ voiden-runner mcp serve — listening on http://${host}:${port}/mcp`));
|
|
1450
|
-
console.error(chalk.gray(` ${servedCount} tool(s) served (plus list_void_files, list_requests, run_request, write_result)`));
|
|
1477
|
+
console.error(chalk.gray(` ${servedCount} tool(s) served (plus list_void_files, list_requests, run_request, write_result, list_environments, select_environment)`));
|
|
1451
1478
|
if (host !== '127.0.0.1' && host !== 'localhost') {
|
|
1452
1479
|
console.error(chalk.red(` ⚠ Bound to ${host} — reachable beyond this machine. Make sure that's intended.`));
|
|
1453
1480
|
}
|
|
@@ -1460,7 +1487,7 @@ mcpCmd
|
|
|
1460
1487
|
// Startup info goes to stderr only, same discipline @voiden/mcp's
|
|
1461
1488
|
// own entrypoint already follows (it prints nothing).
|
|
1462
1489
|
const server = new McpServer({ name: 'voiden-runner', version: '1.0.0' });
|
|
1463
|
-
registerFixedTools(server, projectRoot, runtimeVars, activePlugins);
|
|
1490
|
+
registerFixedTools(server, projectRoot, runtimeVars, activePlugins, selectedEnv);
|
|
1464
1491
|
registerToolsFromDecisions(server, decisions, env, runtimeVars, activePlugins, commitSha, projectRoot);
|
|
1465
1492
|
await server.connect(new StdioServerTransport());
|
|
1466
1493
|
}
|