@node9/proxy 2.28.0 → 2.28.1

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.
Files changed (3) hide show
  1. package/dist/cli.js +92 -17
  2. package/dist/cli.mjs +92 -17
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -57986,15 +57986,25 @@ var VISIBLE_ESCAPES = {
57986
57986
  function toVisibleEscape(c) {
57987
57987
  return VISIBLE_ESCAPES[c] ?? `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`;
57988
57988
  }
57989
+ var redact = (s) => redactText(s).result;
57990
+ var escapeUnsafe = (s) => s.replace(UNSAFE_CHARS, toVisibleEscape);
57989
57991
  function displaySafe(text) {
57990
- return redactText(text).result.replace(UNSAFE_CHARS, toVisibleEscape);
57992
+ return escapeUnsafe(redact(text));
57991
57993
  }
57992
57994
  var INPUT_PREVIEW_MAX = 80;
57993
57995
  function inputPreview(raw) {
57994
- const safe = displaySafe(raw);
57995
- return safe.length > INPUT_PREVIEW_MAX ? safe.slice(0, INPUT_PREVIEW_MAX - 3) + "\u2026" : safe;
57996
+ const redacted = redact(raw);
57997
+ const points = Array.from(redacted);
57998
+ const cut = points.length > INPUT_PREVIEW_MAX ? points.slice(0, INPUT_PREVIEW_MAX - 3).join("") + "\u2026" : redacted;
57999
+ return escapeUnsafe(cut);
58000
+ }
58001
+ var JSON_RAW_UNSAFE = /[\u007f-\u009f\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g;
58002
+ function toSafeJson(doc) {
58003
+ return JSON.stringify(doc, null, 2).replace(
58004
+ JSON_RAW_UNSAFE,
58005
+ (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
58006
+ );
57996
58007
  }
57997
- var redact = (s) => redactText(s).result;
57998
58008
  function buildExplainJson(result, rawInput) {
57999
58009
  return {
58000
58010
  schemaVersion: 1,
@@ -58009,7 +58019,11 @@ function buildExplainJson(result, rawInput) {
58009
58019
  detail: redact(s.detail),
58010
58020
  final: s.isFinal === true
58011
58021
  })),
58012
- waterfall: result.waterfall
58022
+ waterfall: result.waterfall.map((t) => ({
58023
+ ...t,
58024
+ ...t.path !== void 0 && { path: redact(t.path) },
58025
+ ...t.note !== void 0 && { note: redact(t.note) }
58026
+ }))
58013
58027
  };
58014
58028
  }
58015
58029
  function buildExplainJsonError(message) {
@@ -58935,6 +58949,52 @@ ${neutralizeMarkers(text)}
58935
58949
  ${f.footer}`;
58936
58950
  }
58937
58951
 
58952
+ // src/tool-output.ts
58953
+ init_dlp();
58954
+ var MAX_DEPTH3 = 8;
58955
+ function collectToolOutputText(toolResponse, opts = {}) {
58956
+ const maxBytes = opts.maxBytes ?? DLP_SCAN_LIMITS.maxStringBytes;
58957
+ const parts = [];
58958
+ let size = 0;
58959
+ let fields = 0;
58960
+ let truncated = false;
58961
+ const push = (s) => {
58962
+ if (s.length === 0) return true;
58963
+ const room = maxBytes - size;
58964
+ if (s.length > room) {
58965
+ if (room > 0) {
58966
+ parts.push(s.slice(0, room));
58967
+ fields++;
58968
+ }
58969
+ size = maxBytes;
58970
+ truncated = true;
58971
+ return false;
58972
+ }
58973
+ parts.push(s);
58974
+ fields++;
58975
+ size += s.length + 1;
58976
+ return true;
58977
+ };
58978
+ const walk = (v, depth) => {
58979
+ if (typeof v === "string") return push(v);
58980
+ if (depth >= MAX_DEPTH3 || v === null || typeof v !== "object") return true;
58981
+ const children = Array.isArray(v) ? v : Object.values(v);
58982
+ for (const child of children) if (!walk(child, depth + 1)) return false;
58983
+ return true;
58984
+ };
58985
+ walk(toolResponse, 0);
58986
+ return { text: parts.join("\n"), truncated, fields };
58987
+ }
58988
+ function shellOutputText(toolResponse) {
58989
+ if (toolResponse && typeof toolResponse === "object" && !Array.isArray(toolResponse)) {
58990
+ const r = toolResponse;
58991
+ if (typeof r.stdout === "string" || typeof r.stderr === "string") {
58992
+ return [r.stdout, r.stderr].filter((s) => typeof s === "string").join("\n");
58993
+ }
58994
+ }
58995
+ return collectToolOutputText(toolResponse).text;
58996
+ }
58997
+
58938
58998
  // src/cli/commands/log.ts
58939
58999
  init_hasher();
58940
59000
 
@@ -59080,7 +59140,7 @@ function registerLogCommand(program2) {
59080
59140
  }
59081
59141
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
59082
59142
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
59083
- const output = payload.tool_response?.output ?? "";
59143
+ const output = shellOutputText(payload.tool_response);
59084
59144
  if (bashCommand && output) {
59085
59145
  const testResult = detectTestResult(bashCommand, output);
59086
59146
  if (testResult) {
@@ -59132,10 +59192,24 @@ function registerLogCommand(program2) {
59132
59192
  }
59133
59193
  }
59134
59194
  {
59135
- const toolOutput = payload.tool_response?.output;
59195
+ const rawResponse = payload.tool_response;
59196
+ const shimOutput = rawResponse && typeof rawResponse === "object" && typeof rawResponse.output === "string" ? rawResponse.output : void 0;
59197
+ const collected = redactOutputMode ? {
59198
+ text: shimOutput ?? collectToolOutputText(rawResponse, { maxBytes: Number.MAX_SAFE_INTEGER }).text,
59199
+ truncated: false
59200
+ } : collectToolOutputText(rawResponse);
59201
+ const toolOutput = collected.text;
59202
+ if (collected.truncated) {
59203
+ appendToLog(HOOK_DEBUG_LOG, {
59204
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
59205
+ event: "post-tool-scan-truncated",
59206
+ tool,
59207
+ scannedBytes: toolOutput.length
59208
+ });
59209
+ }
59136
59210
  const inj = config.policy.injectionScan;
59137
59211
  const injectionOn = inj.enabled && !inj.allow.includes(tool);
59138
- if (typeof toolOutput === "string" && toolOutput.length > 0) {
59212
+ if (toolOutput.length > 0) {
59139
59213
  if (redactOutputMode) {
59140
59214
  const { result, found } = redactText(toolOutput);
59141
59215
  let out = result;
@@ -59196,7 +59270,7 @@ function registerLogCommand(program2) {
59196
59270
  } catch {
59197
59271
  }
59198
59272
  }
59199
- process.exit(0);
59273
+ process.stdout.write("", () => process.exit(0));
59200
59274
  };
59201
59275
  if (data) {
59202
59276
  await logPayload(data);
@@ -70739,7 +70813,7 @@ program.command("explain").description(
70739
70813
  'Machine-readable output (one JSON document; no "decision" field means failure)'
70740
70814
  ).action(async (tool, argsRaw, opts) => {
70741
70815
  const failJson = (message) => {
70742
- console.log(JSON.stringify(buildExplainJsonError(message), null, 2));
70816
+ console.log(toSafeJson(buildExplainJsonError(message)));
70743
70817
  process.exit(1);
70744
70818
  };
70745
70819
  let args = {};
@@ -70751,7 +70825,7 @@ program.command("explain").description(
70751
70825
  } catch {
70752
70826
  if (opts.json) failJson("Invalid JSON in [args]");
70753
70827
  console.error(import_chalk47.default.red(`
70754
- \u274C Invalid JSON: ${inputPreview(trimmed)}
70828
+ \u274C Invalid JSON: ${displaySafe(trimmed)}
70755
70829
  `));
70756
70830
  process.exit(1);
70757
70831
  }
@@ -70767,7 +70841,7 @@ program.command("explain").description(
70767
70841
  throw err2;
70768
70842
  }
70769
70843
  if (opts.json) {
70770
- console.log(JSON.stringify(buildExplainJson(result, argsRaw), null, 2));
70844
+ console.log(toSafeJson(buildExplainJson(result, argsRaw)));
70771
70845
  return;
70772
70846
  }
70773
70847
  console.log("");
@@ -70781,16 +70855,17 @@ program.command("explain").description(
70781
70855
  console.log(import_chalk47.default.bold("Config Sources (Waterfall):"));
70782
70856
  for (const tier of result.waterfall) {
70783
70857
  const num3 = import_chalk47.default.gray(` ${tier.tier}.`);
70784
- const label3 = tier.label.padEnd(16);
70858
+ const label3 = displaySafe(tier.label).padEnd(16);
70859
+ const tierNote = tier.note === void 0 ? void 0 : displaySafe(tier.note);
70785
70860
  let statusStr;
70786
70861
  if (tier.tier === 1) {
70787
- statusStr = import_chalk47.default.gray(tier.note ?? "");
70862
+ statusStr = import_chalk47.default.gray(tierNote ?? "");
70788
70863
  } else if (tier.status === "active") {
70789
- const loc = tier.path ? import_chalk47.default.gray(tier.path) : "";
70790
- const note = tier.note ? import_chalk47.default.gray(`(${tier.note})`) : "";
70864
+ const loc = tier.path ? import_chalk47.default.gray(displaySafe(tier.path)) : "";
70865
+ const note = tierNote ? import_chalk47.default.gray(`(${tierNote})`) : "";
70791
70866
  statusStr = import_chalk47.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
70792
70867
  } else {
70793
- statusStr = import_chalk47.default.gray("\u25CB " + (tier.note ?? "not found"));
70868
+ statusStr = import_chalk47.default.gray("\u25CB " + (tierNote ?? "not found"));
70794
70869
  }
70795
70870
  console.log(`${num3} ${import_chalk47.default.white(label3)} ${statusStr}`);
70796
70871
  }
package/dist/cli.mjs CHANGED
@@ -57968,15 +57968,25 @@ var VISIBLE_ESCAPES = {
57968
57968
  function toVisibleEscape(c) {
57969
57969
  return VISIBLE_ESCAPES[c] ?? `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`;
57970
57970
  }
57971
+ var redact = (s) => redactText(s).result;
57972
+ var escapeUnsafe = (s) => s.replace(UNSAFE_CHARS, toVisibleEscape);
57971
57973
  function displaySafe(text) {
57972
- return redactText(text).result.replace(UNSAFE_CHARS, toVisibleEscape);
57974
+ return escapeUnsafe(redact(text));
57973
57975
  }
57974
57976
  var INPUT_PREVIEW_MAX = 80;
57975
57977
  function inputPreview(raw) {
57976
- const safe = displaySafe(raw);
57977
- return safe.length > INPUT_PREVIEW_MAX ? safe.slice(0, INPUT_PREVIEW_MAX - 3) + "\u2026" : safe;
57978
+ const redacted = redact(raw);
57979
+ const points = Array.from(redacted);
57980
+ const cut = points.length > INPUT_PREVIEW_MAX ? points.slice(0, INPUT_PREVIEW_MAX - 3).join("") + "\u2026" : redacted;
57981
+ return escapeUnsafe(cut);
57982
+ }
57983
+ var JSON_RAW_UNSAFE = /[\u007f-\u009f\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g;
57984
+ function toSafeJson(doc) {
57985
+ return JSON.stringify(doc, null, 2).replace(
57986
+ JSON_RAW_UNSAFE,
57987
+ (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
57988
+ );
57978
57989
  }
57979
- var redact = (s) => redactText(s).result;
57980
57990
  function buildExplainJson(result, rawInput) {
57981
57991
  return {
57982
57992
  schemaVersion: 1,
@@ -57991,7 +58001,11 @@ function buildExplainJson(result, rawInput) {
57991
58001
  detail: redact(s.detail),
57992
58002
  final: s.isFinal === true
57993
58003
  })),
57994
- waterfall: result.waterfall
58004
+ waterfall: result.waterfall.map((t) => ({
58005
+ ...t,
58006
+ ...t.path !== void 0 && { path: redact(t.path) },
58007
+ ...t.note !== void 0 && { note: redact(t.note) }
58008
+ }))
57995
58009
  };
57996
58010
  }
57997
58011
  function buildExplainJsonError(message) {
@@ -58917,6 +58931,52 @@ ${neutralizeMarkers(text)}
58917
58931
  ${f.footer}`;
58918
58932
  }
58919
58933
 
58934
+ // src/tool-output.ts
58935
+ init_dlp();
58936
+ var MAX_DEPTH3 = 8;
58937
+ function collectToolOutputText(toolResponse, opts = {}) {
58938
+ const maxBytes = opts.maxBytes ?? DLP_SCAN_LIMITS.maxStringBytes;
58939
+ const parts = [];
58940
+ let size = 0;
58941
+ let fields = 0;
58942
+ let truncated = false;
58943
+ const push = (s) => {
58944
+ if (s.length === 0) return true;
58945
+ const room = maxBytes - size;
58946
+ if (s.length > room) {
58947
+ if (room > 0) {
58948
+ parts.push(s.slice(0, room));
58949
+ fields++;
58950
+ }
58951
+ size = maxBytes;
58952
+ truncated = true;
58953
+ return false;
58954
+ }
58955
+ parts.push(s);
58956
+ fields++;
58957
+ size += s.length + 1;
58958
+ return true;
58959
+ };
58960
+ const walk = (v, depth) => {
58961
+ if (typeof v === "string") return push(v);
58962
+ if (depth >= MAX_DEPTH3 || v === null || typeof v !== "object") return true;
58963
+ const children = Array.isArray(v) ? v : Object.values(v);
58964
+ for (const child of children) if (!walk(child, depth + 1)) return false;
58965
+ return true;
58966
+ };
58967
+ walk(toolResponse, 0);
58968
+ return { text: parts.join("\n"), truncated, fields };
58969
+ }
58970
+ function shellOutputText(toolResponse) {
58971
+ if (toolResponse && typeof toolResponse === "object" && !Array.isArray(toolResponse)) {
58972
+ const r = toolResponse;
58973
+ if (typeof r.stdout === "string" || typeof r.stderr === "string") {
58974
+ return [r.stdout, r.stderr].filter((s) => typeof s === "string").join("\n");
58975
+ }
58976
+ }
58977
+ return collectToolOutputText(toolResponse).text;
58978
+ }
58979
+
58920
58980
  // src/cli/commands/log.ts
58921
58981
  init_hasher();
58922
58982
 
@@ -59062,7 +59122,7 @@ function registerLogCommand(program2) {
59062
59122
  }
59063
59123
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
59064
59124
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
59065
- const output = payload.tool_response?.output ?? "";
59125
+ const output = shellOutputText(payload.tool_response);
59066
59126
  if (bashCommand && output) {
59067
59127
  const testResult = detectTestResult(bashCommand, output);
59068
59128
  if (testResult) {
@@ -59114,10 +59174,24 @@ function registerLogCommand(program2) {
59114
59174
  }
59115
59175
  }
59116
59176
  {
59117
- const toolOutput = payload.tool_response?.output;
59177
+ const rawResponse = payload.tool_response;
59178
+ const shimOutput = rawResponse && typeof rawResponse === "object" && typeof rawResponse.output === "string" ? rawResponse.output : void 0;
59179
+ const collected = redactOutputMode ? {
59180
+ text: shimOutput ?? collectToolOutputText(rawResponse, { maxBytes: Number.MAX_SAFE_INTEGER }).text,
59181
+ truncated: false
59182
+ } : collectToolOutputText(rawResponse);
59183
+ const toolOutput = collected.text;
59184
+ if (collected.truncated) {
59185
+ appendToLog(HOOK_DEBUG_LOG, {
59186
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
59187
+ event: "post-tool-scan-truncated",
59188
+ tool,
59189
+ scannedBytes: toolOutput.length
59190
+ });
59191
+ }
59118
59192
  const inj = config.policy.injectionScan;
59119
59193
  const injectionOn = inj.enabled && !inj.allow.includes(tool);
59120
- if (typeof toolOutput === "string" && toolOutput.length > 0) {
59194
+ if (toolOutput.length > 0) {
59121
59195
  if (redactOutputMode) {
59122
59196
  const { result, found } = redactText(toolOutput);
59123
59197
  let out = result;
@@ -59178,7 +59252,7 @@ function registerLogCommand(program2) {
59178
59252
  } catch {
59179
59253
  }
59180
59254
  }
59181
- process.exit(0);
59255
+ process.stdout.write("", () => process.exit(0));
59182
59256
  };
59183
59257
  if (data) {
59184
59258
  await logPayload(data);
@@ -70721,7 +70795,7 @@ program.command("explain").description(
70721
70795
  'Machine-readable output (one JSON document; no "decision" field means failure)'
70722
70796
  ).action(async (tool, argsRaw, opts) => {
70723
70797
  const failJson = (message) => {
70724
- console.log(JSON.stringify(buildExplainJsonError(message), null, 2));
70798
+ console.log(toSafeJson(buildExplainJsonError(message)));
70725
70799
  process.exit(1);
70726
70800
  };
70727
70801
  let args = {};
@@ -70733,7 +70807,7 @@ program.command("explain").description(
70733
70807
  } catch {
70734
70808
  if (opts.json) failJson("Invalid JSON in [args]");
70735
70809
  console.error(chalk47.red(`
70736
- \u274C Invalid JSON: ${inputPreview(trimmed)}
70810
+ \u274C Invalid JSON: ${displaySafe(trimmed)}
70737
70811
  `));
70738
70812
  process.exit(1);
70739
70813
  }
@@ -70749,7 +70823,7 @@ program.command("explain").description(
70749
70823
  throw err2;
70750
70824
  }
70751
70825
  if (opts.json) {
70752
- console.log(JSON.stringify(buildExplainJson(result, argsRaw), null, 2));
70826
+ console.log(toSafeJson(buildExplainJson(result, argsRaw)));
70753
70827
  return;
70754
70828
  }
70755
70829
  console.log("");
@@ -70763,16 +70837,17 @@ program.command("explain").description(
70763
70837
  console.log(chalk47.bold("Config Sources (Waterfall):"));
70764
70838
  for (const tier of result.waterfall) {
70765
70839
  const num3 = chalk47.gray(` ${tier.tier}.`);
70766
- const label3 = tier.label.padEnd(16);
70840
+ const label3 = displaySafe(tier.label).padEnd(16);
70841
+ const tierNote = tier.note === void 0 ? void 0 : displaySafe(tier.note);
70767
70842
  let statusStr;
70768
70843
  if (tier.tier === 1) {
70769
- statusStr = chalk47.gray(tier.note ?? "");
70844
+ statusStr = chalk47.gray(tierNote ?? "");
70770
70845
  } else if (tier.status === "active") {
70771
- const loc = tier.path ? chalk47.gray(tier.path) : "";
70772
- const note = tier.note ? chalk47.gray(`(${tier.note})`) : "";
70846
+ const loc = tier.path ? chalk47.gray(displaySafe(tier.path)) : "";
70847
+ const note = tierNote ? chalk47.gray(`(${tierNote})`) : "";
70773
70848
  statusStr = chalk47.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
70774
70849
  } else {
70775
- statusStr = chalk47.gray("\u25CB " + (tier.note ?? "not found"));
70850
+ statusStr = chalk47.gray("\u25CB " + (tierNote ?? "not found"));
70776
70851
  }
70777
70852
  console.log(`${num3} ${chalk47.white(label3)} ${statusStr}`);
70778
70853
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "2.28.0",
3
+ "version": "2.28.1",
4
4
  "description": "Access control for AI agents. Set what Claude Code, Codex, Gemini, Cursor and any MCP server are allowed to do, review risky actions before they run, and keep every action on the record.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",