@framers/agentos-ext-cli-executor 1.1.0 → 1.1.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.
package/README.md CHANGED
@@ -18,30 +18,36 @@ npm install @framers/agentos-ext-cli-executor
18
18
  ## Quick Start
19
19
 
20
20
  ```typescript
21
- import { createExtensionPack } from '@framers/agentos-ext-cli-executor';
22
21
  import { ExtensionManager } from '@framers/agentos';
22
+ import { createExtensionPack } from '@framers/agentos-ext-cli-executor';
23
23
 
24
24
  const extensionManager = new ExtensionManager();
25
25
 
26
- // Register the CLI extension
27
- extensionManager.register(createExtensionPack({
28
- options: {
29
- defaultShell: 'bash',
30
- timeout: 60000,
31
- blockedCommands: ['rm -rf /', 'format']
32
- },
33
- logger: console
34
- }));
26
+ // Load the pack into the runtime
27
+ await extensionManager.loadPackFromFactory(
28
+ createExtensionPack({
29
+ options: {
30
+ defaultShell: 'bash',
31
+ timeout: 60000,
32
+ blockedCommands: ['rm -rf /', 'format'],
33
+ // Restrict file_* tools to a per-agent workspace
34
+ filesystem: { allowRead: true, allowWrite: true },
35
+ agentWorkspace: { agentId: 'my-agent' },
36
+ },
37
+ logger: console,
38
+ }),
39
+ '@framers/agentos-ext-cli-executor',
40
+ );
35
41
  ```
36
42
 
37
43
  ## Tools
38
44
 
39
- ### shellExecute
45
+ ### shell_execute
40
46
 
41
47
  Execute a shell command.
42
48
 
43
49
  ```typescript
44
- const result = await gmi.executeTool('shellExecute', {
50
+ const result = await gmi.executeTool('shell_execute', {
45
51
  command: 'npm install lodash',
46
52
  cwd: '/path/to/project',
47
53
  timeout: 30000
@@ -49,31 +55,31 @@ const result = await gmi.executeTool('shellExecute', {
49
55
  // Returns: { command, exitCode, stdout, stderr, duration, success }
50
56
  ```
51
57
 
52
- ### fileRead
58
+ ### file_read
53
59
 
54
60
  Read file contents.
55
61
 
56
62
  ```typescript
57
- const result = await gmi.executeTool('fileRead', {
63
+ const result = await gmi.executeTool('file_read', {
58
64
  path: './package.json',
59
65
  encoding: 'utf-8'
60
66
  });
61
67
  // Returns: { path, content, size, truncated, encoding }
62
68
 
63
69
  // Read last 50 lines
64
- const logs = await gmi.executeTool('fileRead', {
70
+ const logs = await gmi.executeTool('file_read', {
65
71
  path: './app.log',
66
72
  lines: 50,
67
73
  fromEnd: true
68
74
  });
69
75
  ```
70
76
 
71
- ### fileWrite
77
+ ### file_write
72
78
 
73
79
  Write content to a file.
74
80
 
75
81
  ```typescript
76
- const result = await gmi.executeTool('fileWrite', {
82
+ const result = await gmi.executeTool('file_write', {
77
83
  path: './config.json',
78
84
  content: JSON.stringify({ key: 'value' }),
79
85
  createDirs: true
@@ -81,12 +87,12 @@ const result = await gmi.executeTool('fileWrite', {
81
87
  // Returns: { path, bytesWritten, created, appended }
82
88
  ```
83
89
 
84
- ### listDirectory
90
+ ### list_directory
85
91
 
86
92
  List directory contents.
87
93
 
88
94
  ```typescript
89
- const result = await gmi.executeTool('listDirectory', {
95
+ const result = await gmi.executeTool('list_directory', {
90
96
  path: './src',
91
97
  recursive: true,
92
98
  pattern: '*.ts',
@@ -119,6 +125,18 @@ createExtensionPack({
119
125
  });
120
126
  ```
121
127
 
