@gotgenes/pi-permission-system 8.0.0 → 8.1.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/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [8.1.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v8.0.0...pi-permission-system-v8.1.0) (2026-05-31)
9
+
10
+
11
+ ### Features
12
+
13
+ * add toolInputPreviewMaxLength and toolTextSummaryMaxLength config fields ([#266](https://github.com/gotgenes/pi-packages/issues/266)) ([3a7dafb](https://github.com/gotgenes/pi-packages/commit/3a7dafbb0bb8534dabda7eeba6c4d35ba2e8708b))
14
+ * use configured preview limits in permission prompts ([#266](https://github.com/gotgenes/pi-packages/issues/266)) ([83e2829](https://github.com/gotgenes/pi-packages/commit/83e2829175a55f2f0436c742e19e3753ee171e47))
15
+
16
+
17
+ ### Documentation
18
+
19
+ * document configurable tool-preview length knobs ([#266](https://github.com/gotgenes/pi-packages/issues/266)) ([6d0b134](https://github.com/gotgenes/pi-packages/commit/6d0b134be4ef4c90ddf582b32058c3ec9d2eb13f))
20
+
8
21
  ## [8.0.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v7.4.1...pi-permission-system-v8.0.0) (2026-05-30)
9
22
 
10
23
 
@@ -5,6 +5,9 @@
5
5
  "permissionReviewLog": true,
6
6
  "yoloMode": false,
7
7
 
8
+ "toolInputPreviewMaxLength": 400,
9
+ "toolTextSummaryMaxLength": 120,
10
+
8
11
  "piInfrastructureReadPaths": [],
9
12
 
10
13
  "permission": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotgenes/pi-permission-system",
3
- "version": "8.0.0",
3
+ "version": "8.1.0",
4
4
  "description": "Permission enforcement extension for the Pi coding agent.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -29,6 +29,18 @@
29
29
  "type": "boolean",
30
30
  "default": false
31
31
  },
32
+ "toolInputPreviewMaxLength": {
33
+ "description": "Maximum character length of the inline-JSON tool-input preview shown in permission prompts. Omit to use the default (200). Set to a large value to disable truncation.",
34
+ "markdownDescription": "Maximum character length of the inline-JSON tool-input preview shown in permission prompts.\n\nOmit to use the default (200). Set to a large value (e.g. `10000`) to effectively disable truncation and see the full input.",
35
+ "type": "integer",
36
+ "minimum": 1
37
+ },
38
+ "toolTextSummaryMaxLength": {
39
+ "description": "Maximum character length of inline pattern/path summaries (e.g. grep patterns, find globs, ls paths) in permission prompts. Omit to use the default (80).",
40
+ "markdownDescription": "Maximum character length of inline pattern/path summaries (e.g. grep patterns, find globs, ls paths) shown in permission prompts.\n\nOmit to use the default (80). Increase this when working with long regexes or deep paths that are being cut off.",
41
+ "type": "integer",
42
+ "minimum": 1
43
+ },
32
44
  "piInfrastructureReadPaths": {
33
45
  "description": "Additional directories to auto-allow for reads as Pi infrastructure, bypassing the external_directory gate. Supports ~ expansion and wildcard patterns (* and ?).",
34
46
  "markdownDescription": "Additional directories to auto-allow for reads as Pi infrastructure, bypassing the `external_directory` gate.\n\nThe extension auto-discovers the global node_modules root (walks up from the extension's install path; falls back to `npm root -g` from a dev checkout), `agentDir`, `agentDir/git`, and project-local `.pi/npm/` and `.pi/git/`. Add entries here for edge cases where auto-discovery is insufficient (e.g. custom `npmCommand` pointing to pnpm).\n\nSupports `~`/`$HOME` expansion. Entries may be plain directory prefixes or wildcard patterns using `*` (matches any characters, including `/`) and `?` (matches exactly one character). `**` and `*` are equivalent — both cross directory boundaries.",
@@ -12,6 +12,10 @@ export interface PermissionSystemExtensionConfig {
12
12
  yoloMode: boolean;
13
13
  /** Additional directories to auto-allow for reads as Pi infrastructure. */
14
14
  piInfrastructureReadPaths?: string[];
15
+ /** Max length of the inline-JSON input preview shown in permission prompts. Defaults to 200. */
16
+ toolInputPreviewMaxLength?: number;
17
+ /** Max length of inline pattern/path summaries (grep/find/ls) in permission prompts. Defaults to 80. */
18
+ toolTextSummaryMaxLength?: number;
15
19
  }
16
20
 
17
21
  export const DEFAULT_EXTENSION_CONFIG: PermissionSystemExtensionConfig = {
@@ -42,6 +46,13 @@ export function detectMisplacedPermissionKeys(
42
46
  return Object.keys(raw).filter((key) => PERMISSION_POLICY_KEYS.has(key));
43
47
  }
44
48
 
49
+ /** Returns `raw` if it is a positive integer; otherwise `undefined`. */
50
+ export function normalizeOptionalPositiveInt(raw: unknown): number | undefined {
51
+ return typeof raw === "number" && Number.isInteger(raw) && raw > 0
52
+ ? raw
53
+ : undefined;
54
+ }
55
+
45
56
  export function normalizePermissionSystemConfig(
46
57
  raw: unknown,
47
58
  ): PermissionSystemExtensionConfig {
@@ -60,6 +71,18 @@ export function normalizePermissionSystemConfig(
60
71
  if (piInfrastructureReadPaths !== undefined) {
61
72
  result.piInfrastructureReadPaths = piInfrastructureReadPaths;
62
73
  }
74
+ const toolInputPreviewMaxLength = normalizeOptionalPositiveInt(
75
+ record.toolInputPreviewMaxLength,
76
+ );
77
+ if (toolInputPreviewMaxLength !== undefined) {
78
+ result.toolInputPreviewMaxLength = toolInputPreviewMaxLength;
79
+ }
80
+ const toolTextSummaryMaxLength = normalizeOptionalPositiveInt(
81
+ record.toolTextSummaryMaxLength,
82
+ );
83
+ if (toolTextSummaryMaxLength !== undefined) {
84
+ result.toolTextSummaryMaxLength = toolTextSummaryMaxLength;
85
+ }
63
86
  return result;
64
87
  }
65
88
 
@@ -1,7 +1,7 @@
1
1
  import { getPathBearingToolPath, PATH_BEARING_TOOLS } from "#src/path-utils";
2
2
  import { suggestSessionPattern } from "#src/pattern-suggest";
3
3
  import { formatAskPrompt } from "#src/permission-prompts";
4
- import { getPermissionLogContext } from "#src/tool-input-preview";
4
+ import type { ToolPreviewFormatter } from "#src/tool-preview-formatter";
5
5
  import type { PermissionCheckResult } from "#src/types";
6
6
  import type { GateDescriptor } from "./descriptor";
7
7
  import { deriveDecisionValue } from "./helpers";
@@ -31,8 +31,9 @@ function deriveSuggestionValue(
31
31
  export function describeToolGate(
32
32
  tcc: ToolCallContext,
33
33
  check: PermissionCheckResult,
34
+ formatter: ToolPreviewFormatter,
34
35
  ): GateDescriptor {
35
- const permissionLogContext = getPermissionLogContext(
36
+ const permissionLogContext = formatter.getPermissionLogContext(
36
37
  check,
37
38
  tcc.input,
38
39
  PATH_BEARING_TOOLS,
@@ -48,6 +49,7 @@ export function describeToolGate(
48
49
  check,
49
50
  tcc.agentName ?? undefined,
50
51
  tcc.input,
52
+ formatter,
51
53
  );
52
54
 
53
55
  return {
@@ -16,6 +16,10 @@ import {
16
16
  formatUnknownToolReason,
17
17
  } from "#src/permission-prompts";
18
18
  import type { PermissionSession } from "#src/permission-session";
19
+ import {
20
+ resolveToolPreviewLimits,
21
+ ToolPreviewFormatter,
22
+ } from "#src/tool-preview-formatter";
19
23
  import {
20
24
  checkRequestedToolRegistration,
21
25
  getToolNameFromValue,
@@ -23,7 +27,7 @@ import {
23
27
  } from "#src/tool-registry";
24
28
  import { describeBashExternalDirectoryGate } from "./gates/bash-external-directory";
25
29
  import { describeBashPathGate } from "./gates/bash-path";
26
- import type { GateRunnerDeps } from "./gates/descriptor";
30
+ import type { GateResult, GateRunnerDeps } from "./gates/descriptor";
27
31
  import { isGateBypass } from "./gates/descriptor";
28
32
  import { describeExternalDirectoryGate } from "./gates/external-directory";
29
33
  import { describePathGate } from "./gates/path";
@@ -58,30 +62,13 @@ export class PermissionGateHandler {
58
62
  ): Promise<{ block?: true; reason?: string }> {
59
63
  this.session.activate(ctx);
60
64
 
61
- const agentName = this.session.resolveAgentName(ctx);
62
- const toolName = getToolNameFromValue(event);
63
-
64
- if (!toolName) {
65
- return { block: true, reason: formatMissingToolNameReason() };
66
- }
67
-
68
- const registrationCheck = checkRequestedToolRegistration(
69
- toolName,
70
- this.toolRegistry.getAll(),
71
- );
72
- if (registrationCheck.status === "missing-tool-name") {
73
- return { block: true, reason: formatMissingToolNameReason() };
65
+ const validation = validateRequestedTool(event, this.toolRegistry.getAll());
66
+ if (validation.status === "block") {
67
+ return { block: true, reason: validation.reason };
74
68
  }
69
+ const toolName = validation.toolName;
75
70
 
76
- if (registrationCheck.status === "unregistered") {
77
- return {
78
- block: true,
79
- reason: formatUnknownToolReason(
80
- registrationCheck.requestedToolName,
81
- registrationCheck.availableToolNames,
82
- ),
83
- };
84
- }
71
+ const agentName = this.session.resolveAgentName(ctx);
85
72
 
86
73
  const input = getEventInput(event);
87
74
  const toolCallId =
@@ -126,136 +113,78 @@ export class PermissionGateHandler {
126
113
  promptPermission,
127
114
  };
128
115
 
129
- // ── Skill-read gate (descriptor + runner) ───────────────────────────────
130
- const skillDescriptor = describeSkillReadGate(tcc, () =>
131
- this.session.getActiveSkillEntries(),
132
- );
133
- if (skillDescriptor) {
134
- const skillResult = await runGateCheck(
135
- skillDescriptor,
116
+ // ── Unified gate executor ─────────────────────────────────────────────
117
+ // Handles the bypass log/emit branch, calls runGateCheck for descriptors,
118
+ // and returns a block result or undefined (allow / no-op).
119
+ const runGate = async (
120
+ gate: GateResult,
121
+ ): Promise<{ block: true; reason: string } | undefined> => {
122
+ if (!gate) {
123
+ return undefined;
124
+ }
125
+ if (isGateBypass(gate)) {
126
+ if (gate.log) {
127
+ writeReviewLog(gate.log.event, gate.log.details);
128
+ }
129
+ if (gate.decision) {
130
+ emitDecision(gate.decision);
131
+ }
132
+ return undefined;
133
+ }
134
+ const result = await runGateCheck(
135
+ gate,
136
136
  tcc.agentName,
137
137
  tcc.toolCallId,
138
138
  runnerDeps,
139
139
  );
140
- if (skillResult.action === "block") {
141
- return { block: true, reason: skillResult.reason };
142
- }
143
- }
140
+ return result.action === "block"
141
+ ? { block: true, reason: result.reason }
142
+ : undefined;
143
+ };
144
144
 
145
- // ── Path gate for tools (descriptor + runner) ────────────────────────────
146
- const pathDesc = describePathGate(tcc, checkPermission, getSessionRuleset);
147
- if (pathDesc) {
148
- if (isGateBypass(pathDesc)) {
149
- if (pathDesc.log) {
150
- writeReviewLog(pathDesc.log.event, pathDesc.log.details);
151
- }
152
- } else {
153
- const pathResult = await runGateCheck(
154
- pathDesc,
155
- tcc.agentName,
156
- tcc.toolCallId,
157
- runnerDeps,
158
- );
159
- if (pathResult.action === "block") {
160
- return { block: true, reason: pathResult.reason };
161
- }
162
- }
163
- }
145
+ const formatter = new ToolPreviewFormatter(
146
+ resolveToolPreviewLimits(this.session.config),
147
+ );
164
148
 
165
- // ── External-directory gate (descriptor + runner) ────────────────────────
149
+ // ── Ordered gate pipeline ─────────────────────────────────────────────
150
+ // infraDirs is computed once, outside the pipeline, exactly as before.
166
151
  const infraDirs = [
167
152
  ...this.session.getInfrastructureDirs(),
168
153
  ...this.session.getInfrastructureReadPaths(),
169
154
  ];
170
- const extDirDesc = describeExternalDirectoryGate(tcc, infraDirs);
171
- if (extDirDesc) {
172
- if (isGateBypass(extDirDesc)) {
173
- if (extDirDesc.log) {
174
- writeReviewLog(extDirDesc.log.event, extDirDesc.log.details);
175
- }
176
- if (extDirDesc.decision) {
177
- emitDecision(extDirDesc.decision);
178
- }
179
- } else {
180
- const extDirResult = await runGateCheck(
181
- extDirDesc,
182
- tcc.agentName,
183
- tcc.toolCallId,
184
- runnerDeps,
185
- );
186
- if (extDirResult.action === "block") {
187
- return { block: true, reason: extDirResult.reason };
188
- }
189
- }
190
- }
191
155
 
192
- // ── Bash external-directory gate (descriptor + runner) ───────────────────
193
- const bashExtDesc = await describeBashExternalDirectoryGate(
194
- tcc,
195
- checkPermission,
196
- getSessionRuleset,
197
- );
198
- if (bashExtDesc) {
199
- if (isGateBypass(bashExtDesc)) {
200
- if (bashExtDesc.log) {
201
- writeReviewLog(bashExtDesc.log.event, bashExtDesc.log.details);
202
- }
203
- } else {
204
- const bashExtResult = await runGateCheck(
205
- bashExtDesc,
206
- tcc.agentName,
207
- tcc.toolCallId,
208
- runnerDeps,
156
+ const gateProducers: Array<() => GateResult | Promise<GateResult>> = [
157
+ () =>
158
+ describeSkillReadGate(tcc, () => this.session.getActiveSkillEntries()),
159
+ () => describePathGate(tcc, checkPermission, getSessionRuleset),
160
+ () => describeExternalDirectoryGate(tcc, infraDirs),
161
+ () =>
162
+ describeBashExternalDirectoryGate(
163
+ tcc,
164
+ checkPermission,
165
+ getSessionRuleset,
166
+ ),
167
+ () => describeBashPathGate(tcc, checkPermission, getSessionRuleset),
168
+ () => {
169
+ const toolCheck = checkPermission(
170
+ tcc.toolName,
171
+ tcc.input,
172
+ tcc.agentName ?? undefined,
173
+ getSessionRuleset(),
209
174
  );
210
- if (bashExtResult.action === "block") {
211
- return { block: true, reason: bashExtResult.reason };
212
- }
213
- }
214
- }
175
+ const toolDescriptor = describeToolGate(tcc, toolCheck, formatter);
176
+ toolDescriptor.preCheck = toolCheck;
177
+ return toolDescriptor;
178
+ },
179
+ ];
215
180
 
216
- // ── Bash path gate (descriptor + runner) ────────────────────────────────
217
- const bashPathDesc = await describeBashPathGate(
218
- tcc,
219
- checkPermission,
220
- getSessionRuleset,
221
- );
222
- if (bashPathDesc) {
223
- if (isGateBypass(bashPathDesc)) {
224
- if (bashPathDesc.log) {
225
- writeReviewLog(bashPathDesc.log.event, bashPathDesc.log.details);
226
- }
227
- } else {
228
- const bashPathResult = await runGateCheck(
229
- bashPathDesc,
230
- tcc.agentName,
231
- tcc.toolCallId,
232
- runnerDeps,
233
- );
234
- if (bashPathResult.action === "block") {
235
- return { block: true, reason: bashPathResult.reason };
236
- }
181
+ for (const produce of gateProducers) {
182
+ const blocked = await runGate(await produce());
183
+ if (blocked) {
184
+ return blocked;
237
185
  }
238
186
  }
239
187
 
240
- // ── Normal tool permission gate (descriptor + runner) ────────────────────
241
- const toolCheck = checkPermission(
242
- tcc.toolName,
243
- tcc.input,
244
- tcc.agentName ?? undefined,
245
- getSessionRuleset(),
246
- );
247
- const toolDescriptor = describeToolGate(tcc, toolCheck);
248
- toolDescriptor.preCheck = toolCheck;
249
- const toolResult = await runGateCheck(
250
- toolDescriptor,
251
- tcc.agentName,
252
- tcc.toolCallId,
253
- runnerDeps,
254
- );
255
- if (toolResult.action === "block") {
256
- return { block: true, reason: toolResult.reason };
257
- }
258
-
259
188
  return {};
260
189
  }
261
190
 
@@ -352,7 +281,46 @@ export class PermissionGateHandler {
352
281
  }
353
282
  }
354
283
 
355
- // ── Pure helpers (re-exported from original modules) ──────────────────────
284
+ // ── Pure helpers ─────────────────────────────────────────────────────────
285
+
286
+ /** Discriminated result of validating a tool-call event's name and registration. */
287
+ export type RequestedToolValidation =
288
+ | { status: "ok"; toolName: string }
289
+ | { status: "block"; reason: string };
290
+
291
+ /**
292
+ * Validate the tool name from a raw event against the registered tool list.
293
+ *
294
+ * Composes `getToolNameFromValue` + `checkRequestedToolRegistration` + the
295
+ * two reason formatters and returns a discriminated result so `handleToolCall`
296
+ * reads as a straight validate → proceed path without nested early-returns.
297
+ *
298
+ * Returns the **raw** tool name (not the normalised form) so that
299
+ * `ToolCallContext.toolName` stays identical to the pre-extraction behaviour.
300
+ */
301
+ export function validateRequestedTool(
302
+ event: unknown,
303
+ availableTools: readonly unknown[],
304
+ ): RequestedToolValidation {
305
+ const toolName = getToolNameFromValue(event);
306
+ if (!toolName) {
307
+ return { status: "block", reason: formatMissingToolNameReason() };
308
+ }
309
+ const check = checkRequestedToolRegistration(toolName, availableTools);
310
+ if (check.status === "missing-tool-name") {
311
+ return { status: "block", reason: formatMissingToolNameReason() };
312
+ }
313
+ if (check.status === "unregistered") {
314
+ return {
315
+ status: "block",
316
+ reason: formatUnknownToolReason(
317
+ check.requestedToolName,
318
+ check.availableToolNames,
319
+ ),
320
+ };
321
+ }
322
+ return { status: "ok", toolName };
323
+ }
356
324
 
357
325
  /**
358
326
  * Extract the tool input from an event, checking both `input` and `arguments`
@@ -1,5 +1,5 @@
1
1
  import type { SkillPromptEntry } from "./skill-prompt-sanitizer";
2
- import { formatToolInputForPrompt } from "./tool-input-preview";
2
+ import type { ToolPreviewFormatter } from "./tool-preview-formatter";
3
3
  import type { PermissionCheckResult } from "./types";
4
4
 
5
5
  // NOTE: formatDenyReason, formatUserDeniedReason, and
@@ -31,6 +31,7 @@ export function formatAskPrompt(
31
31
  result: PermissionCheckResult,
32
32
  agentName?: string,
33
33
  input?: unknown,
34
+ formatter?: ToolPreviewFormatter,
34
35
  ): string {
35
36
  const subject = agentName ? `Agent '${agentName}'` : "Current agent";
36
37
 
@@ -51,7 +52,9 @@ export function formatAskPrompt(
51
52
  const patternInfo = result.matchedPattern
52
53
  ? ` (matched '${result.matchedPattern}')`
53
54
  : "";
54
- const inputPreview = formatToolInputForPrompt(result.toolName, input);
55
+ const inputPreview = formatter
56
+ ? formatter.formatToolInputForPrompt(result.toolName, input)
57
+ : "";
55
58
  const inputSuffix = inputPreview ? ` ${inputPreview}` : "";
56
59
  return `${subject} requested tool '${result.toolName}'${patternInfo}${inputSuffix}. Allow this call?`;
57
60
  }
@@ -1,6 +1,5 @@
1
1
  import { getNonEmptyString, toRecord } from "./common";
2
2
  import { safeJsonStringify } from "./logging";
3
- import type { PermissionCheckResult } from "./types";
4
3
 
5
4
  export const TOOL_INPUT_PREVIEW_MAX_LENGTH = 200;
6
5
  export const TOOL_INPUT_LOG_PREVIEW_MAX_LENGTH = 1000;
@@ -10,14 +9,6 @@ export function truncateInlineText(value: string, maxLength: number): string {
10
9
  return value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;
11
10
  }
12
11
 
13
- export function sanitizeInlineText(
14
- value: string,
15
- maxLength = TOOL_TEXT_SUMMARY_MAX_LENGTH,
16
- ): string {
17
- const normalized = value.replace(/\s+/g, " ").trim();
18
- return normalized ? truncateInlineText(normalized, maxLength) : "empty text";
19
- }
20
-
21
12
  export function countTextLines(value: string): number {
22
13
  if (!value) {
23
14
  return 0;
@@ -95,30 +86,6 @@ export function formatReadInputForPrompt(
95
86
  return parts.length > 0 ? `for ${parts.join(", ")}` : "";
96
87
  }
97
88
 
98
- export function formatSearchInputForPrompt(
99
- toolName: string,
100
- input: Record<string, unknown>,
101
- ): string {
102
- const parts: string[] = [];
103
- const path = getPromptPath(input);
104
- const pattern = getNonEmptyString(input.pattern);
105
- const glob = getNonEmptyString(input.glob);
106
-
107
- if (pattern) {
108
- parts.push(`pattern '${sanitizeInlineText(pattern)}'`);
109
- }
110
- if (glob) {
111
- parts.push(`glob '${sanitizeInlineText(glob)}'`);
112
- }
113
- if (path) {
114
- parts.push(`path '${path}'`);
115
- } else if (toolName === "find" || toolName === "grep" || toolName === "ls") {
116
- parts.push("current working directory");
117
- }
118
-
119
- return parts.length > 0 ? `for ${parts.join(", ")}` : "";
120
- }
121
-
122
89
  export function serializeToolInputPreview(input: unknown): string {
123
90
  const serialized = safeJsonStringify(input);
124
91
  if (!serialized || serialized === "{}" || serialized === "null") {
@@ -127,86 +94,3 @@ export function serializeToolInputPreview(input: unknown): string {
127
94
 
128
95
  return serialized.replace(/\s+/g, " ").trim();
129
96
  }
130
-
131
- export function formatJsonInputForPrompt(input: unknown): string {
132
- const inline = serializeToolInputPreview(input);
133
- return inline
134
- ? `with input ${truncateInlineText(inline, TOOL_INPUT_PREVIEW_MAX_LENGTH)}`
135
- : "";
136
- }
137
-
138
- export function formatToolInputForPrompt(
139
- toolName: string,
140
- input: unknown,
141
- ): string {
142
- const inputRecord = toRecord(input);
143
-
144
- switch (toolName) {
145
- case "edit":
146
- return formatEditInputForPrompt(inputRecord);
147
- case "write":
148
- return formatWriteInputForPrompt(inputRecord);
149
- case "read":
150
- return formatReadInputForPrompt(inputRecord);
151
- case "find":
152
- case "grep":
153
- case "ls":
154
- return formatSearchInputForPrompt(toolName, inputRecord);
155
- default:
156
- return formatJsonInputForPrompt(input);
157
- }
158
- }
159
-
160
- export function formatGenericToolInputForLog(
161
- input: unknown,
162
- ): string | undefined {
163
- const inline = serializeToolInputPreview(input);
164
- return inline
165
- ? `input ${truncateInlineText(inline, TOOL_INPUT_LOG_PREVIEW_MAX_LENGTH)}`
166
- : undefined;
167
- }
168
-
169
- export function getToolInputPreviewForLog(
170
- result: PermissionCheckResult,
171
- input: unknown,
172
- pathBearingTools: ReadonlySet<string>,
173
- ): string | undefined {
174
- if (
175
- result.toolName === "bash" ||
176
- result.toolName === "mcp" ||
177
- result.source === "mcp"
178
- ) {
179
- return undefined;
180
- }
181
-
182
- if (pathBearingTools.has(result.toolName)) {
183
- const inputPreview = formatToolInputForPrompt(result.toolName, input);
184
- return inputPreview
185
- ? truncateInlineText(inputPreview, TOOL_INPUT_LOG_PREVIEW_MAX_LENGTH)
186
- : undefined;
187
- }
188
-
189
- return formatGenericToolInputForLog(input);
190
- }
191
-
192
- export function getPermissionLogContext(
193
- result: PermissionCheckResult,
194
- input: unknown,
195
- pathBearingTools: ReadonlySet<string>,
196
- ): {
197
- command?: string;
198
- target?: string;
199
- toolInputPreview?: string;
200
- origin?: string;
201
- } {
202
- return {
203
- command: result.command,
204
- target: result.target,
205
- toolInputPreview: getToolInputPreviewForLog(
206
- result,
207
- input,
208
- pathBearingTools,
209
- ),
210
- origin: result.origin,
211
- };
212
- }