@vincemakes/kiso-tools-node 0.24.5 → 0.25.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 +8 -1
- package/dist/index.js +33 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -91,8 +91,15 @@ export interface WorkspaceToolsOptions {
|
|
|
91
91
|
* STRIPPED — a shell command must not inherit the agent's API keys (a
|
|
92
92
|
* nested kiso would hit the REAL provider and blow up faux e2e runs;
|
|
93
93
|
* the keys are an exposure surface for any command).
|
|
94
|
+
*
|
|
95
|
+
* ADR-0031 Amendment 1: a RECORD is the third shape — the STRIPPED
|
|
96
|
+
* environment plus these explicit entries, the entries winning (the
|
|
97
|
+
* MCP surface's decision 2, applied here). An embedding host injects
|
|
98
|
+
* what its tools need without a temp file and without opening the
|
|
99
|
+
* whole environment; an entry may deliberately re-add a stripped
|
|
100
|
+
* name — explicit beats the heuristic, as it does for MCP servers.
|
|
94
101
|
*/
|
|
95
|
-
readonly shellEnv?: "inherit"
|
|
102
|
+
readonly shellEnv?: "inherit" | Readonly<Record<string, string>>;
|
|
96
103
|
/**
|
|
97
104
|
* DC-54 — the bounds that keep a tool call finite. Every field is
|
|
98
105
|
* optional and defaults to the constant beside it; a host embedding
|
package/dist/index.js
CHANGED
|
@@ -803,6 +803,7 @@ export function writeFileTool(opts) {
|
|
|
803
803
|
promptSnippet: "write_file — create or replace a whole file",
|
|
804
804
|
promptGuidelines: ["write/edit: cite the file's latest revision as expectedRevision; each successful mutation returns the next one; use \"absent\" only to create"],
|
|
805
805
|
execute: async ({ path, content, expectedRevision: citedRevision }) => {
|
|
806
|
+
const maxReadBytes = opts.limits?.readMaxFileBytes ?? READ_MAX_FILE_BYTES;
|
|
806
807
|
// WR-1-F2: normalize every plausible copy of the token FIRST —
|
|
807
808
|
// tolerance in the reader, strictness in the comparison.
|
|
808
809
|
const expectedRevision = citedRevision === undefined ? undefined : normalizeRevision(citedRevision);
|
|
@@ -838,6 +839,19 @@ export function writeFileTool(opts) {
|
|
|
838
839
|
if (!exists) {
|
|
839
840
|
return precondition(`write_file: ${path} no longer exists — pass expectedRevision:"absent" to create it`);
|
|
840
841
|
}
|
|
842
|
+
// DC-54 owed (R14) — the ceiling, before the read.
|
|
843
|
+
//
|
|
844
|
+
// `read_file` got this bound in 0.24.5; these two did not,
|
|
845
|
+
// and they read the WHOLE file to compute a revision BEFORE
|
|
846
|
+
// the comparison that would reject the call — so the freeze
|
|
847
|
+
// happened on the way to the refusal rather than instead of
|
|
848
|
+
// it. Same ceiling, same precondition shape, same reason: a
|
|
849
|
+
// revision over a prefix could never match, so there is
|
|
850
|
+
// nothing to compute and nothing to compare.
|
|
851
|
+
const wSize = statSync(full).size;
|
|
852
|
+
if (wSize > maxReadBytes) {
|
|
853
|
+
return precondition(`write_file: ${path} is ${mib(wSize)} — too large to read (ceiling ${mib(maxReadBytes)}); use shell with sed/head to take a range`);
|
|
854
|
+
}
|
|
841
855
|
const current = contentRevision(readFileSync(full));
|
|
842
856
|
if (current !== expectedRevision) {
|
|
843
857
|
return precondition(`write_file: ${path} changed since ${expectedRevision} — read it again and cite its [rev:…] line, then re-apply the change`);
|
|
@@ -937,6 +951,7 @@ export function editFileTool(opts) {
|
|
|
937
951
|
promptSnippet: "edit_file — replace an exact old_string block (never rewrite whole files)",
|
|
938
952
|
promptGuidelines: ["write/edit: cite the file's latest revision as expectedRevision; each successful mutation returns the next one; use \"absent\" only to create"],
|
|
939
953
|
execute: async ({ path, search, replace, edits, expectedRevision: citedRevision }) => {
|
|
954
|
+
const maxReadBytes = opts.limits?.readMaxFileBytes ?? READ_MAX_FILE_BYTES;
|
|
940
955
|
// WR-1-F2: normalize the citation (see write_file).
|
|
941
956
|
const expectedRevision = citedRevision === undefined ? undefined : normalizeRevision(citedRevision);
|
|
942
957
|
// WR-1E2 — the form XOR (the draft-07 subset has no oneOf; the
|
|
@@ -983,6 +998,19 @@ export function editFileTool(opts) {
|
|
|
983
998
|
// what was edited (the external validation→replacement window
|
|
984
999
|
// remains and is the narrowed claim). Staleness reports BEFORE
|
|
985
1000
|
// the pattern search: the truer cause first.
|
|
1001
|
+
// DC-54 owed (R14) — the ceiling, before the read.
|
|
1002
|
+
//
|
|
1003
|
+
// `read_file` got this bound in 0.24.5; these two did not,
|
|
1004
|
+
// and they read the WHOLE file to compute a revision BEFORE
|
|
1005
|
+
// the comparison that would reject the call — so the freeze
|
|
1006
|
+
// happened on the way to the refusal rather than instead of
|
|
1007
|
+
// it. Same ceiling, same precondition shape, same reason: a
|
|
1008
|
+
// revision over a prefix could never match, so there is
|
|
1009
|
+
// nothing to compute and nothing to compare.
|
|
1010
|
+
const eSize = statSync(full).size;
|
|
1011
|
+
if (eSize > maxReadBytes) {
|
|
1012
|
+
return precondition(`edit_file: ${path} is ${mib(eSize)} — too large to read (ceiling ${mib(maxReadBytes)}); use shell with sed/head to take a range`);
|
|
1013
|
+
}
|
|
986
1014
|
const bytes = readFileSync(full);
|
|
987
1015
|
const current = contentRevision(bytes);
|
|
988
1016
|
if (current !== expectedRevision) {
|
|
@@ -1105,13 +1133,16 @@ export function shellTool(opts) {
|
|
|
1105
1133
|
// not just the outer shell (Area 4). cwd is the workspace.
|
|
1106
1134
|
// bootstrap #3 (finding #7): the shell child NEVER inherits kiso's own
|
|
1107
1135
|
// provider credentials by default — only the explicit
|
|
1108
|
-
// shellEnv: "inherit" opt-in keeps them.
|
|
1136
|
+
// shellEnv: "inherit" opt-in keeps them. A record (ADR-0031
|
|
1137
|
+
// Amendment 1) rides on the STRIPPED base and wins per key.
|
|
1109
1138
|
const child = spawn(command, {
|
|
1110
1139
|
shell: true,
|
|
1111
1140
|
detached: true,
|
|
1112
1141
|
cwd: opts.workspaceRoot,
|
|
1113
1142
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1114
|
-
env: opts.shellEnv === "inherit"
|
|
1143
|
+
env: opts.shellEnv === "inherit"
|
|
1144
|
+
? process.env
|
|
1145
|
+
: { ...strippedShellEnv(process.env), ...(opts.shellEnv ?? {}) },
|
|
1115
1146
|
});
|
|
1116
1147
|
let stdout = "";
|
|
1117
1148
|
let stderr = "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tools-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "kiso coding tools for Node hosts — read file, list directory, search text, write/edit file, shell command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"test": "vitest run"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@vincemakes/kiso-core": "0.
|
|
24
|
+
"@vincemakes/kiso-core": "0.25.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^26.1.2",
|