128
+ ### Disabling Safety Checks (Dangerous)
129
+
130
+ If you need full control (for example, in a locked-down container or local dev), you can disable all command safety checks:
131
+
132
+ ```typescript
133
+ createExtensionPack({
134
+ options: {
135
+ dangerouslySkipSecurityChecks: true
136
+ }
137
+ });
138
+ ```
139
+
122
140
  ### Risk Assessment
123
141
 
124
142
  Each command is assessed for risk level:
@@ -138,24 +156,61 @@ Each command is assessed for risk level:
138
156
  | `defaultShell` | string | `auto` | Shell to use (bash, powershell, cmd, zsh) |
139
157
  | `timeout` | number | `60000` | Default timeout (ms) |
140
158
  | `workingDirectory` | string | `process.cwd()` | Default working directory |
159
+ | `filesystem` | object | `undefined` | Optional policy for file_* tools (allowRead/allowWrite + roots) |
160
+ | `agentWorkspace` | object | `undefined` | Optional per-agent workspace directory helper |
141
161
  | `allowedCommands` | string[] | `[]` | Command whitelist (empty = all) |
142
- | `blockedCommands` | string[] | `[...]` | Command blacklist |
162
+ | `blockedCommands` | string[] | `[]` | Command blacklist (additional to built-in dangerous patterns) |
163
+ | `dangerouslySkipSecurityChecks` | boolean | `false` | Disable all command safety checks (use only in trusted environments) |
143
164
  | `env` | object | `{}` | Environment variables |
144
165
 
166
+ ### Filesystem Policy (Recommended)
167
+
168
+ By default, the `file_*` tools can access any path (legacy behavior). To enforce a safe filesystem sandbox, configure `filesystem` + roots:
169
+
170
+ ```ts
171
+ createExtensionPack({
172
+ options: {
173
+ filesystem: {
174
+ allowRead: true,
175
+ allowWrite: true,
176
+ readRoots: ['/Users/me/Documents/AgentOS/agents/my-agent'],
177
+ writeRoots: ['/Users/me/Documents/AgentOS/agents/my-agent'],
178
+ },
179
+ },
180
+ });
181
+ ```
182
+
183
+ ### Per-Agent Workspace Helper
184
+
185
+ To simplify safe defaults, you can configure `agentWorkspace`. When paired with `filesystem.allowRead/allowWrite`, the extension defaults roots to the workspace directory.
186
+
187
+ ```ts
188
+ createExtensionPack({
189
+ options: {
190
+ filesystem: { allowRead: true, allowWrite: true },
191
+ agentWorkspace: {
192
+ agentId: 'my-agent',
193
+ // baseDir defaults to ~/Documents/AgentOS
194
+ subdirs: ['assets', 'exports', 'tmp'],
195
+ },
196
+ },
197
+ });
198
+ ```
199
+
145
200
  ## Use Cases
146
201
 
147
202
  ### Code Generation and Execution
148
203
 
149
204
  ```typescript
150
205
  // Write generated code
151
- await gmi.executeTool('fileWrite', {
206
+ await gmi.executeTool('file_write', {
152
207
  path: './generated/app.py',
153
208
  content: generatedPythonCode,
154
209
  createDirs: true
155
210
  });
156
211
 
157
212
  // Execute it
158
- await gmi.executeTool('shellExecute', {
213
+ await gmi.executeTool('shell_execute', {
159
214
  command: 'python ./generated/app.py',
160
215
  timeout: 30000
161
216
  });
@@ -165,12 +220,12 @@ await gmi.executeTool('shellExecute', {
165
220
 
166
221
  ```typescript
167
222
  // Create project structure
