@dexto/tools-process 1.5.8 → 1.6.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 (55) hide show
  1. package/dist/bash-exec-tool.cjs +40 -23
  2. package/dist/bash-exec-tool.d.ts +27 -9
  3. package/dist/bash-exec-tool.d.ts.map +1 -0
  4. package/dist/bash-exec-tool.js +43 -23
  5. package/dist/bash-output-tool.cjs +13 -5
  6. package/dist/bash-output-tool.d.ts +13 -8
  7. package/dist/bash-output-tool.d.ts.map +1 -0
  8. package/dist/bash-output-tool.js +13 -5
  9. package/dist/command-pattern-utils.cjs +83 -0
  10. package/dist/command-pattern-utils.d.ts +29 -0
  11. package/dist/command-pattern-utils.d.ts.map +1 -0
  12. package/dist/command-pattern-utils.js +56 -0
  13. package/dist/command-pattern-utils.test.cjs +80 -0
  14. package/dist/command-pattern-utils.test.d.ts +2 -0
  15. package/dist/command-pattern-utils.test.d.ts.map +1 -0
  16. package/dist/command-pattern-utils.test.js +83 -0
  17. package/dist/command-validator.d.ts +5 -8
  18. package/dist/command-validator.d.ts.map +1 -0
  19. package/dist/error-codes.d.ts +2 -3
  20. package/dist/error-codes.d.ts.map +1 -0
  21. package/dist/errors.d.ts +4 -7
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/index.cjs +6 -3
  24. package/dist/index.d.cts +485 -11
  25. package/dist/index.d.ts +10 -4
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +4 -2
  28. package/dist/kill-process-tool.cjs +13 -5
  29. package/dist/kill-process-tool.d.ts +13 -8
  30. package/dist/kill-process-tool.d.ts.map +1 -0
  31. package/dist/kill-process-tool.js +13 -5
  32. package/dist/process-service.cjs +11 -1
  33. package/dist/process-service.d.ts +12 -11
  34. package/dist/process-service.d.ts.map +1 -0
  35. package/dist/process-service.js +11 -1
  36. package/dist/{tool-provider.cjs → tool-factory-config.cjs} +6 -48
  37. package/dist/{tool-provider.d.ts → tool-factory-config.d.ts} +8 -27
  38. package/dist/tool-factory-config.d.ts.map +1 -0
  39. package/dist/{tool-provider.js → tool-factory-config.js} +2 -44
  40. package/dist/tool-factory.cjs +89 -0
  41. package/dist/tool-factory.d.ts +4 -0
  42. package/dist/tool-factory.d.ts.map +1 -0
  43. package/dist/tool-factory.js +65 -0
  44. package/dist/types.d.ts +9 -10
  45. package/dist/types.d.ts.map +1 -0
  46. package/package.json +5 -4
  47. package/dist/bash-exec-tool.d.cts +0 -17
  48. package/dist/bash-output-tool.d.cts +0 -16
  49. package/dist/command-validator.d.cts +0 -52
  50. package/dist/error-codes.d.cts +0 -26
  51. package/dist/errors.d.cts +0 -90
  52. package/dist/kill-process-tool.d.cts +0 -16
  53. package/dist/process-service.d.cts +0 -96
  54. package/dist/tool-provider.d.cts +0 -72
  55. package/dist/types.d.cts +0 -108
