{"id":15288240,"url":"https://github.com/bitsofinfo/stateful-process-command-proxy","last_synced_at":"2026-03-11T22:41:05.767Z","repository":{"id":25777061,"uuid":"29215415","full_name":"bitsofinfo/stateful-process-command-proxy","owner":"bitsofinfo","description":"node.js module for executing os commands against a pool of stateful child processes such as bash or powershell via stdout and stderr streams","archived":false,"fork":false,"pushed_at":"2024-09-16T14:37:13.000Z","size":309,"stargazers_count":80,"open_issues_count":6,"forks_count":8,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-10T19:58:06.985Z","etag":null,"topics":["bash","command-line","executable","javascript","nodejs","powershell","shell"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitsofinfo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-01-13T22:48:22.000Z","updated_at":"2025-08-26T07:52:32.000Z","dependencies_parsed_at":"2024-10-30T11:02:09.292Z","dependency_job_id":"45a664b3-c003-4103-94fa-4579bd0a971f","html_url":"https://github.com/bitsofinfo/stateful-process-command-proxy","commit_stats":{"total_commits":91,"total_committers":1,"mean_commits":91.0,"dds":0.0,"last_synced_commit":"c45f4bdcacc0933a74570abfc71ee4e268c6be73"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/bitsofinfo/stateful-process-command-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitsofinfo%2Fstateful-process-command-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitsofinfo%2Fstateful-process-command-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitsofinfo%2Fstateful-process-command-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitsofinfo%2Fstateful-process-command-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitsofinfo","download_url":"https://codeload.github.com/bitsofinfo/stateful-process-command-proxy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitsofinfo%2Fstateful-process-command-proxy/sbom","scorecard":{"id":240883,"data":{"date":"2025-08-11","repo":{"name":"github.com/bitsofinfo/stateful-process-command-proxy","commit":"5da32eb199777310c5b439a9efdb3b0ac34f0ccb"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T06:39:40.857Z","repository_id":25777061,"created_at":"2025-08-17T06:39:40.858Z","updated_at":"2025-08-17T06:39:40.858Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30405563,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T22:36:59.286Z","status":"ssl_error","status_checked_at":"2026-03-11T22:36:57.544Z","response_time":84,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","command-line","executable","javascript","nodejs","powershell","shell"],"created_at":"2024-09-30T15:44:52.310Z","updated_at":"2026-03-11T22:41:05.739Z","avatar_url":"https://github.com/bitsofinfo.png","language":"JavaScript","readme":"# stateful-process-command-proxy\nNode.js module for executing os commands against a pool of stateful, long-lived child processes such as bash shells or powershell consoles\n\n[![Build Status](https://travis-ci.org/bitsofinfo/stateful-process-command-proxy.svg?branch=master)](https://travis-ci.org/bitsofinfo/stateful-process-command-proxy)\n\n[![NPM](https://nodei.co/npm/stateful-process-command-proxy.png?downloads=true\u0026downloadRank=true\u0026stars=true)](https://nodei.co/npm/stateful-process-command-proxy/)\n[![NPM](https://nodei.co/npm-dl/stateful-process-command-proxy.png)](https://nodei.co/npm/stateful-process-command-proxy/)\n\nThis node module can be used for proxying long-lived bash process, windows console etc. It works and has been tested on both linux, os-x and windows hosts running the latest version of node.\n\n* [Origin](#origin)\n* [Features](#features)\n* [Install \u0026 Tests](#install)\n* [History](#history)\n* [Usage](#usage)\n* [Example](#example)\n* [Security](#security)\n* [Related Tools](#related)\n\n### \u003ca id=\"Origin\"\u003e\u003c/a\u003e Origin\n\nThis project originated out of the need to execute various Powershell commands (at fairly high volume and frequency) against services within Office365/Azure bridged via a custom node.js implemented REST API; this was due to the lack of certain features in the REST GraphAPI for Azure/o365, that are available only in Powershell.\n\nIf you have done any work with Powershell and o365, then you know that there is considerable overhead in both establishing a remote session and importing and downloading various needed cmdlets. This is an expensive operation and there is a lot of value in being able to keep this remote session open for longer periods of time rather than repeating this entire process for every single command that needs to be executed and then tearing everything down.\n\nSimply doing an child_process.**exec** per command to launch an external process, run the command, and then killing the process is not really an option under such scenarios, as it is expensive and very singular in nature; no state can be maintained if need be. We also tried using [edge.js with powershell](https://github.com/tjanczuk/edge#how-to-script-powershell-in-a-nodejs-application) and this simply would not work with o365 exchange commands and heavy session cmdlet imports (the entire node.js process would crash). Using this module gives you full un-fettered access to the externally connected child_process, with no restrictions other than what uid/gid (permissions) the spawned process is running under (which you **really** have to consider from security standpoint!)\n\nThe diagram below should conceptually give you an idea of what this module does.\n\n**The local user that the node process runs as should have virtually zero rights! Also be sure to properly configure a restricted UID/GID when instatiating a new instance of this. See security notes below.**\n\n![Alt text](/diagram.png \"Diagram1\")\n\n### \u003ca id=\"features\"\u003e\u003c/a\u003e Features\n\n* Works with any operating system that can run Node.js\n* Tested w/ Bash and Powershell, and should work with virtually any other shell or interactive spawnable process which can be communicated with over STDIN, STDOUT, STDERR streams.\n* Maintains a configurable pool of re-usable processes that are checked out/in when commands need to be executed\n* Command whitelisting and blacklisting\n* Definable list of \"init\" and \"destroy\" commands to be run as processes are created/destroyed\n* Definable configuration for \"auto-invalidation\" of active processes\n* Can be configured to maintain a \"history\" of commands run against each proxied process, useful for reporting or auditing purposes\n\n### \u003ca id=\"install\"\u003e\u003c/a\u003e Install \u0026 Tests\n\n```\nnpm install stateful-process-command-proxy\n```\n\n```\nnpm install mocha\nmocha test/all.js\n```\n\n### \u003ca id=\"history\"\u003e\u003c/a\u003e History\n\n```\nv1.0.2 - 2024-09-16\n    - Address #21 Fix slice cropping data output\n\nv1.0.1 - 2016-11-10\n    - Address #13 (force generic-pool 2.4.4)\n    \nv1.0.0 - 2016-06-08\n    - Address #7 and #8 (regex w/ global flag reset, arguments in strict-mode)\n\nv1.0-beta.8 - 2015-03-19\n    - Address memory leaks\n\nv1.0-beta.7 - 2015-02-05\n    - Blacklist logging fix\n\nv1.0-beta.6 - 2015-01-30\n    - bug fixes, for auto-invalidation cmds being auto-whitelisted\n\nv1.0-beta.5 - 2015-01-28\n    - whitelisting fix\n\nv1.0-beta.4 - 2015-01-28\n    - New options for command whitelist regex matching\n      Note new parameter order in ProcessProxy constructor!\n\n    - Support for regex flags for all regex based configs\n\n    - All regex pattern based configurations now must be objects\n      in format {regex:'pattern' [,flags:'img etc']}\n\nv1.0-beta.3 - 2015-01-26\n    - New options for command blacklisting regex matching and interval\n      based self auto-invalidation of ProcessProxy instances\n\nv1.0-beta.2 - 2015-01-21\n    - New return types for executeCommands - is now an array\n\nv1.0-beta.1 - 2015-01-17\n    - Initial version\n```\n\n### \u003ca id=\"usage\"\u003e\u003c/a\u003e Usage\n\nTo use StatefulProcessCommandProxy the constructor takes one parameter which is a configuration object who's properties are described below. Please refer to the example (following) and the unit-test for more details.\n\n```\n    name:           The name of this instance, arbitrary\n\n    max:               maximum number of processes to maintain\n\n    min:               minimum number of processes to maintain\n\n    idleTimeoutMS:     idle in milliseconds by which a process will be destroyed\n\n    processCommand: full path to the actual process to be spawned (i.e. /bin/bash)\n\n    processArgs:    arguments to pass to the process command\n\n    processRetainMaxCmdHistory: for each process spawned, the maximum number\n                                of command history objects to retain in memory\n                                (useful for debugging), default 0\n\n    processInvalidateOnRegex: optional config of regex patterns who if match\n                              their respective type, will flag the process as invalid\n                                          {\n                                         'any' :    [ {regex:'regex1',flags:'ig'}, ....],\n                                         'stdout' : [ {regex:'regex1',flags:'m'}, ....],\n                                         'stderr' : [ {regex:'regex1',flags:'ig'}, ....]\n                                         }\n\n   processCmdBlacklistRegex: optional config array regex patterns who if match the\n                             command requested to be executed will be rejected\n                             with an error. Blacklists run before whitelists\n\n                                     [ {regex:'regex1',flags:'ig'},\n                                       {regex:'regex2',flags:'ig'}...]\n\n   processCmdWhitelistRegex: optional config array regex patterns defining commands\n                             that are permitted to execute, if no match, the command\n                             will be rejected. Whitelists run after blacklists\n\n                                       [ {regex:'regex1',flags:'ig'},\n                                         {regex:'regex2',flags:'ig'}...]\n\n    processCwd:    optional current working directory for the processes to be spawned\n\n    processEnvMap: optional hash/object of key-value pairs for environment variables\n                   to set for the spawned processes\n\n    processUid:    optional uid to launch the processes as\n\n    processGid:    optional gid to launch the processes as\n\n    logFunction:    optional function that should have the signature\n                    (severity,origin,message), where log messages will\n                    be sent to. If null, logs will just go to console\n\n    initCommands:   optional array of actual commands to execute on each newly\n                    spawned ProcessProxy in the pool before it is made available\n\n    preDestroyCommands: optional array of actual commands to execute on a process\n                        before it is killed/destroyed on shutdown or being invalid\n\n    validateFunction:  optional function that should have the signature to accept\n                       a ProcessProxy object, and should return true/false if the\n                       process is valid or not, at a minimum this should call\n                       ProcessProxy.isValid(). If the function is not provided\n                       the default behavior is to only check ProcessProxy.isValid()\n\n    autoInvalidationConfig optional configuration that will run the specified\n                           commands in the background on the given interval,\n                           and if the given regexes match/do-not-match for each command the\n                           ProcessProxy will be flagged as invalid and return FALSE\n                           on calls to isValid(). The commands will be run in\n                           order sequentially via executeCommands()\n        {\n           checkIntervalMS: 30000; // check every 30s\n           commands:\n              [\n               { command:'cmd1toRun',\n\n                 // OPTIONAL: because you can configure multiple commands\n                 // where the first ones doe some prep, then the last one's\n                 // output needs to be evaluated hence 'regexes'  may not\n                 // always be present, (but your LAST command must have a\n                 // regexes config to eval prior work, otherwise whats the point\n\n                 regexes: {\n                        // at least one key must be specified\n                        // 'any' means either stdout or stderr\n                        // for each regex, the 'on' property dictates\n                        // if the process will be flagged invalid based\n                        // on the results of the regex evaluation\n                       'any' :    [ {regex:'regex1', flags:'m', invalidOn:'match | noMatch'}, ....],\n                       'stdout' : [ {regex:'regex1', flags:'ig', invalidOn:'match | noMatch'}, ....],\n                       'stderr' : [ {regex:'regex1', flags:'i', invalidOn:'match | noMatch'}, ....]\n                  }\n              },...\n            ]\n       }\n```\n\nIts highly recommended you check out the unit-tests for some examples in addition to the below:\n\n### \u003ca id=\"example\"\u003e\u003c/a\u003e Example\n\nNote this example is for a machine w/ bash in the typical location on *nix machines (i.e. linux or os-x). Windows (or other) can adjust the below as necessary to run their shell of choice, dos/powershell etc).\n\n```\nvar Promise = require('promise');\nvar StatefulProcessCommandProxy = require(\"./\");\n\nvar statefulProcessCommandProxy = new StatefulProcessCommandProxy(\n    {\n      name: \"test\",\n      max: 2,\n      min: 2,\n      idleTimeoutMS: 10000,\n\n      logFunction: function(severity,origin,msg) {\n          console.log(severity.toUpperCase() + \" \" +origin+\" \"+ msg);\n      },\n\n      processCommand: '/bin/bash',\n      processArgs:  ['-s'],\n      processRetainMaxCmdHistory : 10,\n\n      processInvalidateOnRegex :\n          {\n            'any':[{regex:'.*error.*',flags:'ig'}],\n            'stdout':[{regex:'.*error.*',flags:'ig'}],\n            'stderr':[{regex:'.*error.*',flags:'ig'}]\n          },\n\n      processCwd : './',\n      processEnvMap : {\"testEnvVar\":\"value1\"},\n      processUid : null,\n      processGid : null,\n\n      initCommands: [ 'testInitVar=test' ],\n\n      validateFunction: function(processProxy) {\n          return processProxy.isValid();\n      },\n\n      preDestroyCommands: [ 'echo This ProcessProxy is being destroyed!' ]\n    });\n\n// echo the value of our env variable set above in the constructor config\nstatefulProcessCommandProxy.executeCommand('echo testEnvVar')\n  .then(function(cmdResult) {\n      console.log(\"testEnvVar value: Stdout: \" + cmdResult.stdout);\n  }).catch(function(error) {\n      console.log(\"Error: \" + error);\n  });\n\n// echo the value of our init command that was configured above\nstatefulProcessCommandProxy.executeCommand('echo testInitVar')\n  .then(function(cmdResult) {\n      console.log(\"testInitVar value: Stdout: \" + cmdResult.stdout);\n  }).catch(function(error) {\n      console.log(\"Error: \" + error);\n  });\n\n// test that our invalidation regex above traps and destroys this process instance\nstatefulProcessCommandProxy.executeCommand('echo \"this command has an error and will be '+\n                ' destroyed after check-in because it matches our invalidation regex\"')\n  .then(function(cmdResult) {\n      console.log(\"error test: Stdout: \" + cmdResult.stdout);\n  }).catch(function(error) {\n      console.log(\"Error: \" + error);\n  });\n\n// set a var in the shell\nstatefulProcessCommandProxy.executeCommand('MY_VARIABLE=test1;echo MY_VARIABLE WAS JUST SET')\n  .then(function(cmdResult) {\n      console.log(\"Stdout: \" + cmdResult.stdout);\n  }).catch(function(error) {\n      console.log(\"Error: \" + error);\n  });\n\n// echo it back\nstatefulProcessCommandProxy.executeCommand('echo $MY_VARIABLE')\n  .then(function(cmdResult) {\n      console.log(\"MY_VARIABLE value: Stdout: \" + cmdResult.stdout);\n  }).catch(function(error) {\n      console.log(\"Error: \" + error);\n  });\n\n// shutdown the statefulProcessCommandProxy\n// this is important and your destroy hooks will\n// be called at this time.\nsetTimeout(function() {\n  statefulProcessCommandProxy.shutdown();\n},10000);\n\n```\n\n### \u003ca id=\"security\"\u003e\u003c/a\u003e Security\n\nObviously this module can expose you to some insecure situations depending on how you use it... you are providing a gateway to an external process via Node on your host os! (likely a shell in most use-cases). Here are some tips; ultimately its your responsibility to secure your system.\n\n* Read OWASPs article on command injection - https://www.owasp.org/index.php/Command_Injection\n* Ensure that the node process is running as a user with very limited rights\n* Make use of the uid/gid configuration appropriately to further limit the processes\n* Make use of the whitelisted and blacklisted command configuration feature to mitigate your exposure\n* Never expose calls to this module directly, instead you should write a wrapper layer around StatefulProcessCommandProxy that protects, analyzes and sanitizes external input that can materialize in a `command` statement. For an example of this kind of wrapper w/ sanitization of arguments see https://github.com/bitsofinfo/powershell-command-executor\n* All commands you pass to `execute` should be sanitized to protect from injection attacks. The type of sanitization you do is up to you and is obviously different depending on what shell/process type you are mediating access to via this module.\n\n### \u003ca id=\"related\"\u003e\u003c/a\u003e Related Tools\n\nHave a look at these related projects which build on top of this module to provide some higher level functionality\n\n* https://github.com/bitsofinfo/io-event-reactor - Leverages `stateful-process-command-proxy` to execute shell commands in reaction to IO events\n* https://github.com/bitsofinfo/powershell-command-executor - Introduces a higher level \"registry\" of powershell commands which can be generated, have arguments applied to them (and sanitized), then executed.\n* https://github.com/bitsofinfo/powershell-command-executor-ui - Builds on top of powershell-command-executor to provide a simple Node REST API and AngularJS interface for testing the execution of commands in the registry\n* https://github.com/bitsofinfo/meteor-shell-command-mgr - Small Meteor app that lets you manage/generate a command registry for powershell-command-executor\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitsofinfo%2Fstateful-process-command-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitsofinfo%2Fstateful-process-command-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitsofinfo%2Fstateful-process-command-proxy/lists"}