168
- await gmi.executeTool('shellExecute', {
223
+ await gmi.executeTool('shell_execute', {
169
224
  command: 'npx create-react-app my-app --template typescript'
170
225
  });
171
226
 
172
227
  // Install dependencies
173
- await gmi.executeTool('shellExecute', {
228
+ await gmi.executeTool('shell_execute', {
174
229
  command: 'npm install axios lodash',
175
230
  cwd: './my-app'
176
231
  });
@@ -180,7 +235,7 @@ await gmi.executeTool('shellExecute', {
180
235
 
181
236
  ```typescript
182
237
  // Read recent logs
183
- const logs = await gmi.executeTool('fileRead', {
238
+ const logs = await gmi.executeTool('file_read', {
184
239
  path: '/var/log/app.log',
185
240
  lines: 100,
186
241
  fromEnd: true
@@ -216,6 +271,3 @@ Together, an intelligent agent can:
216
271
  ## License
217
272
 
218
273
  MIT © Frame.dev
219
-
220
-
221
-
package/dist/index.d.ts CHANGED
@@ -5,11 +5,14 @@
5
5
  * capabilities for AgentOS agents.
6
6
  *
7
7
  * @module @framers/agentos-ext-cli-executor
8
- * @version 1.0.0
8
+ * @version 1.1.0
9
9
  * @license MIT
10
10
  */
11
- import type { ExtensionContext, ExtensionPack } from '@framers/agentos';
12
- import type { ShellConfig } from './types';
11
+ import { ExecuteTool } from './tools/execute.js';
12
+ import { FileReadTool } from './tools/fileRead.js';
13
+ import { FileWriteTool } from './tools/fileWrite.js';
14
+ import { ListDirectoryTool } from './tools/listDir.js';
15
+ import type { ShellConfig } from './types.js';
13
16
  /**
14
17
  * Extension configuration options
15
18
  */
@@ -37,12 +40,53 @@ export interface CLIExecutorExtensionOptions extends ShellConfig {
37
40
  * });
38
41
  * ```
39
42
  */
40
- export declare function createExtensionPack(context: ExtensionContext): ExtensionPack;
41
- export { ShellService } from './services/shellService';
42
- export { ExecuteTool } from './tools/execute';
43
- export { FileReadTool } from './tools/fileRead';
44
- export { FileWriteTool } from './tools/fileWrite';
45
- export { ListDirectoryTool } from './tools/listDir';
46
- export * from './types';
43
+ export declare function createExtensionPack(context: {
44
+ options?: Record<string, unknown>;
45
+ secrets?: Record<string, string>;
46
+ logger?: {
47
+ info: (...args: unknown[]) => void;
48
+ };
49
+ onActivate?: () => Promise<void>;
50
+ onDeactivate?: () => Promise<void>;
51
+ [key: string]: unknown;
52
+ }): {
53
+ name: string;
54
+ version: string;
55
+ descriptors: ({
56
+ id: string;
57
+ kind: string;
58
+ priority: number;
59
+ payload: ExecuteTool;
60
+ } | {
61
+ id: string;
62
+ kind: string;
63
+ priority: number;
64
+ payload: FileReadTool;
65
+ } | {
66
+ id: string;
67
+ kind: string;
68
+ priority: number;
69
+ payload: FileWriteTool;
70
+ } | {
71
+ id: string;
72
+ kind: string;
73
+ priority: number;
74
+ payload: ListDirectoryTool;
75
+ })[];
76
+ /**
77
+ * Called when extension is activated
78
+ */
79
+ onActivate: () => Promise<void>;
80
+ /**
81
+ * Called when extension is deactivated
82
+ */
83
+ onDeactivate: () => Promise<void>;
84
+ };
85
+ export { ShellService } from './services/shellService.js';
86
+ export { ExecuteTool } from './tools/execute.js';
87
+ export { FileReadTool } from './tools/fileRead.js';
88
+ export { FileWriteTool } from './tools/fileWrite.js';
89
+ export { ListDirectoryTool } from './tools/listDir.js';
90
+ export * from './types.js';
47
91
  export default createExtensionPack;
48
92
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,2BAA4B,SAAQ,WAAW;IAC9D,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAqE5E;AAGD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,cAAc,SAAS,CAAC;AAGxB,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,2BAA4B,SAAQ,WAAW;IAC9D,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;;;;;;;;;;;;;;;;;;;;;;;;IAuFG;;OAEG;;IAcH;;OAEG;;EAQN;AAGD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,cAAc,YAAY,CAAC;AAG3B,eAAe,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -5,14 +5,17 @@
5
5
  * capabilities for AgentOS agents.
6
6
  *
7
7
  * @module @framers/agentos-ext-cli-executor
8
- * @version 1.0.0
8
+ * @version 1.1.0
9
9
  * @license MIT
10
10
  */
11
- import { ShellService } from './services/shellService';
12
- import { ExecuteTool } from './tools/execute';
13
- import { FileReadTool } from './tools/fileRead';
14
- import { FileWriteTool } from './tools/fileWrite';
15
- import { ListDirectoryTool } from './tools/listDir';
11
+ import * as fs from 'node:fs/promises';
12
+ import * as os from 'node:os';
13
+ import * as path from 'node:path';
14
+ import { ShellService } from './services/shellService.js';
15
+ import { ExecuteTool } from './tools/execute.js';
16
+ import { FileReadTool } from './tools/fileRead.js';
17
+ import { FileWriteTool } from './tools/fileWrite.js';
18
+ import { ListDirectoryTool } from './tools/listDir.js';
16
19
  /**
17
20
  * Creates the CLI executor extension pack
18
21
  *
@@ -35,13 +38,46 @@ import { ListDirectoryTool } from './tools/listDir';
35
38
  */
36
39
  export function createExtensionPack(context) {
37
40
  const options = context.options || {};
41
+ let workspaceDir;
42
+ let workspaceSubdirs = [];
43
+ const workspaceConfig = options.agentWorkspace;
44
+ if (workspaceConfig && workspaceConfig.enabled !== false) {
45
+ const baseDir = (workspaceConfig.baseDir && String(workspaceConfig.baseDir).trim()) ||
46
+ path.join(os.homedir(), 'Documents', 'AgentOS');
47
+ const agentId = String(workspaceConfig.agentId || '').trim();
48
+ if (agentId) {
49
+ workspaceDir = path.resolve(baseDir, agentId);
50
+ workspaceSubdirs = Array.isArray(workspaceConfig.subdirs) && workspaceConfig.subdirs.length > 0
51
+ ? workspaceConfig.subdirs.map((d) => String(d)).filter(Boolean)
52
+ : ['assets', 'exports', 'tmp'];
53
+ }
54
+ }
55
+ const workingDirectory = options.workingDirectory || workspaceDir;
56
+ const filesystem = options.filesystem
57
+ ? {
58
+ ...options.filesystem,
59
+ readRoots: options.filesystem.allowRead === true &&
60
+ (!options.filesystem.readRoots || options.filesystem.readRoots.length === 0) &&
61
+ workspaceDir
62
+ ? [workspaceDir]
63
+ : options.filesystem.readRoots,
64
+ writeRoots: options.filesystem.allowWrite === true &&
65
+ (!options.filesystem.writeRoots || options.filesystem.writeRoots.length === 0) &&
66
+ workspaceDir
67
+ ? [workspaceDir]
68
+ : options.filesystem.writeRoots,
69
+ }
70
+ : undefined;
38
71
  // Initialize shell service with configuration
39
72
  const shellService = new ShellService({
40
73
  defaultShell: options.defaultShell,
41
74
  timeout: options.timeout,
42
- workingDirectory: options.workingDirectory,
75
+ workingDirectory,
76
+ filesystem,
77
+ agentWorkspace: options.agentWorkspace,
43
78
  allowedCommands: options.allowedCommands,
44
79
  blockedCommands: options.blockedCommands,
80
+ dangerouslySkipSecurityChecks: options.dangerouslySkipSecurityChecks,
45
81
  env: options.env,
46
82
  });
47
83
  // Create tool instances
@@ -51,28 +87,28 @@ export function createExtensionPack(context) {
51
87
  const listDirectoryTool = new ListDirectoryTool(shellService);
52
88
  return {
53
89
  name: '@framers/agentos-ext-cli-executor',
54
- version: '1.0.0',
90
+ version: '1.1.0',
55
91
  descriptors: [
56
92
  {
57
- id: 'shellExecute',
93
+ id: executeTool.name,
58
94
  kind: 'tool',
59
95
  priority: options.priority || 50,
60
96
  payload: executeTool,
61
97
  },
62
98
  {
63
- id: 'fileRead',
99
+ id: fileReadTool.name,
64
100
  kind: 'tool',
65
101
  priority: options.priority || 50,
66
102
  payload: fileReadTool,
67
103
  },
68
104
  {
69
- id: 'fileWrite',
105
+ id: fileWriteTool.name,
70
106
  kind: 'tool',
71
107
  priority: options.priority || 50,
72
108
  payload: fileWriteTool,
73
109
  },
74
110
  {
75
- id: 'listDirectory',
111
+ id: listDirectoryTool.name,
76
112
  kind: 'tool',
77
113
  priority: options.priority || 50,
78
114
  payload: listDirectoryTool,
@@ -85,6 +121,12 @@ export function createExtensionPack(context) {
85
121
  if (context.onActivate) {
86
122
  await context.onActivate();
87
123
  }
124
+ if (workspaceDir && workspaceConfig?.createIfMissing !== false) {
125
+ await fs.mkdir(workspaceDir, { recursive: true });
126
+ for (const sub of workspaceSubdirs) {
127
+ await fs.mkdir(path.join(workspaceDir, sub), { recursive: true });
128
+ }
129
+ }
88
130
  context.logger?.info('CLI Executor Extension activated');
89
131
  },
90
132
  /**
@@ -99,12 +141,12 @@ export function createExtensionPack(context) {
99
141
  };
100
142
  }
101
143
  // Export types and classes for consumers
102
- export { ShellService } from './services/shellService';
103
- export { ExecuteTool } from './tools/execute';
104
- export { FileReadTool } from './tools/fileRead';
105
- export { FileWriteTool } from './tools/fileWrite';
106
- export { ListDirectoryTool } from './tools/listDir';
107
- export * from './types';
144
+ export { ShellService } from './services/shellService.js';
145
+ export { ExecuteTool } from './tools/execute.js';
146
+ export { FileReadTool } from './tools/fileRead.js';
147
+ export { FileWriteTool } from './tools/fileWrite.js';
148
+ export { ListDirectoryTool } from './tools/listDir.js';
149
+ export * from './types.js';
108
150
  // Default export for convenience
109
151
  export default createExtensionPack;
110
152
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAWpD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAyB;IAC3D,MAAM,OAAO,GAAI,OAAO,CAAC,OAAuC,IAAI,EAAE,CAAC;IAEvE,8CAA8C;IAC9C,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC;QACpC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,wBAAwB;IACxB,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAE9D,OAAO;QACL,IAAI,EAAE,mCAAmC;QACzC,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE;YACX;gBACE,EAAE,EAAE,cAAc;gBAClB,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;gBAChC,OAAO,EAAE,WAAW;aACrB;YACD;gBACE,EAAE,EAAE,UAAU;gBACd,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;gBAChC,OAAO,EAAE,YAAY;aACtB;YACD;gBACE,EAAE,EAAE,WAAW;gBACf,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;gBAChC,OAAO,EAAE,aAAa;aACvB;YACD;gBACE,EAAE,EAAE,eAAe;gBACnB,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;gBAChC,OAAO,EAAE,iBAAiB;aAC3B;SACF;QAED;;WAEG;QACH,UAAU,EAAE,KAAK,IAAI,EAAE;YACrB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvB,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC7B,CAAC;YACD,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAC3D,CAAC;QAED;;WAEG;QACH,YAAY,EAAE,KAAK,IAAI,EAAE;YACvB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBACzB,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;YAC/B,CAAC;YACD,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,oCAAoC,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC;AAED,yCAAyC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,cAAc,SAAS,CAAC;AAExB,iCAAiC;AACjC,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -4,13 +4,18 @@
4
4
  *
5
5
  * @module @framers/agentos-ext-cli-executor
6
6
  */
7
- import type { ShellConfig, ExecutionResult, ScriptOptions, ScriptResult, FileReadOptions, FileReadResult, FileWriteOptions, FileWriteResult, ListDirectoryOptions, ListDirectoryResult, SecurityCheckResult } from '../types';
7
+ import type { ShellConfig, ExecutionResult, ScriptOptions, ScriptResult, FileReadOptions, FileReadResult, FileWriteOptions, FileWriteResult, ListDirectoryOptions, ListDirectoryResult, SecurityCheckResult } from '../types.js';
8
8
  /**
9
9
  * Shell service for executing commands
10
10
  */
11
11
  export declare class ShellService {
12
12
  private config;
13
13
  constructor(config?: ShellConfig);
14
+ private resolveAbsolutePath;
15
+ private isFilesystemPolicyEnabled;
16
+ private isWithinRoot;
17
+ private resolvePathForAuthorization;
18
+ private assertFilesystemAllowed;
14
19
  /**
15
20
  * Detect the appropriate shell for the current platform
16
21
  */
@@ -1 +1 @@
1
- {"version":3,"file":"shellService.d.ts","sourceRoot":"","sources":["../../src/services/shellService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EAEnB,mBAAmB,EACpB,MAAM,UAAU,CAAC;AAuBlB;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,GAAE,WAAgB;IASpC;;OAEG;IACH,OAAO,CAAC,WAAW;IAenB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB;IAuEnD;;OAEG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACzE,OAAO,CAAC,eAAe,CAAC;IAwD3B;;OAEG;IACG,SAAS,CACb,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IAiCxB;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IA4CpF;;OAEG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC;IAkC3B;;OAEG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC;CA6EhC"}
1
+ {"version":3,"file":"shellService.d.ts","sourceRoot":"","sources":["../../src/services/shellService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EAEnB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAuBrB;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,GAAE,WAAgB;IAUpC,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,yBAAyB;IAIjC,OAAO,CAAC,YAAY;YAKN,2BAA2B;YAwB3B,uBAAuB;IAoCrC;;OAEG;IACH,OAAO,CAAC,WAAW;IAenB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB;IAgFnD;;OAEG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACzE,OAAO,CAAC,eAAe,CAAC;IAwD3B;;OAEG;IACG,SAAS,CACb,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IAiCxB;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IA4CpF;;OAEG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC;IAkC3B;;OAEG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC;CA6EhC"}
@@ -37,9 +37,76 @@ export class ShellService {
37
37
  defaultShell: 'auto',
38
38
  timeout: 60000,
39
39
  blockedCommands: [],
40
+ dangerouslySkipSecurityChecks: false,
40
41
  ...config,
41
42
  };
42
43
  }
44
+ resolveAbsolutePath(filePath) {
45
+ const baseDir = this.config.workingDirectory || process.cwd();
46
+ const abs = path.isAbsolute(filePath) ? filePath : path.resolve(baseDir, filePath);
47
+ return path.normalize(abs);
48
+ }
49
+ isFilesystemPolicyEnabled() {
50
+ return !!this.config.filesystem;
51
+ }
52
+ isWithinRoot(targetPath, rootPath) {
53
+ const rel = path.relative(rootPath, targetPath);
54
+ return rel === '' || (!rel.startsWith(`..${path.sep}`) && rel !== '..' && !path.isAbsolute(rel));
55
+ }
56
+ async resolvePathForAuthorization(absolutePath, op) {
57
+ try {
58
+ return await fs.realpath(absolutePath);
59
+ }
60
+ catch {
61
+ // For writes, resolve the closest existing ancestor so symlink escapes are still detected.
62
+ if (op !== 'write')
63
+ return absolutePath;
64
+ let cursor = path.dirname(absolutePath);
65
+ while (true) {
66
+ try {
67
+ const realCursor = await fs.realpath(cursor);
68
+ const remainder = path.relative(cursor, absolutePath);
69
+ return path.join(realCursor, remainder);
70
+ }
71
+ catch {
72
+ const parent = path.dirname(cursor);
73
+ if (parent === cursor)
74
+ break;
75
+ cursor = parent;
76
+ }
77
+ }
78
+ return absolutePath;
79
+ }
80
+ }
81
+ async assertFilesystemAllowed(op, absolutePath) {
82
+ if (!this.isFilesystemPolicyEnabled())
83
+ return;
84
+ const policy = this.config.filesystem;
85
+ const allow = op === 'write' ? policy.allowWrite === true : policy.allowRead === true;
86
+ if (!allow) {
87
+ throw new Error(`Filesystem ${op} is disabled by policy`);
88
+ }
89
+ const rootsRaw = op === 'write' ? policy.writeRoots : policy.readRoots;
90
+ if (!Array.isArray(rootsRaw) || rootsRaw.length === 0) {
91
+ throw new Error(`Filesystem ${op} roots are not configured`);
92
+ }
93
+ const baseDir = this.config.workingDirectory || process.cwd();
94
+ const roots = await Promise.all(rootsRaw.map(async (root) => {
95
+ const absRoot = path.isAbsolute(root) ? root : path.resolve(baseDir, root);
96
+ const normalized = path.normalize(absRoot);
97
+ try {
98
+ return await fs.realpath(normalized);
99
+ }
100
+ catch {
101
+ return normalized;
102
+ }
103
+ }));
104
+ const authPath = await this.resolvePathForAuthorization(absolutePath, op);
105
+ const allowed = roots.some((root) => this.isWithinRoot(authPath, root));
106
+ if (!allowed) {
107
+ throw new Error(`Path is outside allowed filesystem ${op} roots: ${absolutePath}`);
108
+ }
109
+ }
43
110
  /**
44
111
  * Detect the appropriate shell for the current platform
45
112
  */
@@ -62,6 +129,14 @@ export class ShellService {
62
129
  * Check if a command is safe to execute
63
130
  */
64
131
  checkSecurity(command) {
132
+ if (this.config.dangerouslySkipSecurityChecks) {
133
+ return {
134
+ allowed: true,
135
+ reason: 'Security checks disabled by configuration',
136
+ riskLevel: 'critical',
137
+ warnings: ['Security checks are disabled'],
138
+ };
139
+ }
65
140
  const warnings = [];
66
141
  let riskLevel = 'safe';
67
142
  // Check against blocked commands list
@@ -219,9 +294,8 @@ export class ShellService {
219
294
  */
220
295
  async readFile(filePath, options) {
221
296
  const encoding = options?.encoding || 'utf-8';
222
- const absolutePath = path.isAbsolute(filePath)
223
- ? filePath
224
- : path.resolve(this.config.workingDirectory || process.cwd(), filePath);
297
+ const absolutePath = this.resolveAbsolutePath(filePath);
298
+ await this.assertFilesystemAllowed('read', absolutePath);
225
299
  const stats = await fs.stat(absolutePath);
226
300
  let content;
227
301
  let truncated = false;
@@ -263,9 +337,8 @@ export class ShellService {
263
337
  */
264
338
  async writeFile(filePath, content, options) {
265
339
  const encoding = options?.encoding || 'utf-8';
266
- const absolutePath = path.isAbsolute(filePath)
267
- ? filePath
268
- : path.resolve(this.config.workingDirectory || process.cwd(), filePath);
340
+ const absolutePath = this.resolveAbsolutePath(filePath);
341
+ await this.assertFilesystemAllowed('write', absolutePath);
269
342
  // Check if file exists
270
343
  let fileExists = true;
271
344
  try {
@@ -296,9 +369,8 @@ export class ShellService {
296
369
  * List directory contents
297
370
  */
298
371
  async listDirectory(dirPath, options) {
299
- const absolutePath = path.isAbsolute(dirPath)
300
- ? dirPath
301
- : path.resolve(this.config.workingDirectory || process.cwd(), dirPath);
372
+ const absolutePath = this.resolveAbsolutePath(dirPath);
373
+ await this.assertFilesystemAllowed('list', absolutePath);
302
374
  const entries = [];
303
375
  const readDir = async (dir, depth) => {
304
376
  const items = await fs.readdir(dir, { withFileTypes: true });
@@ -332,7 +404,7 @@ export class ShellService {
332
404
  // Include stats if requested
333
405
  if (options?.includeStats) {
334
406
  try {
335
- const stats = await fs.stat(itemPath);
407
+ const stats = await fs.lstat(itemPath);
336
408
  entry.size = stats.size;
337
409
  entry.modifiedAt = stats.mtime.toISOString();
338
410
  entry.createdAt = stats.birthtime.toISOString();