@vincemakes/kiso-tools-node 0.34.0 → 0.36.0
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/dist/index.d.ts +7 -0
- package/dist/index.js +9 -30
- package/dist/secret-env.d.ts +27 -0
- package/dist/secret-env.js +48 -0
- package/package.json +7 -3
package/dist/index.d.ts
CHANGED
|
@@ -100,6 +100,12 @@ export interface WorkspaceToolsOptions {
|
|
|
100
100
|
* name — explicit beats the heuristic, as it does for MCP servers.
|
|
101
101
|
*/
|
|
102
102
|
readonly shellEnv?: "inherit" | Readonly<Record<string, string>>;
|
|
103
|
+
/** Astra F7: the env var NAMES the configured profiles authenticate with.
|
|
104
|
+
* The strip's suffix rules (`_API_KEY`, `_AUTH_TOKEN`) cannot see a name
|
|
105
|
+
* like `REVIEW_PROVIDER_TOKEN`, and only the config knows which names are
|
|
106
|
+
* secrets — so it says so. Ignored when `shellEnv` is "inherit", which is
|
|
107
|
+
* an explicit opt-in to the whole environment. */
|
|
108
|
+
readonly secretEnvNames?: readonly string[];
|
|
103
109
|
/**
|
|
104
110
|
* DC-54 — the bounds that keep a tool call finite. Every field is
|
|
105
111
|
* optional and defaults to the constant beside it; a host embedding
|
|
@@ -166,6 +172,7 @@ export declare function editFileTool(opts: WorkspaceToolsOptions): Tool<{
|
|
|
166
172
|
}[];
|
|
167
173
|
expectedRevision?: string;
|
|
168
174
|
}>;
|
|
175
|
+
export { SHELL_STRIP_EXACT, strippedShellEnv } from "./secret-env.js";
|
|
169
176
|
export declare function shellTool(opts: WorkspaceToolsOptions): Tool<{
|
|
170
177
|
command: string;
|
|
171
178
|
timeoutMs?: number;
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import { tmpdir } from "node:os";
|
|
|
27
27
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
28
28
|
import { defineTool } from "@vincemakes/kiso-core";
|
|
29
29
|
// WR-1/WR-1A — the revision-guard primitives (unit-tested in wr1a-coda):
|
|
30
|
+
import { strippedShellEnv } from "./secret-env.js";
|
|
30
31
|
import { contentRevision, normalizeRevision, postEffectEscape, precondition, publishNewFile, revalidateBeforeRename } from "./wr1.js";
|
|
31
32
|
/**
|
|
32
33
|
* TUI2-R1 (C) — THE SHELL PROGRESS SIDECAR.
|
|
@@ -995,37 +996,15 @@ export function editFileTool(opts) {
|
|
|
995
996
|
},
|
|
996
997
|
});
|
|
997
998
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
* through untouched.
|
|
1004
|
-
*/
|
|
1005
|
-
const SHELL_STRIP_EXACT = new Set([
|
|
1006
|
-
"ANTHROPIC_API_KEY",
|
|
1007
|
-
"OPENAI_API_KEY",
|
|
1008
|
-
"ANTHROPIC_BASE_URL",
|
|
1009
|
-
"OPENAI_BASE_URL",
|
|
1010
|
-
"ANTHROPIC_MODEL",
|
|
1011
|
-
"OPENAI_MODEL",
|
|
1012
|
-
]);
|
|
1013
|
-
function strippedShellEnv(env) {
|
|
1014
|
-
const out = {};
|
|
1015
|
-
for (const [key, value] of Object.entries(env)) {
|
|
1016
|
-
if (SHELL_STRIP_EXACT.has(key))
|
|
1017
|
-
continue;
|
|
1018
|
-
if (key.endsWith("_API_KEY") || key.endsWith("_AUTH_TOKEN"))
|
|
1019
|
-
continue;
|
|
1020
|
-
if (value !== undefined)
|
|
1021
|
-
out[key] = value;
|
|
1022
|
-
}
|
|
1023
|
-
return out;
|
|
1024
|
-
}
|
|
999
|
+
// Astra F7: the strip is ONE implementation, shared with the MCP
|
|
1000
|
+
// extension's stdio children (./secret-env.ts). It used to live here
|
|
1001
|
+
// with a hand-kept copy over there; the copy never learned the
|
|
1002
|
+
// declared names, which is how MCP children kept leaking.
|
|
1003
|
+
export { SHELL_STRIP_EXACT, strippedShellEnv } from "./secret-env.js";
|
|
1025
1004
|
export function shellTool(opts) {
|
|
1026
1005
|
return defineTool({
|
|
1027
1006
|
name: "shell",
|
|
1028
|
-
description: "Run a shell command with the workspace as the working directory.
|
|
1007
|
+
description: "Run a shell command through /bin/sh with the workspace root as the working directory: builds, tests, git, package managers, curl for HTTP APIs, system queries. Side effects are real; the human may be asked to approve the run. Fails loudly on timeout or non-zero exit.",
|
|
1029
1008
|
parameters: {
|
|
1030
1009
|
type: "object",
|
|
1031
1010
|
properties: {
|
|
@@ -1035,7 +1014,7 @@ export function shellTool(opts) {
|
|
|
1035
1014
|
required: ["command"],
|
|
1036
1015
|
additionalProperties: false,
|
|
1037
1016
|
},
|
|
1038
|
-
promptSnippet: "shell —
|
|
1017
|
+
promptSnippet: "shell — any command the task needs (builds, tests, git, curl, system queries)",
|
|
1039
1018
|
promptGuidelines: ["commands run in the workspace root; on failure read the error and adjust — never repeat blindly"],
|
|
1040
1019
|
execute: async ({ command, timeoutMs }, ctx) => {
|
|
1041
1020
|
const timeout = timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS;
|
|
@@ -1058,7 +1037,7 @@ export function shellTool(opts) {
|
|
|
1058
1037
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1059
1038
|
env: opts.shellEnv === "inherit"
|
|
1060
1039
|
? process.env
|
|
1061
|
-
: { ...strippedShellEnv(process.env), ...(opts.shellEnv ?? {}) },
|
|
1040
|
+
: { ...strippedShellEnv(process.env, opts.secretEnvNames), ...(opts.shellEnv ?? {}) },
|
|
1062
1041
|
});
|
|
1063
1042
|
let stdout = "";
|
|
1064
1043
|
let stderr = "";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE child-environment strip — ONE implementation, both children.
|
|
3
|
+
*
|
|
4
|
+
* bootstrap #3 (finding #7) established the rule for shell children: the
|
|
5
|
+
* agent's own provider surface (both families' keys, base URLs and model
|
|
6
|
+
* choices) plus the generic API-key / auth-token patterns that cover other
|
|
7
|
+
* providers. Everything else passes through untouched.
|
|
8
|
+
*
|
|
9
|
+
* Astra F7 then showed the rule was incomplete AND duplicated. Incomplete:
|
|
10
|
+
* a profile's `apiKeyEnv` can be ANY name — `REVIEW_PROVIDER_TOKEN` ends in
|
|
11
|
+
* neither suffix — so the key a profile authenticates with survived into
|
|
12
|
+
* the child. Duplicated: the MCP extension carried its own copy of the list
|
|
13
|
+
* with a "keep in sync" comment, and a comment is not a mechanism; the copy
|
|
14
|
+
* did not learn the declared names and MCP stdio children kept leaking.
|
|
15
|
+
*
|
|
16
|
+
* The names must come from the caller because only the config knows which
|
|
17
|
+
* env vars are secrets. No names declared = exactly the pre-F7 behaviour,
|
|
18
|
+
* which is what a standalone extension load gets.
|
|
19
|
+
*
|
|
20
|
+
* This module imports NOTHING on purpose: the MCP extension is an esbuild
|
|
21
|
+
* bundle, and a shared rule must not drag a package graph across with it.
|
|
22
|
+
*/
|
|
23
|
+
/** The explicit credential list stripped from every child. */
|
|
24
|
+
export declare const SHELL_STRIP_EXACT: ReadonlySet<string>;
|
|
25
|
+
/** The environment a child process may see: `env` minus the exact list,
|
|
26
|
+
* minus every DECLARED secret name, minus the two suffix families. */
|
|
27
|
+
export declare function strippedShellEnv(env: Record<string, string | undefined>, secretNames?: readonly string[]): Record<string, string | undefined>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE child-environment strip — ONE implementation, both children.
|
|
3
|
+
*
|
|
4
|
+
* bootstrap #3 (finding #7) established the rule for shell children: the
|
|
5
|
+
* agent's own provider surface (both families' keys, base URLs and model
|
|
6
|
+
* choices) plus the generic API-key / auth-token patterns that cover other
|
|
7
|
+
* providers. Everything else passes through untouched.
|
|
8
|
+
*
|
|
9
|
+
* Astra F7 then showed the rule was incomplete AND duplicated. Incomplete:
|
|
10
|
+
* a profile's `apiKeyEnv` can be ANY name — `REVIEW_PROVIDER_TOKEN` ends in
|
|
11
|
+
* neither suffix — so the key a profile authenticates with survived into
|
|
12
|
+
* the child. Duplicated: the MCP extension carried its own copy of the list
|
|
13
|
+
* with a "keep in sync" comment, and a comment is not a mechanism; the copy
|
|
14
|
+
* did not learn the declared names and MCP stdio children kept leaking.
|
|
15
|
+
*
|
|
16
|
+
* The names must come from the caller because only the config knows which
|
|
17
|
+
* env vars are secrets. No names declared = exactly the pre-F7 behaviour,
|
|
18
|
+
* which is what a standalone extension load gets.
|
|
19
|
+
*
|
|
20
|
+
* This module imports NOTHING on purpose: the MCP extension is an esbuild
|
|
21
|
+
* bundle, and a shared rule must not drag a package graph across with it.
|
|
22
|
+
*/
|
|
23
|
+
/** The explicit credential list stripped from every child. */
|
|
24
|
+
export const SHELL_STRIP_EXACT = new Set([
|
|
25
|
+
"ANTHROPIC_API_KEY",
|
|
26
|
+
"OPENAI_API_KEY",
|
|
27
|
+
"ANTHROPIC_BASE_URL",
|
|
28
|
+
"OPENAI_BASE_URL",
|
|
29
|
+
"ANTHROPIC_MODEL",
|
|
30
|
+
"OPENAI_MODEL",
|
|
31
|
+
]);
|
|
32
|
+
/** The environment a child process may see: `env` minus the exact list,
|
|
33
|
+
* minus every DECLARED secret name, minus the two suffix families. */
|
|
34
|
+
export function strippedShellEnv(env, secretNames = []) {
|
|
35
|
+
const declared = new Set(secretNames);
|
|
36
|
+
const out = {};
|
|
37
|
+
for (const [key, value] of Object.entries(env)) {
|
|
38
|
+
if (SHELL_STRIP_EXACT.has(key))
|
|
39
|
+
continue;
|
|
40
|
+
if (declared.has(key))
|
|
41
|
+
continue;
|
|
42
|
+
if (key.endsWith("_API_KEY") || key.endsWith("_AUTH_TOKEN"))
|
|
43
|
+
continue;
|
|
44
|
+
if (value !== undefined)
|
|
45
|
+
out[key] = value;
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tools-node",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "kiso coding tools for Node hosts
|
|
3
|
+
"version": "0.36.0",
|
|
4
|
+
"description": "kiso coding tools for Node hosts \u2014 read file, list directory, search text, write/edit file, shell command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./secret-env": {
|
|
13
|
+
"types": "./dist/secret-env.d.ts",
|
|
14
|
+
"default": "./dist/secret-env.js"
|
|
11
15
|
}
|
|
12
16
|
},
|
|
13
17
|
"files": [
|
|
@@ -21,7 +25,7 @@
|
|
|
21
25
|
"test": "vitest run"
|
|
22
26
|
},
|
|
23
27
|
"dependencies": {
|
|
24
|
-
"@vincemakes/kiso-core": "0.
|
|
28
|
+
"@vincemakes/kiso-core": "0.36.0"
|
|
25
29
|
},
|
|
26
30
|
"devDependencies": {
|
|
27
31
|
"@types/node": "^26.1.2",
|