diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index e697b54..0000000 --- a/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -# ignore these files when generating release tarballs -.editorconfig export-ignore -.gitattributes export-ignore -.gitignore export-ignore -CONTRIBUTING.md export-ignore -install.sh export-ignore -Pipfile export-ignore -Pipfile.lock export-ignore -README.md export-ignore -release.sh export-ignore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..af2327c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: Build and Release +on: + push: + tags: + - 'v*.*.*' + +jobs: + build: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + artifact_name: [windows, linux, macos] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install dependencies + run: pip install -r requirements.txt + - name: Build binary + run: pyinstaller --onefile gpt_cmd.py + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact_name }} + path: dist/gpt_cmd + + release: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + - name: Download artifacts + uses: actions/download-artifact@v4 + - name: Rename artifacts + run: | + for os in windows linux macos; do + echo "Moving ${os}/dist/gpt_cmd to gpt_cmd-${os}" + mv "${os}/dist/gpt_cmd" "gpt_cmd-${os}" + rm -rf "${os}/" + done + - name: Create release + uses: ncipollo/release-action@v1.14.0 + with: + artifacts: gpt_cmd-linux,gpt_cmd-macos,gpt_cmd-windows + tag: ${{ github.ref }} + name: ${{ github.ref }} diff --git a/.gitignore b/.gitignore index 5d82fa9..ffb4f6a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .DS_Store **/__pycache__/ -vendor/ +build/ +dist/ +env/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e5b256..039568b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,14 +5,14 @@ First, install the dependencies (**note**: make sure you're using python 3 and pip 3): ```sh -# install pipenv -brew install pipenv +# create virtual env +python -m venv env -# install both runtime and dev dependencies -pipenv install --dev +# activate env +source env/bin/activate -# activate the virtual env -pipenv shell +# install deps +pip install -r requirements.txt ``` Now you can run the tool via: @@ -23,10 +23,6 @@ python -m gpt_cmd [...] ## Cutting a release -Currently this just updates the `vendor` tarball (only needed if deps were added/upgraded): +Pushing a version tag (e.g. `v.1.0.0`) will trigger the [release.yml](.github/workflows/release.yml) GitHub action, which will build binaries for supported OSes and publish a release with them. -```sh -./release.sh -``` - -This script requires all the tools mentioned in the [Running locally](#running-locally) section. +The binaries are generated using [pyinstaller](https://pyinstaller.org/en/stable/). diff --git a/Pipfile b/Pipfile deleted file mode 100644 index e7946d7..0000000 --- a/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -openai = "*" - -[dev-packages] -black = "*" - -[requires] -python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index b874e18..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,281 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "c994f1e7752fb56fccd28d828b7a1dc2ec0c17632a4eb054cf9cc4e8ad6f1828" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "annotated-types": { - "hashes": [ - "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", - "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" - ], - "markers": "python_version >= '3.8'", - "version": "==0.7.0" - }, - "anyio": { - "hashes": [ - "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94", - "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7" - ], - "markers": "python_version >= '3.8'", - "version": "==4.4.0" - }, - "certifi": { - "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" - ], - "markers": "python_version >= '3.6'", - "version": "==2024.2.2" - }, - "distro": { - "hashes": [ - "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", - "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2" - ], - "markers": "python_version >= '3.6'", - "version": "==1.9.0" - }, - "h11": { - "hashes": [ - "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", - "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" - ], - "markers": "python_version >= '3.7'", - "version": "==0.14.0" - }, - "httpcore": { - "hashes": [ - "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61", - "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5" - ], - "markers": "python_version >= '3.8'", - "version": "==1.0.5" - }, - "httpx": { - "hashes": [ - "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5", - "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5" - ], - "markers": "python_version >= '3.8'", - "version": "==0.27.0" - }, - "idna": { - "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" - ], - "markers": "python_version >= '3.5'", - "version": "==3.7" - }, - "openai": { - "hashes": [ - "sha256:f3488d9a1c4e0d332b019377d27d7cb4b3d6103fd5d0a416c7ceac780d1d9b88", - "sha256:fb2635efd270efaf9fac2e07558d7948373b940637d3ae3ab624c1a983d4f03f" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.1'", - "version": "==1.30.4" - }, - "pydantic": { - "hashes": [ - "sha256:71b2945998f9c9b7919a45bde9a50397b289937d215ae141c1d0903ba7149fd7", - "sha256:834ab954175f94e6e68258537dc49402c4a5e9d0409b9f1b86b7e934a8372de7" - ], - "markers": "python_version >= '3.8'", - "version": "==2.7.2" - }, - "pydantic-core": { - "hashes": [ - "sha256:0bee9bb305a562f8b9271855afb6ce00223f545de3d68560b3c1649c7c5295e9", - "sha256:0ecce4b2360aa3f008da3327d652e74a0e743908eac306198b47e1c58b03dd2b", - "sha256:17954d784bf8abfc0ec2a633108207ebc4fa2df1a0e4c0c3ccbaa9bb01d2c426", - "sha256:19d2e725de0f90d8671f89e420d36c3dd97639b98145e42fcc0e1f6d492a46dc", - "sha256:1f9cd7f5635b719939019be9bda47ecb56e165e51dd26c9a217a433e3d0d59a9", - "sha256:200ad4e3133cb99ed82342a101a5abf3d924722e71cd581cc113fe828f727fbc", - "sha256:24b214b7ee3bd3b865e963dbed0f8bc5375f49449d70e8d407b567af3222aae4", - "sha256:2c44efdd3b6125419c28821590d7ec891c9cb0dff33a7a78d9d5c8b6f66b9702", - "sha256:2c8333f6e934733483c7eddffdb094c143b9463d2af7e6bd85ebcb2d4a1b82c6", - "sha256:2f7ef5f0ebb77ba24c9970da18b771711edc5feaf00c10b18461e0f5f5949231", - "sha256:304378b7bf92206036c8ddd83a2ba7b7d1a5b425acafff637172a3aa72ad7083", - "sha256:370059b7883485c9edb9655355ff46d912f4b03b009d929220d9294c7fd9fd60", - "sha256:37b40c05ced1ba4218b14986fe6f283d22e1ae2ff4c8e28881a70fb81fbfcda7", - "sha256:3d3e42bb54e7e9d72c13ce112e02eb1b3b55681ee948d748842171201a03a98a", - "sha256:3fc1c7f67f34c6c2ef9c213e0f2a351797cda98249d9ca56a70ce4ebcaba45f4", - "sha256:41dbdcb0c7252b58fa931fec47937edb422c9cb22528f41cb8963665c372caf6", - "sha256:432e999088d85c8f36b9a3f769a8e2b57aabd817bbb729a90d1fe7f18f6f1f39", - "sha256:45e4ffbae34f7ae30d0047697e724e534a7ec0a82ef9994b7913a412c21462a0", - "sha256:4afa5f5973e8572b5c0dcb4e2d4fda7890e7cd63329bd5cc3263a25c92ef0026", - "sha256:544a9a75622357076efb6b311983ff190fbfb3c12fc3a853122b34d3d358126c", - "sha256:5560dda746c44b48bf82b3d191d74fe8efc5686a9ef18e69bdabccbbb9ad9442", - "sha256:58ff8631dbab6c7c982e6425da8347108449321f61fe427c52ddfadd66642af7", - "sha256:5a64faeedfd8254f05f5cf6fc755023a7e1606af3959cfc1a9285744cc711044", - "sha256:60e4c625e6f7155d7d0dcac151edf5858102bc61bf959d04469ca6ee4e8381bd", - "sha256:616221a6d473c5b9aa83fa8982745441f6a4a62a66436be9445c65f241b86c94", - "sha256:63081a49dddc6124754b32a3774331467bfc3d2bd5ff8f10df36a95602560361", - "sha256:666e45cf071669fde468886654742fa10b0e74cd0fa0430a46ba6056b24fb0af", - "sha256:67bc078025d70ec5aefe6200ef094576c9d86bd36982df1301c758a9fff7d7f4", - "sha256:691018785779766127f531674fa82bb368df5b36b461622b12e176c18e119022", - "sha256:6a36f78674cbddc165abab0df961b5f96b14461d05feec5e1f78da58808b97e7", - "sha256:6afd5c867a74c4d314c557b5ea9520183fadfbd1df4c2d6e09fd0d990ce412cd", - "sha256:6b32c2a1f8032570842257e4c19288eba9a2bba4712af542327de9a1204faff8", - "sha256:6e59fca51ffbdd1638b3856779342ed69bcecb8484c1d4b8bdb237d0eb5a45e2", - "sha256:70cf099197d6b98953468461d753563b28e73cf1eade2ffe069675d2657ed1d5", - "sha256:73038d66614d2e5cde30435b5afdced2b473b4c77d4ca3a8624dd3e41a9c19be", - "sha256:744697428fcdec6be5670460b578161d1ffe34743a5c15656be7ea82b008197c", - "sha256:77319771a026f7c7d29c6ebc623de889e9563b7087911b46fd06c044a12aa5e9", - "sha256:7a20dded653e516a4655f4c98e97ccafb13753987434fe7cf044aa25f5b7d417", - "sha256:7e6382ce89a92bc1d0c0c5edd51e931432202b9080dc921d8d003e616402efd1", - "sha256:7fdd362f6a586e681ff86550b2379e532fee63c52def1c666887956748eaa326", - "sha256:80aea0ffeb1049336043d07799eace1c9602519fb3192916ff525b0287b2b1e4", - "sha256:82f2718430098bcdf60402136c845e4126a189959d103900ebabb6774a5d9fdb", - "sha256:855ec66589c68aa367d989da5c4755bb74ee92ccad4fdb6af942c3612c067e34", - "sha256:9128089da8f4fe73f7a91973895ebf2502539d627891a14034e45fb9e707e26d", - "sha256:929c24e9dea3990bc8bcd27c5f2d3916c0c86f5511d2caa69e0d5290115344a9", - "sha256:98ed737567d8f2ecd54f7c8d4f8572ca7c7921ede93a2e52939416170d357812", - "sha256:9a46795b1f3beb167eaee91736d5d17ac3a994bf2215a996aed825a45f897558", - "sha256:9f9e04afebd3ed8c15d67a564ed0a34b54e52136c6d40d14c5547b238390e779", - "sha256:a4e651e47d981c1b701dcc74ab8fec5a60a5b004650416b4abbef13db23bc7be", - "sha256:a62e437d687cc148381bdd5f51e3e81f5b20a735c55f690c5be94e05da2b0d5c", - "sha256:aaee40f25bba38132e655ffa3d1998a6d576ba7cf81deff8bfa189fb43fd2bbe", - "sha256:adf952c3f4100e203cbaf8e0c907c835d3e28f9041474e52b651761dc248a3c0", - "sha256:b367a73a414bbb08507da102dc2cde0fa7afe57d09b3240ce82a16d608a7679c", - "sha256:b8e20e15d18bf7dbb453be78a2d858f946f5cdf06c5072453dace00ab652e2b2", - "sha256:b95a0972fac2b1ff3c94629fc9081b16371dad870959f1408cc33b2f78ad347a", - "sha256:b9ebe8231726c49518b16b237b9fe0d7d361dd221302af511a83d4ada01183ab", - "sha256:ba905d184f62e7ddbb7a5a751d8a5c805463511c7b08d1aca4a3e8c11f2e5048", - "sha256:bd4435b8d83f0c9561a2a9585b1de78f1abb17cb0cef5f39bf6a4b47d19bafe3", - "sha256:bd7df92f28d351bb9f12470f4c533cf03d1b52ec5a6e5c58c65b183055a60106", - "sha256:c0037a92cf0c580ed14e10953cdd26528e8796307bb8bb312dc65f71547df04d", - "sha256:c0d9ff283cd3459fa0bf9b0256a2b6f01ac1ff9ffb034e24457b9035f75587cb", - "sha256:c56eca1686539fa0c9bda992e7bd6a37583f20083c37590413381acfc5f192d6", - "sha256:c6ac9ffccc9d2e69d9fba841441d4259cb668ac180e51b30d3632cd7abca2b9b", - "sha256:c826870b277143e701c9ccf34ebc33ddb4d072612683a044e7cce2d52f6c3fef", - "sha256:cd4a032bb65cc132cae1fe3e52877daecc2097965cd3914e44fbd12b00dae7c5", - "sha256:d33ce258e4e6e6038f2b9e8b8a631d17d017567db43483314993b3ca345dcbbb", - "sha256:d531076bdfb65af593326ffd567e6ab3da145020dafb9187a1d131064a55f97c", - "sha256:dccf3ef1400390ddd1fb55bf0632209d39140552d068ee5ac45553b556780e06", - "sha256:df11fa992e9f576473038510d66dd305bcd51d7dd508c163a8c8fe148454e059", - "sha256:e1a8376fef60790152564b0eab376b3e23dd6e54f29d84aad46f7b264ecca943", - "sha256:e201935d282707394f3668380e41ccf25b5794d1b131cdd96b07f615a33ca4b1", - "sha256:e2e253af04ceaebde8eb201eb3f3e3e7e390f2d275a88300d6a1959d710539e2", - "sha256:e862823be114387257dacbfa7d78547165a85d7add33b446ca4f4fae92c7ff5c", - "sha256:eecf63195be644b0396f972c82598cd15693550f0ff236dcf7ab92e2eb6d3522", - "sha256:f0928cde2ae416a2d1ebe6dee324709c6f73e93494d8c7aea92df99aab1fc40f", - "sha256:f9c08cabff68704a1b4667d33f534d544b8a07b8e5d039c37067fceb18789e78", - "sha256:fec02527e1e03257aa25b1a4dcbe697b40a22f1229f5d026503e8b7ff6d2eda7", - "sha256:ff58f379345603d940e461eae474b6bbb6dab66ed9a851ecd3cb3709bf4dcf6a", - "sha256:ffecbb5edb7f5ffae13599aec33b735e9e4c7676ca1633c60f2c606beb17efc5" - ], - "markers": "python_version >= '3.8'", - "version": "==2.18.3" - }, - "sniffio": { - "hashes": [ - "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", - "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.1" - }, - "tqdm": { - "hashes": [ - "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644", - "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb" - ], - "markers": "python_version >= '3.7'", - "version": "==4.66.4" - }, - "typing-extensions": { - "hashes": [ - "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", - "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" - ], - "markers": "python_version >= '3.8'", - "version": "==4.12.0" - } - }, - "develop": { - "black": { - "hashes": [ - "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474", - "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1", - "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0", - "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8", - "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96", - "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1", - "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04", - "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021", - "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94", - "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d", - "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c", - "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7", - "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c", - "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc", - "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7", - "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d", - "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c", - "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741", - "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce", - "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb", - "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063", - "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==24.4.2" - }, - "click": { - "hashes": [ - "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", - "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.7" - }, - "mypy-extensions": { - "hashes": [ - "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", - "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.0" - }, - "packaging": { - "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" - ], - "markers": "python_version >= '3.7'", - "version": "==24.0" - }, - "pathspec": { - "hashes": [ - "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", - "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "platformdirs": { - "hashes": [ - "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", - "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" - ], - "markers": "python_version >= '3.8'", - "version": "==4.2.2" - } - } -} diff --git a/bin/gpt_cmd b/bin/gpt_cmd deleted file mode 100755 index 09c838f..0000000 --- a/bin/gpt_cmd +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -e - -project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" - -function quit_python_required() { - echo "ERROR: python 3 is required to run gpt_cmd" >&2 - exit 1 -} - -function get_python_bin() { - if command -v python3 >/dev/null; then - echo "python3" - return 0 - elif command -v python >/dev/null; then - major_version="$(python --version | grep -oE '[0-9]+' | head -1)" - if [ "$major_version" -ne 3 ]; then - quit_python_required - fi - - echo "python" - return 0 - fi - - quit_python_required -} - -export PYTHONPATH="$project_root/vendor" -export GPT_CMD_PROJECT_ROOT="$project_root" -$(get_python_bin) "$project_root/gpt_cmd.py" "$@" diff --git a/gpt_cmd.py b/gpt_cmd.py index 6c98049..417bfda 100644 --- a/gpt_cmd.py +++ b/gpt_cmd.py @@ -5,6 +5,20 @@ import sys from openai import OpenAI +SYSTEM_PROMPT = ''' +Your job is to run commands necessary for achieving a task from a terminal. + +You'll be provided with an end goal, and you'll send replies in JSON format containing an array of commands to run in the terminal. Each time you send command(s) to run, you'll then be provided with the resulting stdout and stderr (you're being accessed via the OpenAI API, so when possible, include arguments in your commands to reduce noise in stdout and stderr to limit API usage). + +To convey context, you can use a JSON object with `context` (string) and `commands` (array). + +When you believe that the end goal is accomplished or unrecoverably failed, send a JSON object containing `status` ("success" or "failed") and `context` (noting things like commands that can be used to use any tools you installed, or why it failed if it did). + +IMPORTANT NOTE: each command you provide is being executed in a subshell via a python script, which means things like `cd` won't persist across commands, so you'll need to account for that. + +IMPORTANT NOTE: in your response to the first user prompt, generate a short (5 words max) dash-separated file name to describe their prompt. Provide this in a `convo-file-name` property in your JSON object. +''' + def ensure_dir(directory): if not os.path.exists(directory): os.makedirs(directory, exist_ok=True) @@ -27,13 +41,8 @@ def write_file(file_path, content): ), } -# trust path provided by entrypoint bash script over `__file__`, -# which can be a relative path in some cases -PROJECT_ROOT_DIR = os.path.normpath( - os.environ.get('GPT_CMD_PROJECT_ROOT', os.path.dirname(__file__)) -) -CONVOS_DIR = os.path.join(PROJECT_ROOT_DIR, '.convos') -SYSTEM_PROMPT = read_file(os.path.join(PROJECT_ROOT_DIR, 'system-prompt.txt')) +PROJECT_FILES_DIR = os.path.join(os.path.expanduser('~'), '.gpt_cmd') +CONVOS_DIR = os.path.join(PROJECT_FILES_DIR, '.convos') OPENAI_CLIENT = None class ansi: @@ -145,7 +154,7 @@ def save_convo(): print(response['context']) save_convo() - exit(0 if was_success else 1) + sys.exit(0 if was_success else 1) if isinstance(response.get('context'), str): print(f"{ansi.blue('Context:')} {response['context']}") @@ -162,7 +171,7 @@ def save_convo(): clear_prev_line() else: save_convo() - exit(1) + sys.exit(1) stdout, exit_code = exec_cmd(cmd) cmd_ansi_color = ansi.green if exit_code == 0 else ansi.red @@ -177,22 +186,22 @@ def save_convo(): else: print(ansi.red('ERROR: No further commands provided, and no success/failure signal was provided')) save_convo() - exit(1) + sys.exit(1) if __name__ == "__main__": helptext = 'Usage:\ngpt_cmd \ngpt_cmd --get-convos-dir' if len(sys.argv) != 2: print(helptext) - sys.exit(1) + sys.sys.exit(1) if sys.argv[1] == '--help': print(helptext) - exit(0) + sys.exit(0) if sys.argv[1] == '--get-convos-dir': print(CONVOS_DIR) - exit(0) + sys.exit(0) goal = sys.argv[1] main(goal) diff --git a/gpt_cmd.spec b/gpt_cmd.spec new file mode 100644 index 0000000..3efab29 --- /dev/null +++ b/gpt_cmd.spec @@ -0,0 +1,38 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['gpt_cmd.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='gpt_cmd', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/install.sh b/install.sh index f4d261d..65624ba 100755 --- a/install.sh +++ b/install.sh @@ -2,6 +2,8 @@ set -e +# FIXME: update to use new binary approach + ansi_blue='\033[94m' ansi_green='\033[92m' ansi_red='\033[91m' diff --git a/release.sh b/release.sh deleted file mode 100755 index 20d285e..0000000 --- a/release.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -# install deps into `vendor` dir and zip it up into a tarball for the repo -pip install --target=vendor -r <(pipenv requirements) -tar -czf ./vendor.tar.gz vendor -rm -rf ./vendor diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8dfce69 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,20 @@ +altgraph==0.17.4 +annotated-types==0.7.0 +anyio==4.4.0 +certifi==2024.2.2 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.5 +httpx==0.27.0 +idna==3.7 +macholib==1.16.3 +openai==1.30.4 +packaging==24.0 +pydantic==2.7.2 +pydantic_core==2.18.3 +pyinstaller==6.7.0 +pyinstaller-hooks-contrib==2024.6 +setuptools==70.0.0 +sniffio==1.3.1 +tqdm==4.66.4 +typing_extensions==4.12.0 diff --git a/system-prompt.txt b/system-prompt.txt deleted file mode 100644 index 9eb5ee2..0000000 --- a/system-prompt.txt +++ /dev/null @@ -1,11 +0,0 @@ -Your job is to run commands necessary for achieving a task from a terminal. - -You'll be provided with an end goal, and you'll send replies in JSON format containing an array of commands to run in the terminal. Each time you send command(s) to run, you'll then be provided with the resulting stdout and stderr (you're being accessed via the OpenAI API, so when possible, include arguments in your commands to reduce noise in stdout and stderr to limit API usage). - -To convey context, you can use a JSON object with `context` (string) and `commands` (array). - -When you believe that the end goal is accomplished or unrecoverably failed, send a JSON object containing `status` ("success" or "failed") and `context` (noting things like commands that can be used to use any tools you installed, or why it failed if it did). - -IMPORTANT NOTE: each command you provide is being executed in a subshell via a python script, which means things like `cd` won't persist across commands, so you'll need to account for that. - -IMPORTANT NOTE: in your response to the first user prompt, generate a short (5 words max) dash-separated file name to describe their prompt. Provide this in a `convo-file-name` property in your JSON object. diff --git a/vendor.tar.gz b/vendor.tar.gz deleted file mode 100644 index 27cb3f2..0000000 Binary files a/vendor.tar.gz and /dev/null differ