MCPcopy
hub / github.com/Doorman11991/smallcode / run

Method run

src/tools/shell_session.js:155–242  ·  view source on GitHub ↗

* Run a command in the persistent shell. Returns { stdout, exitCode, timedOut }. * Output is sanitized (ANSI stripped, secrets redacted) before returning.

(command)

Source from the content-addressed store, hash-verified

153 * Output is sanitized (ANSI stripped, secrets redacted) before returning.
154 */
155 async run(command) {
156 if (this._dead) {
157 // Auto-restart on dead shell
158 const ok = await this.start();
159 if (!ok) return { stdout: '', exitCode: -1, timedOut: false, error: 'shell unavailable' };
160 }
161 if (!this.proc) {
162 const ok = await this.start();
163 if (!ok) return { stdout: '', exitCode: -1, timedOut: false, error: 'shell failed to start' };
164 }
165
166 // Optional containment: parse cwd-changing commands and reject ones that
167 // would leave the project root. We strip leading `;` `&` `&&` so chained
168 // commands are inspected too. Catches:
169 // cd ../../etc
170 // cd "../../etc"
171 // cd '..'
172 // pushd ..
173 // ; cd ..
174 // && cd ..
175 // bash -c "cd .." (refused outright — sub-shells bypass our wrapper)
176 // sh -c '...' (same)
177 if (this.containCwd) {
178 // Reject sub-shell escapes — we cannot track cwd through them
179 if (/\b(?:bash|sh|zsh|ksh|fish|pwsh|powershell|cmd)\s+-c\b/.test(command)) {
180 return { stdout: `(refused: -c sub-shells bypass cwd containment)\n`, exitCode: 1, timedOut: false };
181 }
182 // Iterate every cd / pushd / chdir (chained or not)
183 const cdRe = /(?:^|[;&|])\s*(?:cd|pushd|chdir)\s+([^\s;&|]+)/g;
184 let cdMatch;
185 let simulatedCwd = this.cwd;
186 while ((cdMatch = cdRe.exec(command))) {
187 const target = cdMatch[1].replace(/^['"]|['"]$/g, '');
188 const resolved = path.isAbsolute(target) ? target : path.resolve(simulatedCwd, target);
189 const rel = path.relative(this.rootDir, resolved);
190 if (rel.startsWith('..') || path.isAbsolute(rel)) {
191 return { stdout: `(cd refused: target outside project root)\n`, exitCode: 1, timedOut: false };
192 }
193 simulatedCwd = resolved;
194 }
195 }
196
197 const sentinel = SENTINEL_PREFIX + crypto.randomBytes(8).toString('hex');
198 const isWin = process.platform === 'win32';
199
200 // Wrap the command so we can detect end-of-output and capture exit code.
201 // POSIX: `; printf "\n__SENTINEL__%d__\n" $?`
202 // Windows cmd: `& echo __SENTINEL__%errorlevel%__`
203 const wrapped = isWin
204 ? `${command}\r\n@echo ${sentinel}_%errorlevel%_\r\n`
205 : `${command}\nprintf '\\n${sentinel}_%d_\\n' $?\n`;
206
207 return new Promise((resolve) => {
208 let timedOut = false;
209 const timer = setTimeout(() => {
210 timedOut = true;
211 // On timeout we mark the shell dead and reset it — the next command
212 // will spawn a fresh shell. Half-measures (writing \n, sending SIGINT)

Callers 1

pwdMethod · 0.95

Calls 4

startMethod · 0.95
_failPendingMethod · 0.95
killMethod · 0.80
writeMethod · 0.65

Tested by

no test coverage detected