MCPcopy Create free account
hub / github.com/Zoo-Code-Org/Zoo-Code / parseCommand

Function parseCommand

src/shared/parse-command.ts:471–537  ·  view source on GitHub ↗
(command: string)

Source from the content-addressed store, hash-verified

469 * should surface the error rather than proceeding with auto-approval.
470 */
471export function parseCommand(command: string): ParseResult {
472 if (!command?.trim()) {
473 return { commands: [], parseError: null }
474 }
475
476 // Run the shared state-machine scan once. It gives us both the list of
477 // top-level quoted spans (used by maskTopLevelQuotes) and the parse-error
478 // descriptor (used here to detect malformed input) in a single pass.
479 const { unterminatedQuote } = scanTopLevelQuotes(command)
480
481 // Reject syntactically malformed input -- an unterminated quote is a shell
482 // syntax error. Return the raw input as a single opaque token so callers
483 // can surface the error to the agent rather than splitting unsafe fragments
484 // that might be auto-approved in isolation.
485 if (unterminatedQuote !== null) {
486 return { commands: [command], parseError: unterminatedQuote }
487 }
488
489 // Pre-escape any literal __ sequences present in the raw command so they
490 // cannot collide with the internal placeholder tokens (e.g. __QUOTE_0__)
491 // used during masking and splitting. \x00 (the null byte, U+0000) is the
492 // sentinel: it encodes end-of-string at the C/OS level, so the OS terminates
493 // any command string at the first \x00 -- meaning a real shell command can
494 // never contain one. It therefore cannot appear in any command text the
495 // parser receives and will never match a placeholder regex. The post-unescape
496 // step at the return converts \x00 back to __ in every output command.
497 const escapedCommand = command.replace(/__/g, "\x00")
498
499 // Mask quoted strings before splitting on newlines so that newlines embedded
500 // inside a quoted argument are not mistaken for command separators. The
501 // masker delegates to scanTopLevelQuotes internally, ensuring identical
502 // quoting rules with the check above.
503 const { masked, quotes: topLevelQuotes } = maskTopLevelQuotes(escapedCommand)
504
505 // Split on unquoted newlines (all line-ending formats).
506 const lines = masked.split(/\r\n|\r|\n/)
507 const allCommands: string[] = []
508
509 for (const line of lines) {
510 if (!line.trim()) {
511 continue
512 }
513
514 // Restore top-level quote placeholders before per-line parsing so that
515 // parseCommandLine sees the original quoted content and can apply its own
516 // masking for operator splitting.
517 const restoredLine = line.replace(/__TOPLEVEL_QUOTE_(\d+)__/g, (_, i) => topLevelQuotes[parseInt(i)])
518
519 // If the restored line contains embedded newlines it means a top-level
520 // quote (e.g. a heredoc) spanned multiple lines. The entire restored
521 // string is a single atomic command -- passing it through parseCommandLine
522 // would let shell-quote split on the embedded newlines and << operators.
523 if (restoredLine.includes("\n")) {
524 allCommands.push(restoredLine)
525 continue
526 }
527
528 const lineCommands = parseCommandLine(restoredLine)

Callers 5

executeMethod · 0.90
getCommandDecisionFunction · 0.90
CommandExecutionFunction · 0.90

Calls 4

scanTopLevelQuotesFunction · 0.85
maskTopLevelQuotesFunction · 0.85
parseCommandLineFunction · 0.85
replaceMethod · 0.65

Tested by

no test coverage detected