@@ -33,9 +33,11 @@ __export(bash_exec_tool_exports, {
33
33
  module.exports = __toCommonJS(bash_exec_tool_exports);
34
34
  var path = __toESM(require("node:path"), 1);
35
35
  var import_zod = require("zod");
36
+ var import_core = require("@dexto/core");
36
37
  var import_errors = require("./errors.js");
38
+ var import_command_pattern_utils = require("./command-pattern-utils.js");
37
39
  const BashExecInputSchema = import_zod.z.object({
38
- command: import_zod.z.string().describe("Shell command to execute"),
40
+ command: import_zod.z.string().min(1).describe("Shell command to execute"),
39
41
  description: import_zod.z.string().optional().describe("Human-readable description of what the command does (5-10 words)"),
40
42
  timeout: import_zod.z.number().int().positive().max(6e5).optional().default(12e4).describe(
41
43
  "Timeout in milliseconds (max: 600000 = 10 minutes, default: 120000 = 2 minutes)"
@@ -43,9 +45,10 @@ const BashExecInputSchema = import_zod.z.object({
43
45
  run_in_background: import_zod.z.boolean().optional().default(false).describe("Execute command in background (default: false)"),
44
46
  cwd: import_zod.z.string().optional().describe("Working directory for command execution (optional)")
45
47
  }).strict();
46
- function createBashExecTool(processService) {
47
- return {
48
+ function createBashExecTool(getProcessService) {
49
+ return (0, import_core.defineTool)({
48
50
  id: "bash_exec",
51
+ aliases: ["bash"],
49
52
  description: `Execute a shell command in the project root directory.
50
53
 
51
54
  IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. Do NOT use it for file operations - use the specialized tools instead:
@@ -92,27 +95,39 @@ Each command runs in a fresh shell, so cd does not persist between calls.
92
95
 
93
96
  Security: Dangerous commands are blocked. Injection attempts are detected. Requires approval with pattern-based session memory.`,
94
97
  inputSchema: BashExecInputSchema,
95
- /**
96
- * Generate preview for approval UI - shows the command to be executed
97
- */
98
- generatePreview: async (input, _context) => {
99
- const { command, run_in_background } = input;
100
- const preview = {
101
- type: "shell",
102
- command,
103
- exitCode: 0,
104
- // Placeholder - not executed yet
105
- duration: 0,
106
- // Placeholder - not executed yet
107
- ...run_in_background !== void 0 && { isBackground: run_in_background }
108
- };
109
- return preview;
98
+ approval: {
99
+ patternKey: (input) => (0, import_command_pattern_utils.generateCommandPatternKey)(input.command),
100
+ suggestPatterns: (input) => (0, import_command_pattern_utils.generateCommandPatternSuggestions)(input.command)
110
101
  },
111
- execute: async (input, context) => {
102
+ presentation: {
103
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
104
+ title: "Bash",
105
+ argsText: (0, import_core.truncateForHeader)(input.command, 140)
106
+ }),
107
+ /**
108
+ * Generate preview for approval UI - shows the command to be executed
109
+ */
110
+ preview: async (input, _context) => {
111
+ const { command, run_in_background } = input;
112
+ const preview = {
113
+ type: "shell",
114
+ title: "Bash",
115
+ command,
116
+ exitCode: 0,
117
+ // Placeholder - not executed yet
118
+ duration: 0,
119
+ // Placeholder - not executed yet
120
+ isBackground: run_in_background
121
+ };
122
+ return preview;
123
+ }
124
+ },
125
+ async execute(input, context) {
126
+ const resolvedProcessService = await getProcessService(context);
112
127
  const { command, description, timeout, run_in_background, cwd } = input;
113
128
  let validatedCwd = cwd;
114
129
  if (cwd) {
115
- const baseDir = processService.getConfig().workingDirectory || process.cwd();
130
+ const baseDir = resolvedProcessService.getConfig().workingDirectory || process.cwd();
116
131
  const candidatePath = path.isAbsolute(cwd) ? path.resolve(cwd) : path.resolve(baseDir, cwd);
117
132
  const relativePath = path.relative(baseDir, candidatePath);
118
133
  const isOutsideBase = relativePath.startsWith("..") || path.isAbsolute(relativePath);
@@ -124,17 +139,18 @@ Security: Dangerous commands are blocked. Injection attempts are detected. Requi
124
139
  }
125
140
  validatedCwd = candidatePath;
126
141
  }
127
- const result = await processService.executeCommand(command, {
142
+ const result = await resolvedProcessService.executeCommand(command, {
128
143
  description,
129
144
  timeout,
130
145
  runInBackground: run_in_background,
131
146
  cwd: validatedCwd,
132
147
  // Pass abort signal for cancellation support
133
- abortSignal: context?.abortSignal
148
+ abortSignal: context.abortSignal
134
149
  });
135
150
  if ("stdout" in result) {
136
151
  const _display = {
137
152
  type: "shell",
153
+ title: "Bash",
138
154
  command,
139
155
  exitCode: result.exitCode,
140
156
  duration: result.duration,
@@ -152,6 +168,7 @@ Security: Dangerous commands are blocked. Injection attempts are detected. Requi
152
168
  } else {
153
169
  const _display = {
154
170
  type: "shell",
171
+ title: "Bash",
155
172
  command,
156
173
  exitCode: 0,
157
174
  // Background process hasn't exited yet
@@ -166,7 +183,7 @@ Security: Dangerous commands are blocked. Injection attempts are detected. Requi
166
183
  };
167
184
  }
168
185
  }
169
- };
186
+ });
170
187
  }
171
188
  // Annotate the CommonJS export names for ESM import in node:
172
189
  0 && (module.exports = {
@@ -1,17 +1,35 @@
1
- import { InternalTool } from '@dexto/core';
2
- import { ProcessService } from './process-service.js';
3
- import './types.js';
4
-
5
1
  /**
6
2
  * Bash Execute Tool
7
3
  *
8
4
  * Internal tool for executing shell commands.
9
- * Approval is handled at the ToolManager level with pattern-based approval.
5
+ * Pattern-based approval support is declared on the tool (ToolManager stays generic).
10
6
  */
11
-
7
+ import { z } from 'zod';
8
+ import type { Tool, ToolExecutionContext } from '@dexto/core';
9
+ import { ProcessService } from './process-service.js';
10
+ declare const BashExecInputSchema: z.ZodObject<{
11
+ command: z.ZodString;
12
+ description: z.ZodOptional<z.ZodString>;
13
+ timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
14
+ run_in_background: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
15
+ cwd: z.ZodOptional<z.ZodString>;
16
+ }, "strict", z.ZodTypeAny, {
17
+ command: string;
18
+ timeout: number;
19
+ run_in_background: boolean;
20
+ cwd?: string | undefined;
21
+ description?: string | undefined;
22
+ }, {
23
+ command: string;
24
+ timeout?: number | undefined;
25
+ cwd?: string | undefined;
26
+ description?: string | undefined;
27
+ run_in_background?: boolean | undefined;
28
+ }>;
12
29
  /**
13
30
  * Create the bash_exec internal tool
14
31
  */
15
- declare function createBashExecTool(processService: ProcessService): InternalTool;
16
-
17
- export { createBashExecTool };
32
+ export type ProcessServiceGetter = (context: ToolExecutionContext) => Promise<ProcessService>;
33
+ export declare function createBashExecTool(getProcessService: ProcessServiceGetter): Tool<typeof BashExecInputSchema>;
34
+ export {};
35
+ //# sourceMappingURL=bash-exec-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash-exec-tool.d.ts","sourceRoot":"","sources":["../src/bash-exec-tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQtD,QAAA,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;EAwBZ,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAE9F,wBAAgB,kBAAkB,CAC9B,iBAAiB,EAAE,oBAAoB,GACxC,IAAI,CAAC,OAAO,mBAAmB,CAAC,CAmKlC"}
@@ -1,8 +1,13 @@
1
1
  import * as path from "node:path";
2
2
  import { z } from "zod";
3
+ import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
4
  import { ProcessError } from "./errors.js";
5
+ import {
6
+ generateCommandPatternKey,
7
+ generateCommandPatternSuggestions
8
+ } from "./command-pattern-utils.js";
4
9
  const BashExecInputSchema = z.object({
5
- command: z.string().describe("Shell command to execute"),
10
+ command: z.string().min(1).describe("Shell command to execute"),
6
11
  description: z.string().optional().describe("Human-readable description of what the command does (5-10 words)"),
7
12
  timeout: z.number().int().positive().max(6e5).optional().default(12e4).describe(
8
13
  "Timeout in milliseconds (max: 600000 = 10 minutes, default: 120000 = 2 minutes)"
@@ -10,9 +15,10 @@ const BashExecInputSchema = z.object({
10
15
  run_in_background: z.boolean().optional().default(false).describe("Execute command in background (default: false)"),
11
16
  cwd: z.string().optional().describe("Working directory for command execution (optional)")
12
17
  }).strict();
13
- function createBashExecTool(processService) {
14
- return {
18
+ function createBashExecTool(getProcessService) {
19
+ return defineTool({
15
20
  id: "bash_exec",
21
+ aliases: ["bash"],
16
22
  description: `Execute a shell command in the project root directory.
17
23
 
18
24
  IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. Do NOT use it for file operations - use the specialized tools instead:
@@ -59,27 +65,39 @@ Each command runs in a fresh shell, so cd does not persist between calls.
59
65
 
60
66
  Security: Dangerous commands are blocked. Injection attempts are detected. Requires approval with pattern-based session memory.`,
61
67
  inputSchema: BashExecInputSchema,
62
- /**
63
- * Generate preview for approval UI - shows the command to be executed
64
- */
65
- generatePreview: async (input, _context) => {
66
- const { command, run_in_background } = input;
67
- const preview = {
68
- type: "shell",
69
- command,
70
- exitCode: 0,
71
- // Placeholder - not executed yet
72
- duration: 0,
73
- // Placeholder - not executed yet
74
- ...run_in_background !== void 0 && { isBackground: run_in_background }
75
- };
76
- return preview;
68
+ approval: {
69
+ patternKey: (input) => generateCommandPatternKey(input.command),
70
+ suggestPatterns: (input) => generateCommandPatternSuggestions(input.command)
77
71
  },
78
- execute: async (input, context) => {
72
+ presentation: {
73
+ describeHeader: (input) => createLocalToolCallHeader({
74
+ title: "Bash",
75
+ argsText: truncateForHeader(input.command, 140)
76
+ }),
77
+ /**
78
+ * Generate preview for approval UI - shows the command to be executed
79
+ */
80
+ preview: async (input, _context) => {
81
+ const { command, run_in_background } = input;
82
+ const preview = {
83
+ type: "shell",
84
+ title: "Bash",
85
+ command,
86
+ exitCode: 0,
87
+ // Placeholder - not executed yet
88
+ duration: 0,
89
+ // Placeholder - not executed yet
90
+ isBackground: run_in_background
91
+ };
92
+ return preview;
93
+ }
94
+ },
95
+ async execute(input, context) {
96
+ const resolvedProcessService = await getProcessService(context);
79
97
  const { command, description, timeout, run_in_background, cwd } = input;
80
98
  let validatedCwd = cwd;
81
99
  if (cwd) {
82
- const baseDir = processService.getConfig().workingDirectory || process.cwd();
100
+ const baseDir = resolvedProcessService.getConfig().workingDirectory || process.cwd();
83
101
  const candidatePath = path.isAbsolute(cwd) ? path.resolve(cwd) : path.resolve(baseDir, cwd);
84
102
  const relativePath = path.relative(baseDir, candidatePath);
85
103
  const isOutsideBase = relativePath.startsWith("..") || path.isAbsolute(relativePath);
@@ -91,17 +109,18 @@ Security: Dangerous commands are blocked. Injection attempts are detected. Requi
91
109
  }
92
110
  validatedCwd = candidatePath;
93
111
  }
94
- const result = await processService.executeCommand(command, {
112
+ const result = await resolvedProcessService.executeCommand(command, {
95
113
  description,
96
114
  timeout,
97
115
  runInBackground: run_in_background,
98
116
  cwd: validatedCwd,
99
117
  // Pass abort signal for cancellation support
100
- abortSignal: context?.abortSignal
118
+ abortSignal: context.abortSignal
101
119
  });
102
120
  if ("stdout" in result) {
103
121
  const _display = {
104
122
  type: "shell",
123
+ title: "Bash",
105
124
  command,
106
125
  exitCode: result.exitCode,
107
126
  duration: result.duration,
@@ -119,6 +138,7 @@ Security: Dangerous commands are blocked. Injection attempts are detected. Requi
119
138
  } else {
120
139
  const _display = {
121
140
  type: "shell",
141
+ title: "Bash",
122
142
  command,
123
143
  exitCode: 0,
124
144
  // Background process hasn't exited yet
@@ -133,7 +153,7 @@ Security: Dangerous commands are blocked. Injection attempts are detected. Requi
133
153
  };
134
154
  }
135
155
  }
136
- };
156
+ });
137
157
  }
138
158
  export {
139
159
  createBashExecTool
@@ -22,17 +22,25 @@ __export(bash_output_tool_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(bash_output_tool_exports);
24
24
  var import_zod = require("zod");
25
+ var import_core = require("@dexto/core");
25
26
  const BashOutputInputSchema = import_zod.z.object({
26
27
  process_id: import_zod.z.string().describe("Process ID from bash_exec (when run_in_background=true)")
27
28
  }).strict();
28
- function createBashOutputTool(processService) {
29
- return {
29
+ function createBashOutputTool(getProcessService) {
30
+ return (0, import_core.defineTool)({
30
31
  id: "bash_output",
31
32
  description: "Retrieve output from a background process started with bash_exec. Returns stdout, stderr, status (running/completed/failed), exit code, and duration. Each call returns only new output since last read. The output buffer is cleared after reading. Use this tool to monitor long-running commands.",
32
33
  inputSchema: BashOutputInputSchema,
33
- execute: async (input, _context) => {
34
+ presentation: {
35
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
36
+ title: "Bash Output",
37
+ argsText: (0, import_core.truncateForHeader)(input.process_id, 80)
38
+ })
39
+ },
40
+ async execute(input, context) {
41
+ const resolvedProcessService = await getProcessService(context);
34
42
  const { process_id } = input;
35
- const result = await processService.getProcessOutput(process_id);
43
+ const result = await resolvedProcessService.getProcessOutput(process_id);
36
44
  return {
37
45
  stdout: result.stdout,
38
46
  stderr: result.stderr,
@@ -41,7 +49,7 @@ function createBashOutputTool(processService) {
41
49
  ...result.duration !== void 0 && { duration: result.duration }
42
50
  };
43
51
  }
44
- };
52
+ });
45
53
  }
46
54
  // Annotate the CommonJS export names for ESM import in node:
47
55
  0 && (module.exports = {
@@ -1,16 +1,21 @@
1
- import { InternalTool } from '@dexto/core';
2
- import { ProcessService } from './process-service.js';
3
- import './types.js';
4
-
5
1
  /**
6
2
  * Bash Output Tool
7
3
  *
8
4
  * Internal tool for retrieving output from background processes
9
5
  */
10
-
6
+ import { z } from 'zod';
7
+ import type { Tool } from '@dexto/core';
8
+ import type { ProcessServiceGetter } from './bash-exec-tool.js';
9
+ declare const BashOutputInputSchema: z.ZodObject<{
10
+ process_id: z.ZodString;
11
+ }, "strict", z.ZodTypeAny, {
12
+ process_id: string;
13
+ }, {
14
+ process_id: string;
15
+ }>;
11
16
  /**
12
17
  * Create the bash_output internal tool
13
18
  */
14
- declare function createBashOutputTool(processService: ProcessService): InternalTool;
15
-
16
- export { createBashOutputTool };
19
+ export declare function createBashOutputTool(getProcessService: ProcessServiceGetter): Tool<typeof BashOutputInputSchema>;
20
+ export {};
21
+ //# sourceMappingURL=bash-output-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash-output-tool.d.ts","sourceRoot":"","sources":["../src/bash-output-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,QAAA,MAAM,qBAAqB;;;;;;EAId,CAAC;AAEd;;GAEG;AACH,wBAAgB,oBAAoB,CAChC,iBAAiB,EAAE,oBAAoB,GACxC,IAAI,CAAC,OAAO,qBAAqB,CAAC,CA+BpC"}
@@ -1,15 +1,23 @@
1
1
  import { z } from "zod";
2
+ import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
2
3
  const BashOutputInputSchema = z.object({
3
4
  process_id: z.string().describe("Process ID from bash_exec (when run_in_background=true)")
4
5
  }).strict();
5
- function createBashOutputTool(processService) {
6
- return {
6
+ function createBashOutputTool(getProcessService) {
7
+ return defineTool({
7
8
  id: "bash_output",
8
9
  description: "Retrieve output from a background process started with bash_exec. Returns stdout, stderr, status (running/completed/failed), exit code, and duration. Each call returns only new output since last read. The output buffer is cleared after reading. Use this tool to monitor long-running commands.",
9
10
  inputSchema: BashOutputInputSchema,
10
- execute: async (input, _context) => {
11
+ presentation: {
12
+ describeHeader: (input) => createLocalToolCallHeader({
13
+ title: "Bash Output",
14
+ argsText: truncateForHeader(input.process_id, 80)
15
+ })
16
+ },
17
+ async execute(input, context) {
18
+ const resolvedProcessService = await getProcessService(context);
11
19
  const { process_id } = input;
12
- const result = await processService.getProcessOutput(process_id);
20
+ const result = await resolvedProcessService.getProcessOutput(process_id);
13
21
  return {
14
22
  stdout: result.stdout,
15
23
  stderr: result.stderr,
@@ -18,7 +26,7 @@ function createBashOutputTool(processService) {
18
26
  ...result.duration !== void 0 && { duration: result.duration }
19
27
  };
20
28
  }
21
- };
29
+ });
22
30
  }
23
31
  export {
24
32
  createBashOutputTool
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var command_pattern_utils_exports = {};
20
+ __export(command_pattern_utils_exports, {
21
+ DANGEROUS_COMMAND_PREFIXES: () => DANGEROUS_COMMAND_PREFIXES,
22
+ generateCommandPatternKey: () => generateCommandPatternKey,
23
+ generateCommandPatternSuggestions: () => generateCommandPatternSuggestions,
24
+ isDangerousCommand: () => isDangerousCommand
25
+ });
26
+ module.exports = __toCommonJS(command_pattern_utils_exports);
27
+ const DANGEROUS_COMMAND_PREFIXES = [
28
+ "rm",
29
+ "chmod",
30
+ "chown",
31
+ "chgrp",
32
+ "sudo",
33
+ "su",
34
+ "dd",
35
+ "mkfs",
36
+ "fdisk",
37
+ "parted",
38
+ "kill",
39
+ "killall",
40
+ "pkill",
41
+ "shutdown",
42
+ "reboot",
43
+ "halt",
44
+ "poweroff"
45
+ ];
46
+ function isDangerousCommand(command) {
47
+ const tokens = command.trim().split(/\s+/);
48
+ if (!tokens[0]) return false;
49
+ const head = tokens[0].toLowerCase();
50
+ return DANGEROUS_COMMAND_PREFIXES.includes(head);
51
+ }
52
+ function generateCommandPatternKey(command) {
53
+ const tokens = command.trim().split(/\s+/);
54
+ if (!tokens[0]) return null;
55
+ const head = tokens[0].toLowerCase();
56
+ if (isDangerousCommand(command)) {
57
+ return null;
58
+ }
59
+ const subcommand = tokens.slice(1).find((arg) => !arg.startsWith("-"));
60
+ return subcommand ? `${head} ${subcommand.toLowerCase()} *` : `${head} *`;
61
+ }
62
+ function generateCommandPatternSuggestions(command) {
63
+ const tokens = command.trim().toLowerCase().split(/\s+/);
64
+ if (!tokens[0]) return [];
65
+ const head = tokens[0];
66
+ if (isDangerousCommand(command)) {
67
+ return [];
68
+ }
69
+ const patterns = [];
70
+ const nonFlagArgs = tokens.slice(1).filter((arg) => !arg.startsWith("-"));
71
+ if (nonFlagArgs.length > 0) {
72
+ patterns.push(`${head} ${nonFlagArgs[0]} *`);
73
+ }
74
+ patterns.push(`${head} *`);
75
+ return patterns;
76
+ }
77
+ // Annotate the CommonJS export names for ESM import in node:
78
+ 0 && (module.exports = {
79
+ DANGEROUS_COMMAND_PREFIXES,
80
+ generateCommandPatternKey,
81
+ generateCommandPatternSuggestions,
82
+ isDangerousCommand
83
+ });
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Utility functions for generating approval patterns for shell commands.
3
+ *
4
+ * Pattern-based approvals allow users to approve command patterns like "git *"
5
+ * that automatically cover future matching commands (e.g., "git status", "git push").
6
+ */
7
+ /**
8
+ * Commands that should never get auto-approve pattern suggestions.
9
+ * These require explicit approval each time for safety.
10
+ */
11
+ export declare const DANGEROUS_COMMAND_PREFIXES: readonly ["rm", "chmod", "chown", "chgrp", "sudo", "su", "dd", "mkfs", "fdisk", "parted", "kill", "killall", "pkill", "shutdown", "reboot", "halt", "poweroff"];
12
+ export declare function isDangerousCommand(command: string): boolean;
13
+ /**
14
+ * Generate the pattern key for a shell command.
15
+ *
16
+ * Examples:
17
+ * - "ls -la" → "ls *" (flags don't count as subcommand)
18
+ * - "git push origin" → "git push *" (first non-flag arg is subcommand)
19
+ * - "rm -rf /" → null (dangerous command)
20
+ */
21
+ export declare function generateCommandPatternKey(command: string): string | null;
22
+ /**
23
+ * Generate suggested patterns for UI selection.
24
+ * Returns progressively broader patterns from specific to general.
25
+ *
26
+ * Example: "git push origin main" → ["git push *", "git *"]
27
+ */
28
+ export declare function generateCommandPatternSuggestions(command: string): string[];
29
+ //# sourceMappingURL=command-pattern-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-pattern-utils.d.ts","sourceRoot":"","sources":["../src/command-pattern-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,0BAA0B,iKAkB7B,CAAC;AAEX,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK3D;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYxE;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB3E"}
@@ -0,0 +1,56 @@
1
+ const DANGEROUS_COMMAND_PREFIXES = [
2
+ "rm",
3
+ "chmod",
4
+ "chown",
5
+ "chgrp",
6
+ "sudo",
7
+ "su",
8
+ "dd",
9
+ "mkfs",
10
+ "fdisk",
11
+ "parted",
12
+ "kill",
13
+ "killall",
14
+ "pkill",
15
+ "shutdown",
16
+ "reboot",
17
+ "halt",
18
+ "poweroff"
19
+ ];
20
+ function isDangerousCommand(command) {
21
+ const tokens = command.trim().split(/\s+/);
22
+ if (!tokens[0]) return false;
23
+ const head = tokens[0].toLowerCase();
24
+ return DANGEROUS_COMMAND_PREFIXES.includes(head);
25
+ }
26
+ function generateCommandPatternKey(command) {
27
+ const tokens = command.trim().split(/\s+/);
28
+ if (!tokens[0]) return null;
29
+ const head = tokens[0].toLowerCase();
30
+ if (isDangerousCommand(command)) {
31
+ return null;
32
+ }
33
+ const subcommand = tokens.slice(1).find((arg) => !arg.startsWith("-"));
34
+ return subcommand ? `${head} ${subcommand.toLowerCase()} *` : `${head} *`;
35
+ }
36
+ function generateCommandPatternSuggestions(command) {
37
+ const tokens = command.trim().toLowerCase().split(/\s+/);
38
+ if (!tokens[0]) return [];
39
+ const head = tokens[0];
40
+ if (isDangerousCommand(command)) {
41
+ return [];
42
+ }
43
+ const patterns = [];
44
+ const nonFlagArgs = tokens.slice(1).filter((arg) => !arg.startsWith("-"));
45
+ if (nonFlagArgs.length > 0) {
46
+ patterns.push(`${head} ${nonFlagArgs[0]} *`);
47
+ }
48
+ patterns.push(`${head} *`);
49
+ return patterns;
50
+ }
51
+ export {
52
+ DANGEROUS_COMMAND_PREFIXES,
53
+ generateCommandPatternKey,
54
+ generateCommandPatternSuggestions,
55
+ isDangerousCommand
56
+ };
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var import_command_pattern_utils = require("./command-pattern-utils.js");
3
+ var import_vitest = require("vitest");
4
+ (0, import_vitest.describe)("command-pattern-utils", () => {
5
+ (0, import_vitest.describe)("isDangerousCommand", () => {
6
+ (0, import_vitest.it)("should detect dangerous commands", () => {
7
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("rm -rf /")).toBe(true);
8
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("sudo apt install")).toBe(true);
9
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("chmod 777 file")).toBe(true);
10
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("kill -9 1234")).toBe(true);
11
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("dd if=/dev/zero of=/dev/sda")).toBe(true);
12
+ });
13
+ (0, import_vitest.it)("should not flag safe commands", () => {
14
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("ls -la")).toBe(false);
15
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("git status")).toBe(false);
16
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("npm install")).toBe(false);
17
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("cat file.txt")).toBe(false);
18
+ });
19
+ (0, import_vitest.it)("should be case-insensitive", () => {
20
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("RM -rf /")).toBe(true);
21
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("SUDO apt install")).toBe(true);
22
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("Chmod 777 file")).toBe(true);
23
+ });
24
+ (0, import_vitest.it)("should handle empty input", () => {
25
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)("")).toBe(false);
26
+ (0, import_vitest.expect)((0, import_command_pattern_utils.isDangerousCommand)(" ")).toBe(false);
27
+ });
28
+ });
29
+ (0, import_vitest.describe)("generateCommandPatternKey", () => {
30
+ (0, import_vitest.it)("should generate patterns for simple commands", () => {
31
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("ls")).toBe("ls *");
32
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("pwd")).toBe("pwd *");
33
+ });
34
+ (0, import_vitest.it)("should ignore flags when choosing subcommand", () => {
35
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("ls -la")).toBe("ls *");
36
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("git -v status")).toBe("git status *");
37
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("npm --verbose install")).toBe("npm install *");
38
+ });
39
+ (0, import_vitest.it)("should generate subcommand patterns", () => {
40
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("git status")).toBe("git status *");
41
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("git push origin main")).toBe("git push *");
42
+ });
43
+ (0, import_vitest.it)("should return null for dangerous commands", () => {
44
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("rm -rf /")).toBeNull();
45
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("sudo apt install")).toBeNull();
46
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("shutdown -h now")).toBeNull();
47
+ });
48
+ (0, import_vitest.it)("should handle empty input", () => {
49
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)("")).toBeNull();
50
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)(" ")).toBeNull();
51
+ });
52
+ (0, import_vitest.it)("should trim and normalize whitespace", () => {
53
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)(" ls -la ")).toBe("ls *");
54
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternKey)(" git push origin ")).toBe("git push *");
55
+ });
56
+ });
57
+ (0, import_vitest.describe)("generateCommandPatternSuggestions", () => {
58
+ (0, import_vitest.it)("should generate broad-to-narrow suggestions", () => {
59
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternSuggestions)("ls")).toEqual(["ls *"]);
60
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternSuggestions)("git push origin main")).toEqual([
61
+ "git push *",
62
+ "git *"
63
+ ]);
64
+ });
65
+ (0, import_vitest.it)("should return empty for dangerous commands", () => {
66
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternSuggestions)("rm -rf /")).toEqual([]);
67
+ });
68
+ (0, import_vitest.it)("should handle empty input", () => {
69
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternSuggestions)("")).toEqual([]);
70
+ (0, import_vitest.expect)((0, import_command_pattern_utils.generateCommandPatternSuggestions)(" ")).toEqual([]);
71
+ });
72
+ (0, import_vitest.it)("should keep suggestions consistent with pattern key", () => {
73
+ const command = "git push origin main";
74
+ const patternKey = (0, import_command_pattern_utils.generateCommandPatternKey)(command);
75
+ const suggestions = (0, import_command_pattern_utils.generateCommandPatternSuggestions)(command);
76
+ (0, import_vitest.expect)(patternKey).toBe("git push *");
77
+ (0, import_vitest.expect)(suggestions[0]).toBe(patternKey);
78
+ });
79
+ });
80
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=command-pattern-utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-pattern-utils.test.d.ts","sourceRoot":"","sources":["../src/command-pattern-utils.test.ts"],"names":[],"mappings":""}