├── .github ├── scripts │ └── update_version_file.sh └── workflows │ └── rebyte-release.yml ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── build.sh ├── deno.json ├── deno.lock ├── dev.sh ├── imgs └── create-key.png ├── import_map.json ├── install.sh ├── instructions.md ├── mod.ts ├── scripts └── update-lock.sh └── src ├── chalk.ts ├── client.ts ├── config.ts ├── index.ts ├── pagination.ts ├── rebyte.ts ├── router.ts ├── types.ts ├── utils.ts └── version.ts /.github/scripts/update_version_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | VERSION="$1" 4 | 5 | echo "export const version = \"$VERSION\"" > ./src/version.ts -------------------------------------------------------------------------------- /.github/workflows/rebyte-release.yml: -------------------------------------------------------------------------------- 1 | name: REBYTE CLI RELEASE 2 | 3 | on: 4 | push: 5 | tags: 6 | - v** 7 | 8 | jobs: 9 | build: 10 | name: Upload Release Asset 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | packages: write 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v3 18 | - uses: denoland/setup-deno@v1 19 | with: 20 | deno-version: v1.39.1 # Run with latest stable Deno. 21 | - name: Update Versio File 22 | run: ./.github/scripts/update_version_file.sh ${{ github.ref_name }} 23 | - name: Build project 24 | run: ./build.sh 25 | - name: Release 26 | uses: softprops/action-gh-release@v1 27 | if: startsWith(github.ref, 'refs/tags/') 28 | with: 29 | files: | 30 | rebyte-linux-x64 31 | rebyte-macos-x64 32 | rebyte-macos-arm64 33 | rebyte-windows-x64.exe -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | .idea 11 | rebyte-cli 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # Snowpack dependency directory (https://snowpack.dev/) 49 | web_modules/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Optional stylelint cache 61 | .stylelintcache 62 | 63 | # Microbundle cache 64 | .rpt2_cache/ 65 | .rts2_cache_cjs/ 66 | .rts2_cache_es/ 67 | .rts2_cache_umd/ 68 | 69 | # Optional REPL history 70 | .node_repl_history 71 | 72 | # Output of 'npm pack' 73 | *.tgz 74 | 75 | # Yarn Integrity file 76 | .yarn-integrity 77 | 78 | # dotenv environment variable files 79 | .env 80 | .env.development.local 81 | .env.test.local 82 | .env.production.local 83 | .env.local 84 | 85 | # parcel-bundler cache (https://parceljs.org/) 86 | .cache 87 | .parcel-cache 88 | 89 | # Next.js build output 90 | .next 91 | out 92 | 93 | # Nuxt.js build / generate output 94 | .nuxt 95 | dist 96 | 97 | # Gatsby files 98 | .cache/ 99 | # Comment in the public line in if your project uses Gatsby and not Next.js 100 | # https://nextjs.org/blog/next-9-1#public-directory-support 101 | # public 102 | 103 | # vuepress build output 104 | .vuepress/dist 105 | 106 | # vuepress v2.x temp and cache directory 107 | .temp 108 | .cache 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | rebyte-macos* 136 | rebyte-linux* 137 | rebyte-windows* 138 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true, 4 | "deno.unstable": true 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rebyte-cli 2 | 3 | # Introduction 4 | Rebyte-cli is a command line tool for **rebyte.ai**. It can help you to manage your rebyte project via command line. 5 | * Manage your agent 6 | * Manage your agent extension 7 | * Manage your knowledge base 8 | 9 | # Install 10 | 11 | You may install rebyte cli using the following scripts. 12 | 13 | > **⚠️ Note:** We use a short link to download install script. If you encounter error when using short link 14 | > you can try our full link 15 | replace the short link `https://shorturl.at/cGH23` to `https://raw.githubusercontent.com/rebyteai/rebyte-cli/main/install.sh` 16 | 17 | ### On Windows 18 | Using PowerShell: 19 | ```iwr 20 | iwr https://shorturl.at/cGH23 -useb | iex 21 | ``` 22 | 23 | ### On POSIX systems 24 | 25 | ```sh 26 | curl -fsSL https://shorturl.at/cGH23 | sudo sh - 27 | ``` 28 | 29 | If you don't have curl installed, you would like to use wget: 30 | 31 | ```sh 32 | wget -qO- https://shorturl.at/cGH23 | sudo sh - 33 | ``` 34 | 35 | 42 | 43 | > **⚠️ Note:** Scripts will download rebyte binray to `/usr/local/bin` directory. 44 | > Make sure the `/usr/local/bin` directory exists and in your `PATH` environment 45 | > variable 46 | 47 | # Using rebyte CLI to create action extension 48 | 49 | ## Login through rebyte api 50 | 51 | #### 1. generate rebyte api KEY from https://rebyte.ai 52 | 53 | ![img](./imgs/create-key.png) 54 | 55 | #### 2. login using your api 56 | 57 | ``` 58 | rebyte login -k 59 | ``` 60 | 61 | > For cn user, you can use `rebyte login -k -u https://colingo.ai` 62 | 63 | ## Create Extension 64 | 65 | You need to go to UI to create an extension first. 66 | 67 | http://rebyte.ai/p//settings/extensions 68 | 69 | 70 | ## Deploy Extension 71 | 72 | Using `rebyte deploy` to deploy your project. Your project dir must have a 73 | `rebyte.json` file 74 | 75 | ``` 76 | rebyte deploy 77 | ``` 78 | 79 | ## Show help message 80 | 81 | ``` 82 | rebyte --help 83 | ``` 84 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | deno compile -A --unstable --output rebyte-linux-x64 --target x86_64-unknown-linux-gnu mod.ts 4 | deno compile -A --unstable --output rebyte-macos-arm64 --target aarch64-apple-darwin mod.ts 5 | deno compile -A --unstable --output rebyte-macos-x64 --target x86_64-apple-darwin mod.ts 6 | deno compile -A --unstable --output rebyte-windows-x64 --target x86_64-pc-windows-msvc mod.ts 7 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "importMap": "import_map.json", 3 | "tasks": { 4 | "esm:add": "deno run -A https://esm.sh/v132 add", 5 | "esm:update": "deno run -A https://esm.sh/v132 update", 6 | "esm:remove": "deno run -A https://esm.sh/v132 remove" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "specifiers": { 4 | "npm:form-data@*": "4.0.1" 5 | }, 6 | "npm": { 7 | "asynckit@0.4.0": { 8 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 9 | }, 10 | "combined-stream@1.0.8": { 11 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 12 | "dependencies": [ 13 | "delayed-stream" 14 | ] 15 | }, 16 | "delayed-stream@1.0.0": { 17 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" 18 | }, 19 | "form-data@4.0.1": { 20 | "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", 21 | "dependencies": [ 22 | "asynckit", 23 | "combined-stream", 24 | "mime-types" 25 | ] 26 | }, 27 | "mime-db@1.52.0": { 28 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 29 | }, 30 | "mime-types@2.1.35": { 31 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 32 | "dependencies": [ 33 | "mime-db" 34 | ] 35 | } 36 | }, 37 | "redirects": { 38 | "https://deno.land/x/momentjs/mod.ts": "https://deno.land/x/momentjs@2.29.1-deno/mod.ts" 39 | }, 40 | "remote": { 41 | "https://cdn.skypack.dev/-/mri@v1.2.0-GXZUE9rTNy9jmiiaKeNR/dist=es2019,mode=imports/optimized/mri.js": "e5f545a671f1b3c89eb383081fdb3d6b4abf0aa6239d87eb14bda751cd121d82", 42 | "https://cdn.skypack.dev/mri": "a281ab99861887195d3071e7b3a61588af422ffaff9f6cd9239358c62fa3591b", 43 | "https://deno.land/std@0.110.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", 44 | "https://deno.land/std@0.110.0/_util/os.ts": "dfb186cc4e968c770ab6cc3288bd65f4871be03b93beecae57d657232ecffcac", 45 | "https://deno.land/std@0.110.0/async/deadline.ts": "1d6ac7aeaee22f75eb86e4e105d6161118aad7b41ae2dd14f4cfd3bf97472b93", 46 | "https://deno.land/std@0.110.0/async/debounce.ts": "b2f693e4baa16b62793fd618de6c003b63228db50ecfe3bd51fc5f6dc0bc264b", 47 | "https://deno.land/std@0.110.0/async/deferred.ts": "ab60d46ba561abb3b13c0c8085d05797a384b9f182935f051dc67136817acdee", 48 | "https://deno.land/std@0.110.0/async/delay.ts": "db68b7c22518ea9805be110cdc914017d741894d2bececf4d78607fd2f0548e7", 49 | "https://deno.land/std@0.110.0/async/mod.ts": "78425176fabea7bd1046ce3819fd69ce40da85c83e0f174d17e8e224a91f7d10", 50 | "https://deno.land/std@0.110.0/async/mux_async_iterator.ts": "62abff3af9ff619e8f2adc96fc70d4ca020fa48a50c23c13f12d02ed2b760dbe", 51 | "https://deno.land/std@0.110.0/async/pool.ts": "353ce4f91865da203a097aa6f33de8966340c91b6f4a055611c8c5d534afd12f", 52 | "https://deno.land/std@0.110.0/async/tee.ts": "63811ea47268825db2b15e973dc5c37bab37b749ffa00d2b7bbb6c6f568412cb", 53 | "https://deno.land/std@0.110.0/bytes/mod.ts": "440684e07e8f57a19a43b34d57eb63af0b36fc92b6657b6dcdbf9d5612d62e29", 54 | "https://deno.land/std@0.110.0/encoding/base64.ts": "eecae390f1f1d1cae6f6c6d732ede5276bf4b9cd29b1d281678c054dc5cc009e", 55 | "https://deno.land/std@0.110.0/encoding/hex.ts": "5bc7df19af498c315cdaba69e2fce1b2aef5fc57344e8c21c08991aa8505a260", 56 | "https://deno.land/std@0.110.0/fmt/colors.ts": "8368ddf2d48dfe413ffd04cdbb7ae6a1009cf0dccc9c7ff1d76259d9c61a0621", 57 | "https://deno.land/std@0.110.0/fs/eol.ts": "afaebaaac36f48c423b920c836551997715672b80a0fee9aa7667c181a94f2df", 58 | "https://deno.land/std@0.110.0/io/buffer.ts": "3ead6bb11276ebcf093c403f74f67fd2205a515dbbb9061862c468ca56f37cd8", 59 | "https://deno.land/std@0.110.0/io/util.ts": "85c33d61b20fd706acc094fe80d4c8ae618b04abcf3a96ca2b47071842c1c8ac", 60 | "https://deno.land/std@0.110.0/node/_errors.ts": "74d1e7c7aad0f4a04df20be1f25f8a0a1d39483a75daabefa2cb285b0090e6e5", 61 | "https://deno.land/std@0.110.0/node/_stream/async_iterator.ts": "f5e8e4cf7e823364740a9db1cf492f571a4c7c7cbc4c9f65cb505db439eecca1", 62 | "https://deno.land/std@0.110.0/node/_stream/buffer_list.ts": "93526777ba6436a5e73590b7878506ad4dbe99e6cb041d15cf748b2df28596d1", 63 | "https://deno.land/std@0.110.0/node/_stream/destroy.ts": "c6248bab9e1c85693716867a48cb881c6df6d6111c698d7b9301eda571e54347", 64 | "https://deno.land/std@0.110.0/node/_stream/duplex.ts": "c0a6ce0a286ccd2c37cca217c356316007b799b803865b20a3c75559a6e933ad", 65 | "https://deno.land/std@0.110.0/node/_stream/duplex_internal.ts": "61c6dd6712472ca70019ad207455df2ab5524248ba3c5325ccc78473fe0b2795", 66 | "https://deno.land/std@0.110.0/node/_stream/end_of_stream.ts": "5bd4d24e1b418062be8fdf569b6407b89f7cedec6644b4865bf46dcf4ee72976", 67 | "https://deno.land/std@0.110.0/node/_stream/from.ts": "d1c041b3788ec2cb28ea4949036dc7b1af11e900dd6181b1150d7c0ed10e7f57", 68 | "https://deno.land/std@0.110.0/node/_stream/passthrough.ts": "361145fcdd270f00b162565c7e12078ef1f48b1c96ce7954998a985b926322ba", 69 | "https://deno.land/std@0.110.0/node/_stream/pipeline.ts": "76624903a47d2bca6f30d4af246aca65396b63a1642894f44e6d227c184dae86", 70 | "https://deno.land/std@0.110.0/node/_stream/promises.ts": "71d77087c158c2c3b84ddc0a4a4d70f810f6767b55195374303fa271f224cee9", 71 | "https://deno.land/std@0.110.0/node/_stream/readable.ts": "770ff73f2c767d0098769831a3ee6e77562a32d82ff5420950323d664d0bcc46", 72 | "https://deno.land/std@0.110.0/node/_stream/readable_internal.ts": "126d3f2067900459465db73bf16c5d9ddb48c37d0fba03f8f69d7f274d0dbc89", 73 | "https://deno.land/std@0.110.0/node/_stream/stream.ts": "a630a4163777a68190de1f3903901e84260d7cfd9fe861c9398867745c333bf7", 74 | "https://deno.land/std@0.110.0/node/_stream/symbols.ts": "980ba25e8e05593fd775c51e05e7ccf2af7fe466616f110c107dd96bce302754", 75 | "https://deno.land/std@0.110.0/node/_stream/transform.ts": "7b7b7fe1506e461412f5f53325da57d8de11dde2990c7e2f8d0d8cb7690262e3", 76 | "https://deno.land/std@0.110.0/node/_stream/writable.ts": "25ec104069af7abd6bf98ea59c40b14c0427826d979036f42f4358189d1aaeec", 77 | "https://deno.land/std@0.110.0/node/_stream/writable_internal.ts": "ef00bd654f949c17eb4b1749d1e37e92a93cbc7fc5807b63875d3b94a667c023", 78 | "https://deno.land/std@0.110.0/node/_util/_util_callbackify.ts": "947aa66d148c10e484c5c5e65ca4041cdd65085d7045fb26d388269a63c4d079", 79 | "https://deno.land/std@0.110.0/node/_util/_util_promisify.ts": "2ad6efe685f73443d5ed6ae009999789a8de4a0f01e6d2afdf242b4515477ee2", 80 | "https://deno.land/std@0.110.0/node/_util/_util_types.ts": "ae3d21e07c975f06590ab80bbde8173670d70ff40546267c0c1df869fc2ff00c", 81 | "https://deno.land/std@0.110.0/node/_utils.ts": "c32d3491e380488728d65ad471698ed0aadff7fe35bde0a26ba4dd8f434ed0e7", 82 | "https://deno.land/std@0.110.0/node/buffer.ts": "29e7a8849479c9d325a1be899fd79d1289a858afe211ab5a0c78e57f3493dfea", 83 | "https://deno.land/std@0.110.0/node/events.ts": "f92ba300cb0a6efa4ff4d8a267a507ee725858d6a250a2eeb829ec99b21f90b1", 84 | "https://deno.land/std@0.110.0/node/os.ts": "350dc64e5bb8af0f2e91690e509220fb238992af1fdcbb9ee087907c80e2a7c5", 85 | "https://deno.land/std@0.110.0/node/process.ts": "f22c10d8039ecef4d814310081e4685aeaa9f0b4591c75c3c9d4dd189a5f1354", 86 | "https://deno.land/std@0.110.0/node/stream.ts": "a4ed80f73bd94415cc4b27ea6c08000294361165fd97dfdbce6bcb52245eb744", 87 | "https://deno.land/std@0.110.0/node/string_decoder.ts": "da8586cf9288fa8d83574c409b4eadb0d634b0294fad2b4675df78dfac6ff546", 88 | "https://deno.land/std@0.110.0/node/util.ts": "23878bd3ee67a52e67cfe5acb78c7ccce9c54735c6d280b069577605e8679935", 89 | "https://deno.land/std@0.110.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853", 90 | "https://deno.land/std@0.110.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4", 91 | "https://deno.land/std@0.110.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b", 92 | "https://deno.land/std@0.110.0/path/common.ts": "f41a38a0719a1e85aa11c6ba3bea5e37c15dd009d705bd8873f94c833568cbc4", 93 | "https://deno.land/std@0.110.0/path/glob.ts": "46708a3249cb5dc4a116cae3055114d6339bd5f0c1f412db6a4e0cb44c828a7d", 94 | "https://deno.land/std@0.110.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12", 95 | "https://deno.land/std@0.110.0/path/posix.ts": "34349174b9cd121625a2810837a82dd8b986bbaaad5ade690d1de75bbb4555b2", 96 | "https://deno.land/std@0.110.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c", 97 | "https://deno.land/std@0.110.0/path/win32.ts": "2edb2f71f10578ee1168de01a8cbd3c65483e45a46bc2fa3156a0c6bfbd2720d", 98 | "https://deno.land/std@0.110.0/testing/_diff.ts": "ccd6c3af6e44c74bf1591acb1361995f5f50df64323a6e7fb3f16c8ea792c940", 99 | "https://deno.land/std@0.110.0/testing/asserts.ts": "6b0d6ba564bdff807bd0f0e93e02c48aa3177acf19416bf84a7f420191ef74cd", 100 | "https://deno.land/std@0.114.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", 101 | "https://deno.land/std@0.114.0/_util/os.ts": "dfb186cc4e968c770ab6cc3288bd65f4871be03b93beecae57d657232ecffcac", 102 | "https://deno.land/std@0.114.0/async/deadline.ts": "1d6ac7aeaee22f75eb86e4e105d6161118aad7b41ae2dd14f4cfd3bf97472b93", 103 | "https://deno.land/std@0.114.0/async/debounce.ts": "b2f693e4baa16b62793fd618de6c003b63228db50ecfe3bd51fc5f6dc0bc264b", 104 | "https://deno.land/std@0.114.0/async/deferred.ts": "ab60d46ba561abb3b13c0c8085d05797a384b9f182935f051dc67136817acdee", 105 | "https://deno.land/std@0.114.0/async/delay.ts": "f2d8ccaa8ebc26594bd8b0989edfd8a96257a714c1dee2fb54d986e5bdd840ac", 106 | "https://deno.land/std@0.114.0/async/mod.ts": "78425176fabea7bd1046ce3819fd69ce40da85c83e0f174d17e8e224a91f7d10", 107 | "https://deno.land/std@0.114.0/async/mux_async_iterator.ts": "62abff3af9ff619e8f2adc96fc70d4ca020fa48a50c23c13f12d02ed2b760dbe", 108 | "https://deno.land/std@0.114.0/async/pool.ts": "353ce4f91865da203a097aa6f33de8966340c91b6f4a055611c8c5d534afd12f", 109 | "https://deno.land/std@0.114.0/async/tee.ts": "3e9f2ef6b36e55188de16a667c702ace4ad0cf84e3720379160e062bf27348ad", 110 | "https://deno.land/std@0.114.0/bytes/bytes_list.ts": "3bff6a09c72b2e0b1e92e29bd3b135053894196cca07a2bba842901073efe5cb", 111 | "https://deno.land/std@0.114.0/bytes/equals.ts": "69f55fdbd45c71f920c1a621e6c0865dc780cd8ae34e0f5e55a9497b70c31c1b", 112 | "https://deno.land/std@0.114.0/bytes/mod.ts": "fedb80b8da2e7ad8dd251148e65f92a04c73d6c5a430b7d197dc39588c8dda6f", 113 | "https://deno.land/std@0.114.0/fmt/colors.ts": "8368ddf2d48dfe413ffd04cdbb7ae6a1009cf0dccc9c7ff1d76259d9c61a0621", 114 | "https://deno.land/std@0.114.0/io/buffer.ts": "a587093277c889ded709a933cd7d5b6285978275b2015a7cf9c8a3caad464236", 115 | "https://deno.land/std@0.114.0/node/_errors.ts": "f60f811e5967220b25edb1a726306ffae38b42ce9780e3a4ecc38073d3b434e3", 116 | "https://deno.land/std@0.114.0/node/_util/_util_callbackify.ts": "947aa66d148c10e484c5c5e65ca4041cdd65085d7045fb26d388269a63c4d079", 117 | "https://deno.land/std@0.114.0/node/_util/_util_promisify.ts": "6d8d88fd81763f1074c84f4494484f9dd86182dfe46b63fe5aadd6448b767896", 118 | "https://deno.land/std@0.114.0/node/_util/_util_types.ts": "2a2580f346e870cca7a79b34e7c640123452fd152a25801dcd0dc2504121d067", 119 | "https://deno.land/std@0.114.0/node/_utils.ts": "42e5b28e1740ba0be9b4ace2c9adb95317d9cadb099418c51ed34cd6a301cae3", 120 | "https://deno.land/std@0.114.0/node/events.ts": "f3e412b1ad8aad6ff8c86236681ad175afbd907fa211b27344b5c69822726df9", 121 | "https://deno.land/std@0.114.0/node/internal_binding/uv.ts": "68d75325ed14825fac6cac4c7b22547a445b742b121a056f3e1cc761fac86b51", 122 | "https://deno.land/std@0.114.0/node/path.ts": "86b262d6957fba13d4f3d58a92ced49de4f40169d06542326b5547ff97257f0d", 123 | "https://deno.land/std@0.114.0/node/url.ts": "ff2c3dd221f562ffa88a4e13926d27385d7a13f2856d7ebd6e632fb107ca0712", 124 | "https://deno.land/std@0.114.0/node/util.ts": "11413ac71e045004c3a3047146f9aea49d56de54d717695fa97b8c3d378107ec", 125 | "https://deno.land/std@0.114.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853", 126 | "https://deno.land/std@0.114.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4", 127 | "https://deno.land/std@0.114.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b", 128 | "https://deno.land/std@0.114.0/path/common.ts": "f41a38a0719a1e85aa11c6ba3bea5e37c15dd009d705bd8873f94c833568cbc4", 129 | "https://deno.land/std@0.114.0/path/glob.ts": "ea87985765b977cc284b92771003b2070c440e0807c90e1eb0ff3e095911a820", 130 | "https://deno.land/std@0.114.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12", 131 | "https://deno.land/std@0.114.0/path/posix.ts": "34349174b9cd121625a2810837a82dd8b986bbaaad5ade690d1de75bbb4555b2", 132 | "https://deno.land/std@0.114.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c", 133 | "https://deno.land/std@0.114.0/path/win32.ts": "11549e8c6df8307a8efcfa47ad7b2a75da743eac7d4c89c9723a944661c8bd2e", 134 | "https://deno.land/std@0.114.0/streams/conversion.ts": "fe0059ed9d3c53eda4ba44eb71a6a9acb98c5fdb5ba1b6c6ab28004724c7641b", 135 | "https://deno.land/std@0.114.0/testing/_diff.ts": "95578951cd3c9977fd3822c64e9831c739ae8d2a5faece71d3f21bfb553f6275", 136 | "https://deno.land/std@0.114.0/testing/asserts.ts": "550c71c634c608cffabf9e50520435cf03ff4bbd1db1253b0ade4debb444b131", 137 | "https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", 138 | "https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49", 139 | "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d", 140 | "https://deno.land/std@0.140.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9", 141 | "https://deno.land/std@0.140.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf", 142 | "https://deno.land/std@0.140.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37", 143 | "https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f", 144 | "https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d", 145 | "https://deno.land/std@0.140.0/hash/sha256.ts": "803846c7a5a8a5a97f31defeb37d72f519086c880837129934f5d6f72102a8e8", 146 | "https://deno.land/std@0.140.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b", 147 | "https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3", 148 | "https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09", 149 | "https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b", 150 | "https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633", 151 | "https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee", 152 | "https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d", 153 | "https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44", 154 | "https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9", 155 | "https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757", 156 | "https://deno.land/std@0.140.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21", 157 | "https://deno.land/std@0.153.0/media_types/_util.ts": "ce9b4fc4ba1c447dafab619055e20fd88236ca6bdd7834a21f98bd193c3fbfa1", 158 | "https://deno.land/std@0.153.0/media_types/mod.ts": "74885352135624774b8cd164f3a9d866aac1e0dc3ccb5412e2a2d56ed4b1fc99", 159 | "https://deno.land/std@0.153.0/media_types/vendor/mime-db.v1.52.0.ts": "724cee25fa40f1a52d3937d6b4fbbfdd7791ff55e1b7ac08d9319d5632c7f5af", 160 | "https://deno.land/std@0.201.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", 161 | "https://deno.land/std@0.201.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", 162 | "https://deno.land/std@0.201.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8", 163 | "https://deno.land/std@0.201.0/bytes/concat.ts": "d26d6f3d7922e6d663dacfcd357563b7bf4a380ce5b9c2bbe0c8586662f25ce2", 164 | "https://deno.land/std@0.201.0/bytes/copy.ts": "939d89e302a9761dcf1d9c937c7711174ed74c59eef40a1e4569a05c9de88219", 165 | "https://deno.land/std@0.201.0/encoding/base32.ts": "c329447451560ec692b9eb4d1badb6437f1d419ddbb21c1f994b0fe0b6b66cc8", 166 | "https://deno.land/std@0.201.0/fs/_util.ts": "fbf57dcdc9f7bc8128d60301eece608246971a7836a3bb1e78da75314f08b978", 167 | "https://deno.land/std@0.201.0/fs/copy.ts": "23cc1c465babe5ca4d69778821e2f8addc44593e30a5ca0b902b3784eed75bb6", 168 | "https://deno.land/std@0.201.0/fs/empty_dir.ts": "2e52cd4674d18e2e007175c80449fc3d263786a1361e858d9dfa9360a6581b47", 169 | "https://deno.land/std@0.201.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", 170 | "https://deno.land/std@0.201.0/fs/ensure_file.ts": "39ac83cc283a20ec2735e956adf5de3e8a3334e0b6820547b5772f71c49ae083", 171 | "https://deno.land/std@0.201.0/fs/ensure_link.ts": "c15e69c48556d78aae31b83e0c0ece04b7b8bc0951412f5b759aceb6fde7f0ac", 172 | "https://deno.land/std@0.201.0/fs/ensure_symlink.ts": "b389c8568f0656d145ac7ece472afe710815cccbb2ebfd19da7978379ae143fe", 173 | "https://deno.land/std@0.201.0/fs/eol.ts": "f1f2eb348a750c34500741987b21d65607f352cf7205f48f4319d417fff42842", 174 | "https://deno.land/std@0.201.0/fs/exists.ts": "cb59a853d84871d87acab0e7936a4dac11282957f8e195102c5a7acb42546bb8", 175 | "https://deno.land/std@0.201.0/fs/expand_glob.ts": "52b8b6f5b1fa585c348250da1c80ce5d820746cb4a75d874b3599646f677d3a7", 176 | "https://deno.land/std@0.201.0/fs/mod.ts": "bc3d0acd488cc7b42627044caf47d72019846d459279544e1934418955ba4898", 177 | "https://deno.land/std@0.201.0/fs/move.ts": "b4f8f46730b40c32ea3c0bc8eb0fd0e8139249a698883c7b3756424cf19785c9", 178 | "https://deno.land/std@0.201.0/fs/walk.ts": "a16146724a6aaf9efdb92023a74e9805195c3469900744ce5de4113b07b29779", 179 | "https://deno.land/std@0.201.0/io/buffer.ts": "4d6883daeb2e698579c4064170515683d69f40f3de019bfe46c5cf31e74ae793", 180 | "https://deno.land/std@0.201.0/jsonc/mod.ts": "b88dce28eb3645667caa856538ae2fe87af51410822544a0b45a4177ef3bd7dd", 181 | "https://deno.land/std@0.201.0/jsonc/parse.ts": "c1096e2b7ffb4996d7ed841dfdb29a4fccc78edcc55299beaa20d6fe5facf7b6", 182 | "https://deno.land/std@0.201.0/path/_basename.ts": "057d420c9049821f983f784fd87fa73ac471901fb628920b67972b0f44319343", 183 | "https://deno.land/std@0.201.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 184 | "https://deno.land/std@0.201.0/path/_dirname.ts": "355e297236b2218600aee7a5301b937204c62e12da9db4b0b044993d9e658395", 185 | "https://deno.land/std@0.201.0/path/_extname.ts": "eaaa5aae1acf1f03254d681bd6a8ce42a9cb5b7ff2213a9d4740e8ab31283664", 186 | "https://deno.land/std@0.201.0/path/_format.ts": "4a99270d6810f082e614309164fad75d6f1a483b68eed97c830a506cc589f8b4", 187 | "https://deno.land/std@0.201.0/path/_from_file_url.ts": "6eadfae2e6f63ad9ee46b26db4a1b16583055c0392acedfb50ed2fc694b6f581", 188 | "https://deno.land/std@0.201.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 189 | "https://deno.land/std@0.201.0/path/_is_absolute.ts": "05dac10b5e93c63198b92e3687baa2be178df5321c527dc555266c0f4f51558c", 190 | "https://deno.land/std@0.201.0/path/_join.ts": "815f5e85b042285175b1492dd5781240ce126c23bd97bad6b8211fe7129c538e", 191 | "https://deno.land/std@0.201.0/path/_normalize.ts": "a19ec8706b2707f9dd974662a5cd89fad438e62ab1857e08b314a8eb49a34d81", 192 | "https://deno.land/std@0.201.0/path/_os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", 193 | "https://deno.land/std@0.201.0/path/_parse.ts": "0f9b0ff43682dd9964eb1c4398610c4e165d8db9d3ac9d594220217adf480cfa", 194 | "https://deno.land/std@0.201.0/path/_relative.ts": "27bdeffb5311a47d85be26d37ad1969979359f7636c5cd9fcf05dcd0d5099dc5", 195 | "https://deno.land/std@0.201.0/path/_resolve.ts": "7a3616f1093735ed327e758313b79c3c04ea921808ca5f19ddf240cb68d0adf6", 196 | "https://deno.land/std@0.201.0/path/_to_file_url.ts": "a141e4a525303e1a3a0c0571fd024552b5f3553a2af7d75d1ff3a503dcbb66d8", 197 | "https://deno.land/std@0.201.0/path/_to_namespaced_path.ts": "0d5f4caa2ed98ef7a8786286df6af804b50e38859ae897b5b5b4c8c5930a75c8", 198 | "https://deno.land/std@0.201.0/path/_util.ts": "4e191b1bac6b3bf0c31aab42e5ca2e01a86ab5a0d2e08b75acf8585047a86221", 199 | "https://deno.land/std@0.201.0/path/basename.ts": "bdfa5a624c6a45564dc6758ef2077f2822978a6dbe77b0a3514f7d1f81362930", 200 | "https://deno.land/std@0.201.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", 201 | "https://deno.land/std@0.201.0/path/dirname.ts": "b6533f4ee4174a526dec50c279534df5345836dfdc15318400b08c62a62a39dd", 202 | "https://deno.land/std@0.201.0/path/extname.ts": "62c4b376300795342fe1e4746c0de518b4dc9c4b0b4617bfee62a2973a9555cf", 203 | "https://deno.land/std@0.201.0/path/format.ts": "110270b238514dd68455a4c54956215a1aff7e37e22e4427b7771cefe1920aa5", 204 | "https://deno.land/std@0.201.0/path/from_file_url.ts": "9f5cb58d58be14c775ec2e57fc70029ac8b17ed3bd7fe93e475b07280adde0ac", 205 | "https://deno.land/std@0.201.0/path/glob.ts": "593e2c3573883225c25c5a21aaa8e9382a696b8e175ea20a3b6a1471ad17aaed", 206 | "https://deno.land/std@0.201.0/path/is_absolute.ts": "0b92eb35a0a8780e9f16f16bb23655b67dace6a8e0d92d42039e518ee38103c1", 207 | "https://deno.land/std@0.201.0/path/join.ts": "31c5419f23d91655b08ec7aec403f4e4cd1a63d39e28f6e42642ea207c2734f8", 208 | "https://deno.land/std@0.201.0/path/mod.ts": "6e1efb0b13121463aedb53ea51dabf5639a3172ab58c89900bbb72b486872532", 209 | "https://deno.land/std@0.201.0/path/normalize.ts": "6ea523e0040979dd7ae2f1be5bf2083941881a252554c0f32566a18b03021955", 210 | "https://deno.land/std@0.201.0/path/parse.ts": "be8de342bb9e1924d78dc4d93c45215c152db7bf738ec32475560424b119b394", 211 | "https://deno.land/std@0.201.0/path/posix.ts": "0a1c1952d132323a88736d03e92bd236f3ed5f9f079e5823fae07c8d978ee61b", 212 | "https://deno.land/std@0.201.0/path/relative.ts": "8bedac226afd360afc45d451a6c29fabceaf32978526bcb38e0c852661f66c61", 213 | "https://deno.land/std@0.201.0/path/resolve.ts": "133161e4949fc97f9ca67988d51376b0f5eef8968a6372325ab84d39d30b80dc", 214 | "https://deno.land/std@0.201.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f", 215 | "https://deno.land/std@0.201.0/path/to_file_url.ts": "00e6322373dd51ad109956b775e4e72e5f9fa68ce2c6b04e4af2a6eed3825d31", 216 | "https://deno.land/std@0.201.0/path/to_namespaced_path.ts": "1b1db3055c343ab389901adfbda34e82b7386bcd1c744d54f9c1496ee0fd0c3d", 217 | "https://deno.land/std@0.201.0/path/win32.ts": "8b3f80ef7a462511d5e8020ff490edcaa0a0d118f1b1e9da50e2916bdd73f9dd", 218 | "https://deno.land/std@0.201.0/streams/_common.ts": "3b2c1f0287ce2ad51fff4091a7d0f48375c85b0ec341468e76d5ac13bb0014dd", 219 | "https://deno.land/std@0.201.0/streams/buffer.ts": "6cd773d22cf21bb988a98cc551b5abfc4c3b03516f93eaa3fb6f2f6e16032deb", 220 | "https://deno.land/std@0.201.0/streams/byte_slice_stream.ts": "c46d7c74836fc8c1a9acd9fe211cbe1bbaaee1b36087c834fb03af4991135c3a", 221 | "https://deno.land/std@0.201.0/streams/copy.ts": "75cbc795ff89291df22ddca5252de88b2e16d40c85d02840593386a8a1454f71", 222 | "https://deno.land/std@0.201.0/streams/delimiter_stream.ts": "a676837e8bdaa94502fe3d8cae57fbf54697801ae61cefbaf39fb7ab64169d2a", 223 | "https://deno.land/std@0.201.0/streams/early_zip_readable_streams.ts": "4005fa74162b943f79899e5d7cb96adcbc0a6b867f9144974ed12d30e0a556e1", 224 | "https://deno.land/std@0.201.0/streams/iterate_reader.ts": "bbec1d45c2df2c0c5920bad0549351446fdc8e0886d99e95959b259dbcdb6072", 225 | "https://deno.land/std@0.201.0/streams/limited_bytes_transform_stream.ts": "05dc592ffaab83257494d22dd53917e56243c26e5e3129b3f13ddbbbc4785048", 226 | "https://deno.land/std@0.201.0/streams/limited_transform_stream.ts": "d69ab790232c1b86f53621ad41ef03c235f2abb4b7a1cd51960ad6e12ee55e38", 227 | "https://deno.land/std@0.201.0/streams/merge_readable_streams.ts": "dc2db0cbf1b14d999aa2aa2a2a1ba24ce58953878f29845ed9319321d0a01fab", 228 | "https://deno.land/std@0.201.0/streams/mod.ts": "206c718cebeba0ea690be032f6095a8fd079d4168ad7eb3d6e1b6d35b8ee4f42", 229 | "https://deno.land/std@0.201.0/streams/read_all.ts": "ee319772fb0fd28302f97343cc48dfcf948f154fd0d755d8efe65814b70533be", 230 | "https://deno.land/std@0.201.0/streams/readable_stream_from_reader.ts": "9bc9e71f0ddad557daa7035daca052ca840e0a45e9d1d467d40afcf2c78933fb", 231 | "https://deno.land/std@0.201.0/streams/reader_from_iterable.ts": "c2d655262d1f6593b49b494430815c273a272b4804e4d07f11987813fbbb9ef1", 232 | "https://deno.land/std@0.201.0/streams/reader_from_stream_reader.ts": "fa4971e5615a010e49492c5d1688ca1a4d17472a41e98b498ab89a64ebd7ac73", 233 | "https://deno.land/std@0.201.0/streams/text_delimiter_stream.ts": "f0dc8ff953a8a77f0d1fa8db1fee62de817f36e20d79b00b1362847e30fbdd90", 234 | "https://deno.land/std@0.201.0/streams/text_line_stream.ts": "0f2c4b33a5fdb2476f2e060974cba1347cefe99a4af33c28a57524b1a34750fa", 235 | "https://deno.land/std@0.201.0/streams/to_transform_stream.ts": "50af06140c414090df8c3879f46bed4043a5d73caa60352c0c9682a88ec7a8c9", 236 | "https://deno.land/std@0.201.0/streams/writable_stream_from_writer.ts": "c8f6b8525089c7db5a94cffe30d2be11f77ec9a92492644461c736ffc29f68f1", 237 | "https://deno.land/std@0.201.0/streams/write_all.ts": "aec90152978581ea62d56bb53a5cbf487e6a89c902f87c5969681ffbdf32b998", 238 | "https://deno.land/std@0.201.0/streams/writer_from_stream_writer.ts": "07c7ee025151a190f37fc42cbb01ff93afc949119ebddc6e0d0df14df1bf6950", 239 | "https://deno.land/std@0.201.0/streams/zip_readable_streams.ts": "5639c8fea8c21d7dab6f34edcf3d08218b7e548a197f7fd79a3a995305a81e9f", 240 | "https://deno.land/std@0.94.0/node/tty.ts": "9fa7f7b461759774b4eeab00334ac5d25b69bf0de003c02814be01e65150da79", 241 | "https://deno.land/x/ascii_table@v0.1.0/mod.ts": "bd99729ffefd9e0792787b7aafd06c5257039b31ffe3b987fe5257d3fa0c39b5", 242 | "https://deno.land/x/chalk_deno@v4.1.1-deno/source/ansi-styles/index.js": "7cc96ab93d1c9cfc0746e9dffb40be872e42ee242906f48e68df0d2c9669f737", 243 | "https://deno.land/x/chalk_deno@v4.1.1-deno/source/has-flag/index.js": "aed21e4eba656057e7b8c6024305f5354d2ebee2adc857a1d8cd5207923de7e5", 244 | "https://deno.land/x/chalk_deno@v4.1.1-deno/source/index.js": "6339123f32f7eb4b17c5c9c926ecdf3dbc353fd4fda7811ad2d3c1d4b98a7420", 245 | "https://deno.land/x/chalk_deno@v4.1.1-deno/source/supports-color/index.js": "4d7f2d216b6ac9013d9ec7e004de21f5a7d00bf2be4075bab2d82638d0d41a86", 246 | "https://deno.land/x/chalk_deno@v4.1.1-deno/source/templates.js": "f2e12be18cb84710e341e5499528280278052909fa74a12cefc9e2cc26a597ac", 247 | "https://deno.land/x/chalk_deno@v4.1.1-deno/source/util.js": "cd08297ec411dcee91826ad01a00d3427235d4548ba605a59e64f0da83af8306", 248 | "https://deno.land/x/deno_cache@0.4.1/auth_tokens.ts": "5fee7e9155e78cedf3f6ff3efacffdb76ac1a76c86978658d9066d4fb0f7326e", 249 | "https://deno.land/x/deno_cache@0.4.1/cache.ts": "51f72f4299411193d780faac8c09d4e8cbee951f541121ef75fcc0e94e64c195", 250 | "https://deno.land/x/deno_cache@0.4.1/deno_dir.ts": "f2a9044ce8c7fe1109004cda6be96bf98b08f478ce77e7a07f866eff1bdd933f", 251 | "https://deno.land/x/deno_cache@0.4.1/deps.ts": "8974097d6c17e65d9a82d39377ae8af7d94d74c25c0cbb5855d2920e063f2343", 252 | "https://deno.land/x/deno_cache@0.4.1/dirs.ts": "d2fa473ef490a74f2dcb5abb4b9ab92a48d2b5b6320875df2dee64851fa64aa9", 253 | "https://deno.land/x/deno_cache@0.4.1/disk_cache.ts": "1f3f5232cba4c56412d93bdb324c624e95d5dd179d0578d2121e3ccdf55539f9", 254 | "https://deno.land/x/deno_cache@0.4.1/file_fetcher.ts": "07a6c5f8fd94bf50a116278cc6012b4921c70d2251d98ce1c9f3c352135c39f7", 255 | "https://deno.land/x/deno_cache@0.4.1/http_cache.ts": "f632e0d6ec4a5d61ae3987737a72caf5fcdb93670d21032ddb78df41131360cd", 256 | "https://deno.land/x/deno_cache@0.4.1/mod.ts": "ef1cda9235a93b89cb175fe648372fc0f785add2a43aa29126567a05e3e36195", 257 | "https://deno.land/x/deno_cache@0.4.1/util.ts": "8cb686526f4be5205b92c819ca2ce82220aa0a8dd3613ef0913f6dc269dbbcfe", 258 | "https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6", 259 | "https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4", 260 | "https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d", 261 | "https://deno.land/x/esbuild@v0.19.4/mod.js": "6277018cfbcad3912fd346409e0b2a9807cf10c9555a15e4aac299b3194fa4fb", 262 | "https://deno.land/x/esbuild_deno_loader@0.8.2/deps.ts": "c1aa4747e43d3ae09da96e54aac798ed9bb967634cff72f21b7fab6e5435c293", 263 | "https://deno.land/x/esbuild_deno_loader@0.8.2/mod.ts": "28524460bef46d487221b01ade6ed913d2e127de7eeee025ab75b34b491283da", 264 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/deno.ts": "b0af3e430c068f18c6fa48c2083a1b4354b6c303e16fb37855e02fcafb95f36d", 265 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/loader_native.ts": "3ffab59d0ed26c9329b2b84e0a775be5a910b7fed403a46edf4d2c3c8feb8b5a", 266 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/loader_portable.ts": "d999f452ef3d8ec2dd3c8443f542adf57efc8a2cd59b29cc41f5b3d7dff512e5", 267 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/plugin_deno_loader.ts": "166356133ee63d80e5559a10c18e10b625da96e39a4518b8c7adfef718bb4e32", 268 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/plugin_deno_resolver.ts": "0449ed23ae93db1ec74d015a46934aefd7ba7a8f719f7a4980b616cb3f5bbee4", 269 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/shared.ts": "33052684aeb542ebd24da372816bbbf885cd090a7ab0fde7770801f7f5b49572", 270 | "https://deno.land/x/importmap@0.2.1/_util.ts": "ada9a9618b537e6c0316c048a898352396c882b9f2de38aba18fd3f2950ede89", 271 | "https://deno.land/x/importmap@0.2.1/mod.ts": "ae3d1cd7eabd18c01a4960d57db471126b020f23b37ef14e1359bbb949227ade", 272 | "https://deno.land/x/momentjs@2.29.1-deno/mod.ts": "f0c8542988b812d2aeaabe4fe3d86e7638ba6dd469ac9dd252eb2d9a765b8b49", 273 | "https://deno.land/x/momentjs@2.29.1-deno/node_modules/moment/moment.js": "7ba0da6b25146fe95a948b47ec8a7707b4bcf6a87390d4b655a0663e107f7845", 274 | "https://deno.land/x/zod@v3.21.4/ZodError.ts": "4de18ff525e75a0315f2c12066b77b5c2ae18c7c15ef7df7e165d63536fdf2ea", 275 | "https://deno.land/x/zod@v3.21.4/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", 276 | "https://deno.land/x/zod@v3.21.4/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", 277 | "https://deno.land/x/zod@v3.21.4/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", 278 | "https://deno.land/x/zod@v3.21.4/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", 279 | "https://deno.land/x/zod@v3.21.4/helpers/parseUtil.ts": "51a76c126ee212be86013d53a9d07f87e9ae04bb1496f2558e61b62cb74a6aa8", 280 | "https://deno.land/x/zod@v3.21.4/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", 281 | "https://deno.land/x/zod@v3.21.4/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", 282 | "https://deno.land/x/zod@v3.21.4/helpers/util.ts": "8baf19b19b2fca8424380367b90364b32503b6b71780269a6e3e67700bb02774", 283 | "https://deno.land/x/zod@v3.21.4/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", 284 | "https://deno.land/x/zod@v3.21.4/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", 285 | "https://deno.land/x/zod@v3.21.4/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", 286 | "https://deno.land/x/zod@v3.21.4/types.ts": "b5d061babea250de14fc63764df5b3afa24f2b088a1d797fc060ba49a0ddff28", 287 | "https://esm.sh/superjson@2.1.0": "b356d3581eecb859ce94261caab59e34322ac1a7a3bc716ac884cf2f035d2054", 288 | "https://esm.sh/v119/@trpc/client@10.28.2": "d98a9eb8a2bd2c1af3872d2c5ce426c1fa3b7698f9940c232abfde70477d06fb", 289 | "https://esm.sh/v119/@trpc/client@10.28.2/denonext/client.mjs": "1665d583e61590a74dd0993d67369d99e11f894a9dcd2779b557c49031eeebe6", 290 | "https://esm.sh/v119/@trpc/server@10.28.2": "ed69b70af939cf7539e699afbd0938a0bcc49af5b824a705334e330e0b48e2a4", 291 | "https://esm.sh/v119/@trpc/server@10.28.2/denonext/observable.js": "ec52e2b74331e78224e754257b41006c95d1ebcbf673f958afe0831608e9c831", 292 | "https://esm.sh/v119/@trpc/server@10.28.2/denonext/server.mjs": "c0f6c8964e16a8fff8615dfc8ef4e207fe38465a053ec0bf4dbdf947830fe74f", 293 | "https://esm.sh/v119/@trpc/server@10.28.2/denonext/shared.js": "f1498e7a8ea62e152a08b7c901aff5bf16bd3fb0f9444bd15855ed0c062bedde", 294 | "https://esm.sh/v135/copy-anything@3.0.5/denonext/copy-anything.mjs": "9d89b9383fe6a846f62ff4e0d2d12f8ae24eee93462e7591f4b72ac9e5643c2c", 295 | "https://esm.sh/v135/is-what@4.1.16/denonext/is-what.mjs": "ca4fb1138ffedd5a5a6fbd65c48f5dc1d1d0f7abbbe6890e5c74ed4351796399", 296 | "https://esm.sh/v135/superjson@2.1.0/denonext/superjson.mjs": "4a6e37ab72d5165ff6dfde187edd851ec3731b1a8157fab3fab6600b690eb2af", 297 | "https://unpkg.com/cac@6.7.14/deno/CAC.ts": "a339654af11f347392119be13e4dd5c240daab4a281c24f2f667de0a9f272e77", 298 | "https://unpkg.com/cac@6.7.14/deno/Command.ts": "7252e73944c820add18826529c56ce764f7e8fb6fcfebd771f680ca1f43ddcc4", 299 | "https://unpkg.com/cac@6.7.14/deno/Option.ts": "e4ae2c9dfa3e7cb89bfd9ac095194dc97e9cb0a6f6368df2f7b0ab64a542fb35", 300 | "https://unpkg.com/cac@6.7.14/deno/deno.ts": "e4b3295c6dcb9b5ad7e72544b0f15968027a396465c12b5d7e863f6f124db359", 301 | "https://unpkg.com/cac@6.7.14/deno/index.ts": "c716f480bbb2fc178bffb25caa027785c10ee161450ede8bf2a1c8ec597576d6", 302 | "https://unpkg.com/cac@6.7.14/deno/utils.ts": "e6426b2706edd6a07c287499b6ca68a2895cc48dc47a2eb602676c2a6cd05ecb", 303 | "https://unpkg.com/cac@6.7.14/mod.ts": "5e642f7e9d9753f5057c549cda3a37a1c1f5f47dcd1bd2e4ee0ab919bb31db99" 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export REBYTE_CLI_DEV=1 4 | deno run --lock=deno.lock -A src/index.ts $@ -------------------------------------------------------------------------------- /imgs/create-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReByteAI/rebyte-cli/23e582ba1f8381dbf5c7857dbb5268f82b22c911/imgs/create-key.png -------------------------------------------------------------------------------- /import_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@trpc/server": "https://esm.sh/v119/@trpc/server@10.28.2", 4 | "@trpc/server/": "https://esm.sh/v119/@trpc/server@10.28.2/", 5 | "@trpc/client": "https://esm.sh/v119/@trpc/client@10.28.2", 6 | "zod": "https://deno.land/x/zod@v3.21.4/mod.ts", 7 | "axios": "https://esm.sh/axios", 8 | "superjson": "https://esm.sh/superjson@2.1.0", 9 | "cac": "https://unpkg.com/cac@6.7.14/mod.ts", 10 | "asciitable": "https://deno.land/x/ascii_table@v0.1.0/mod.ts", 11 | "path": "https://deno.land/std@0.201.0/path/mod.ts", 12 | "esbuild": "https://deno.land/x/esbuild@v0.19.4/mod.js", 13 | "esbuild-deno-loader": "https://deno.land/x/esbuild_deno_loader@0.8.2/mod.ts", 14 | "chalk": "https://deno.land/x/chalk_deno@v4.1.1-deno/source/index.js", 15 | "mimetypes": "https://deno.land/std@0.153.0/media_types/mod.ts", 16 | "assert": "https://deno.land/std@0.201.0/assert/assert.ts" 17 | }, 18 | "scopes": { 19 | "https://ga.jspm.io/": { 20 | "ansi-regex": "https://ga.jspm.io/npm:ansi-regex@5.0.1/index.js", 21 | "buffer": "node:buffer", 22 | "clone": "https://ga.jspm.io/npm:clone@1.0.4/clone.js", 23 | "defaults": "https://ga.jspm.io/npm:defaults@1.0.4/index.js", 24 | "wcwidth": "https://ga.jspm.io/npm:wcwidth@1.0.1/index.js" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # From https://github.com/Homebrew/install/blob/master/install.sh 4 | abort() { 5 | printf "%s\n" "$@" 6 | exit 1 7 | } 8 | 9 | # string formatters 10 | if [ -t 1 ]; then 11 | tty_escape() { printf "\033[%sm" "$1"; } 12 | else 13 | tty_escape() { :; } 14 | fi 15 | tty_mkbold() { tty_escape "1;$1"; } 16 | tty_blue="$(tty_mkbold 34)" 17 | tty_bold="$(tty_mkbold 39)" 18 | tty_reset="$(tty_escape 0)" 19 | 20 | ohai() { 21 | printf "${tty_blue}==>${tty_bold} %s${tty_reset}\n" "$1" 22 | } 23 | 24 | # End from https://github.com/Homebrew/install/blob/master/install.sh 25 | 26 | download() { 27 | if command -v curl > /dev/null 2>&1; then 28 | curl -fsSL "$1" --progress-bar 29 | else 30 | wget -qO- "$1" 31 | fi 32 | } 33 | 34 | validate_url() { 35 | local url 36 | url="$1" 37 | 38 | if command -v curl > /dev/null 2>&1; then 39 | curl --output /dev/null --silent --show-error --location --head --fail "$url" 40 | else 41 | wget --spider --quiet "$url" 42 | fi 43 | } 44 | 45 | is_glibc_compatible() { 46 | getconf GNU_LIBC_VERSION >/dev/null 2>&1 || ldd --version >/dev/null 2>&1 || return 1 47 | } 48 | 49 | detect_platform() { 50 | local platform 51 | platform="$(uname -s | tr '[:upper:]' '[:lower:]')" 52 | 53 | case "${platform}" in 54 | linux) 55 | if is_glibc_compatible; then 56 | platform="linux" 57 | else 58 | platform="linuxstatic" 59 | fi 60 | ;; 61 | darwin) platform="macos" ;; 62 | windows) platform="win" ;; 63 | esac 64 | 65 | printf '%s' "${platform}" 66 | } 67 | 68 | detect_arch() { 69 | local arch 70 | arch="$(uname -m | tr '[:upper:]' '[:lower:]')" 71 | 72 | case "${arch}" in 73 | x86_64 | amd64) arch="x64" ;; 74 | armv*) arch="arm" ;; 75 | arm64 | aarch64) arch="arm64" ;; 76 | esac 77 | 78 | # `uname -m` in some cases mis-reports 32-bit OS as 64-bit, so double check 79 | if [ "${arch}" = "x64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then 80 | arch=i686 81 | elif [ "${arch}" = "arm64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then 82 | arch=arm 83 | fi 84 | 85 | case "$arch" in 86 | x64*) ;; 87 | arm64*) ;; 88 | *) return 1 89 | esac 90 | printf '%s' "${arch}" 91 | } 92 | 93 | download_and_install() { 94 | local platform arch version archive_url tmp_dir version_url 95 | platform="$(detect_platform)" 96 | arch="$(detect_arch)" || abort "Sorry! rebyte currently only provides pre-built binaries for x86_64/arm64 architectures." 97 | 98 | version="$(curl --silent "https://api.github.com/repos/ReByteAI/rebyte-cli/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')" 99 | ohai "The latest version is $version" 100 | 101 | archive_url="https://github.com/ReByteAI/rebyte-cli/releases/download/${version}/rebyte-${platform}-${arch}" 102 | if [ "${platform}" = "win" ]; then 103 | archive_url="${archive_url}.exe" 104 | fi 105 | 106 | validate_url "$archive_url" || abort "rebyte version '${version}' could not be found" 107 | 108 | # install to REBYTE_HOME, defaulting to ~/.rebyte 109 | tmp_dir="$(mktemp -d)" || abort "Tmpdir Error!" 110 | trap 'rm -rf "$tmp_dir"' EXIT INT TERM HUP 111 | 112 | ohai "Downloading rebyte binaries ${version} to /usr/local/bin/" 113 | # download the binary to the specified directory 114 | download "$archive_url" > "$tmp_dir/rebyte" || return 1 115 | chmod +x "$tmp_dir/rebyte" 116 | cp "$tmp_dir/rebyte" "/usr/local/bin/rebyte" || return 1 117 | ohai "Rebyte binary was downloaded to /usr/local/bin/rebyte" 118 | # SHELL="$SHELL" "$tmp_dir/rebyte" setup --force || return 1 119 | } 120 | 121 | download_and_install || abort "Install Error!" 122 | -------------------------------------------------------------------------------- /instructions.md: -------------------------------------------------------------------------------- 1 | # Create your own action extension 2 | 3 | 4 | ## Install deno 5 | 6 | ```sh 7 | curl -fsSL https://deno.land/x/install/install.sh | sh 8 | ``` 9 | 10 | ## install rebyte cli 11 | 12 | ```sh 13 | curl -fsSL https://raw.githubusercontent.com/rebyteai/rebyte-cli/main/install.sh | sudo sh - 14 | ``` 15 | 16 | 17 | ## Login to rebyte using your api key 18 | 19 | **API** access is only available for **Pro** users and **Team User**. 20 | 21 | ```sh 22 | rebyte login -k 23 | ``` 24 | 25 | ## Start from template 26 | 27 | ```sh 28 | mkdir -p my-extension 29 | cd my-extension 30 | git clone https://github.com/ReByteAI/action-extension-template/ 31 | ``` 32 | 33 | ## Define your action 34 | You need to specify a json file to define your extension. The file name must be named `rebyte.json`. 35 | 36 | This is an example of `rebyte.json` for [call_agent](https://github.com/ReByteAI/ext_call_agent/tree/main) 37 | 38 | ```json 39 | { 40 | "name": "call_agent", 41 | "description": "Action that calls another ReByte agent", 42 | "version": "0.0.3", 43 | "main": "./src/main.ts", 44 | "inputArgs": [ 45 | { 46 | "name": "callableId", 47 | "type": "string", 48 | "description": "Id of target agent to call", 49 | "required": true 50 | }, 51 | { 52 | "name": "projectId", 53 | "type": "string", 54 | "description": "project id of the agent", 55 | "required": true 56 | }, 57 | { 58 | "name": "apiKey", 59 | "type": "credential", 60 | "description": "API key to use for targeting project", 61 | "required": true 62 | }, 63 | { 64 | "name": "version", 65 | "type": "string", 66 | "description": "version of the agent, latest if not specified", 67 | "required": false 68 | }, 69 | { 70 | "name": "inputArgs", 71 | "type": "array", 72 | "description": "input arguments to pass to the agent", 73 | "required": false 74 | } 75 | ] 76 | } 77 | ``` 78 | 79 | ## Create an action extension on project settings page 80 | 81 | `https://rebyte.ai/p//settings/extensions` 82 | 83 | ```sh 84 | rebyte create 85 | ``` 86 | 87 | **Extension created will only be visible to your project.** 88 | 89 | ## Test your action 90 | 91 | ## Deploy your action 92 | 93 | ```sh 94 | rebyte deploy 95 | ``` -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/index.ts"; 2 | 3 | export * from "./src/config.ts"; 4 | export * from "./src/rebyte.ts"; 5 | export * from "./src/client.ts"; 6 | export * from "./src/router.ts"; 7 | 8 | -------------------------------------------------------------------------------- /scripts/update-lock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | deno cache --unstable --lock=deno.lock --lock-write ./mod.ts 4 | -------------------------------------------------------------------------------- /src/chalk.ts: -------------------------------------------------------------------------------- 1 | // @deno-types="https://deno.land/x/chalk_deno@v4.1.1-deno/index.d.ts" 2 | import chalk from "chalk"; 3 | export { 4 | chalk 5 | } -------------------------------------------------------------------------------- /src/client.ts: -------------------------------------------------------------------------------- 1 | import { readableStreamFromReader } from "https://deno.land/std@0.201.0/streams/mod.ts"; 2 | import FormDataV2 from "npm:form-data"; 3 | import { typeByExtension } from "mimetypes"; 4 | import { RebyteJson } from "./rebyte.ts"; 5 | import { RebyteServer } from "./config.ts"; 6 | import { createTRPCProxyClient, httpBatchLink } from "@trpc/client"; 7 | import superjson from "superjson"; 8 | import { AppRouter } from "./router.ts"; 9 | import * as path from "path"; 10 | import { ListQuery, ListResult, listQueryString } from "./pagination.ts"; 11 | import { ExternalFileType, KnowledgeType, KnowledgeVisibility, MessageType, RunType, ThreadType } from "./types.ts"; 12 | 13 | export class RebyteAPI { 14 | key: string; 15 | server: string; 16 | sdkBase: string; 17 | trpc: any; 18 | pId: string; 19 | 20 | constructor(server: RebyteServer) { 21 | this.key = server.api_key; 22 | this.server = server.url; 23 | this.sdkBase = server.url + "/api/sdk"; 24 | this.pId = server.pId; 25 | 26 | const client = createTRPCProxyClient({ 27 | links: [ 28 | httpBatchLink({ 29 | url: `${server.url}/api/trpc`, 30 | // You can pass any HTTP headers you wish here 31 | headers() { 32 | return { 33 | Authorization: `Bearer ${server.api_key}`, 34 | }; 35 | }, 36 | }), 37 | ], 38 | //@ts-ignore: superjson type error 39 | transformer: superjson, 40 | }); 41 | this.trpc = client; 42 | } 43 | 44 | async ping(): Promise { 45 | const response = await fetch(this.sdkBase + "/ext/ping", { 46 | method: "GET", 47 | headers: { 48 | Authorization: `Bearer ${this.key}`, 49 | Accept: "application/json", 50 | "Content-Type": "application/json", 51 | }, 52 | }); 53 | 54 | if (response.status === 401) { 55 | return null; 56 | } 57 | if (response.ok) { 58 | this.pId = (await response.json()).pId; 59 | return this.pId; 60 | } else { 61 | throw Error(`Failed to ping with server ${await response.text()} `); 62 | } 63 | } 64 | 65 | async getUploadURL(fileName: string): Promise { 66 | const response = await fetch(this.sdkBase + "/ext/upload", { 67 | method: "POST", 68 | headers: { 69 | Authorization: `Bearer ${this.key}`, 70 | Accept: "application/json", 71 | "Content-Type": "application/json", 72 | }, 73 | body: JSON.stringify({ fileName }), 74 | }); 75 | 76 | if (response.ok) { 77 | const data = await response.json(); 78 | return data.url; 79 | } else { 80 | throw Error(`Failed to get upload url: `); 81 | } 82 | } 83 | 84 | async uploadExtensionFile(url: string, filePath: string) { 85 | const f = await Deno.open(filePath); 86 | const response = await fetch(url, { 87 | method: "PUT", 88 | body: readableStreamFromReader(f), 89 | headers: { 90 | "Content-Type": "text/javascript", 91 | }, 92 | }); 93 | if (!response.ok) { 94 | throw Error(`Failed to upload file: ${response.statusText}`); 95 | } 96 | } 97 | 98 | async listAgents() { 99 | const exts = await this.trpc["callable.getCallables"].query(); 100 | return exts; 101 | } 102 | 103 | async listFiles() { 104 | const response = await fetch(this.sdkBase + "/files", { 105 | method: "GET", 106 | headers: { 107 | Authorization: `Bearer ${this.key}`, 108 | Accept: "application/json", 109 | "Content-Type": "application/json", 110 | }, 111 | }); 112 | 113 | if (response.ok) { 114 | const data = await response.json(); 115 | return data.files 116 | } else { 117 | throw Error(`Failed to list files ${await response.text()} `); 118 | } 119 | } 120 | 121 | async uploadFile(filePath: string) { 122 | const decoder = new TextDecoder("utf-8"); 123 | const f = Deno.readFileSync(filePath); 124 | const formData = new FormDataV2(); 125 | const file_extension = filePath.split(".").pop(); 126 | let mime_type = "application/octet-stream"; 127 | if (file_extension && typeByExtension(file_extension)) { 128 | mime_type = typeByExtension(file_extension) as string; 129 | } 130 | formData.append('file', decoder.decode(f), { 131 | filename: path.basename(filePath), 132 | contentType: mime_type 133 | }); 134 | 135 | const response = await fetch(this.sdkBase + "/files", { 136 | method: "POST", 137 | headers: formData.getHeaders({ 138 | Authorization: `Bearer ${this.key}`, 139 | }), 140 | body: formData.getBuffer(), 141 | }); 142 | if (!response.ok) { 143 | throw Error(`Failed to upload file: ${await response.text()}`); 144 | } 145 | const file_info = await response.json(); 146 | return file_info; 147 | } 148 | 149 | async getFileById(id: string) { 150 | const response = await fetch(this.sdkBase + "/files/" + id, { 151 | method: "GET", 152 | headers: { 153 | Authorization: `Bearer ${this.key}`, 154 | }, 155 | }); 156 | if (!response.ok) { 157 | throw Error(`Failed to upload file: ${await response.text()}`); 158 | } 159 | const file_info = await response.json(); 160 | return file_info.file as ExternalFileType; 161 | } 162 | 163 | async downloadFileById(id: string, output: string) { 164 | const response = await fetch(this.sdkBase + "/files/" + id + "/content", { 165 | method: "GET", 166 | headers: { 167 | Authorization: `Bearer ${this.key}`, 168 | }, 169 | }); 170 | if (!response.ok) { 171 | throw Error(`Failed to upload file: ${await response.text()}`); 172 | } 173 | const file = await Deno.open(output, {write: true, create: true}); 174 | await file.write(new Uint8Array(await response.arrayBuffer())); 175 | return "file saved to " + output; 176 | } 177 | 178 | async deleteFileById(id: string) { 179 | const response = await fetch(this.sdkBase + "/files/" + id, { 180 | method: "DELETE", 181 | headers: { 182 | Authorization: `Bearer ${this.key}`, 183 | }, 184 | }); 185 | if (!response.ok) { 186 | throw Error(`Failed to upload file: ${await response.text()}`); 187 | } 188 | const file_info = await response.json(); 189 | return file_info; 190 | } 191 | 192 | async checkValidVersion(rebyte: RebyteJson) { 193 | const response = await fetch(this.sdkBase + "/ext/check", { 194 | method: "POST", 195 | headers: { 196 | Authorization: `Bearer ${this.key}`, 197 | Accept: "application/json", 198 | "Content-Type": "application/json", 199 | }, 200 | body: JSON.stringify({ name: rebyte.name, version: rebyte.version }), 201 | }); 202 | 203 | if (response.ok) { 204 | const data = await response.json(); 205 | console.log(data.message); 206 | } else { 207 | throw Error(`Failed to check name ${await response.text()} `); 208 | } 209 | } 210 | 211 | async createExtension(rebyte: RebyteJson, fileId: string) { 212 | const response = await fetch(this.sdkBase + `/ext/${rebyte.name}`, { 213 | method: "POST", 214 | headers: { 215 | Authorization: `Bearer ${this.key}`, 216 | Accept: "application/json", 217 | "Content-Type": "application/json", 218 | }, 219 | body: JSON.stringify({ ...rebyte, fileId }), 220 | }); 221 | 222 | if (!response.ok) { 223 | throw Error(`Failed to create extension err: ${await response.text()} `); 224 | } 225 | } 226 | 227 | async getExtensions() { 228 | const exts = await this.trpc["extension.get"].query(); 229 | return exts["json"]; 230 | } 231 | 232 | async upsertDoc( 233 | knowledgeName: string, 234 | file: Deno.DirEntry, 235 | baseDir: string, 236 | ): Promise { 237 | console.log("upserting doc: ", file.name); 238 | const urlSafeName = encodeURIComponent(knowledgeName); 239 | const url = `${this.sdkBase}/p/${this.pId}/knowledge/${urlSafeName}/d/${file.name}/upload`; 240 | 241 | const fileContent = await Deno.readFile(path.join(baseDir, file.name)); 242 | 243 | const form = new FormData(); 244 | form.append( 245 | "file", 246 | new Blob([fileContent], { 247 | type: file.name.endsWith(".pdf") ? "application/pdf" : "text/plain", 248 | }), 249 | file.name, 250 | ); 251 | form.append("knowledgeName", knowledgeName); 252 | 253 | try { 254 | const response = await fetch(url, { 255 | method: "POST", 256 | body: form, 257 | headers: { 258 | Authorization: `Bearer ${this.key}`, 259 | }, 260 | }); 261 | console.log("upserted doc success: ", file.name); 262 | return response.statusText; 263 | } catch (error) { 264 | console.log(error); 265 | throw Error(`Failed to index file ${file.name}`); 266 | } 267 | } 268 | 269 | async createThread(metadata?: string) { 270 | const url = `${this.sdkBase}/threads` 271 | const response = await fetch(url, { 272 | method: "POST", 273 | headers: { 274 | Authorization: `Bearer ${this.key}`, 275 | "Content-Type": "application/json", 276 | }, 277 | body: JSON.stringify({ 278 | metadata: metadata ? JSON.parse(metadata) : undefined 279 | }) 280 | }); 281 | if (response.ok) { 282 | return await response.json() as ThreadType; 283 | } else { 284 | throw Error(`Failed to create thread ${JSON.stringify(await response.json())}`); 285 | } 286 | } 287 | 288 | async listThreads(query: ListQuery) { 289 | const url = `${this.sdkBase}/threads?${listQueryString(query)}` 290 | const response = await fetch(url, { 291 | method: "GET", 292 | headers: { Authorization: `Bearer ${this.key}`}, 293 | }); 294 | if (response.ok) { 295 | return await response.json() as ListResult; 296 | } else { 297 | throw Error(`Failed to list threads ${JSON.stringify(await response.json())}`); 298 | } 299 | } 300 | 301 | async createKnowledge( 302 | name: string, 303 | description: string, 304 | visibility: KnowledgeVisibility, 305 | embedder: string, 306 | chunkSize: number 307 | ) { 308 | const url = `${this.sdkBase}/p/${this.pId}/knowledge` 309 | const response = await fetch(url, { 310 | method: "POST", 311 | headers: { 312 | Authorization: `Bearer ${this.key}`, 313 | "Content-Type": "application/json", 314 | }, 315 | body: JSON.stringify({ 316 | name, 317 | description, 318 | visibility, 319 | embedder, 320 | chunkSize, 321 | provider: "files" // Only support create files knowledge through API 322 | }) 323 | }); 324 | if (response.ok) { 325 | return await response.json() as { knowledge: KnowledgeType }; 326 | } else { 327 | throw Error(`Failed to create knowledge ${JSON.stringify(await response.json())}`); 328 | } 329 | } 330 | 331 | async insertContentToKnowledge( 332 | knowledgeName: string, 333 | documentId: string, 334 | text: string, 335 | ) { 336 | const url = `${this.sdkBase}/p/${this.pId}/knowledge/${knowledgeName}/d` 337 | const response = await fetch(url, { 338 | method: "POST", 339 | headers: { 340 | Authorization: `Bearer ${this.key}`, 341 | "Content-Type": "application/json", 342 | }, 343 | body: JSON.stringify({ 344 | documentId, 345 | text, 346 | }) 347 | }); 348 | if (response.ok) { 349 | return await response.json() as { documentId: string, textSize: number }; 350 | } else { 351 | throw Error(`Failed to insert text to knowledge ${JSON.stringify(await response.json())}`); 352 | } 353 | } 354 | 355 | async getThread(threadId: string) { 356 | const url = `${this.sdkBase}/threads/${threadId}` 357 | const response = await fetch(url, { 358 | method: "GET", 359 | headers: { Authorization: `Bearer ${this.key}`}, 360 | }); 361 | if (response.ok) { 362 | return await response.json() as ThreadType; 363 | } else { 364 | throw Error(`Failed to get thread ${JSON.stringify(await response.json())}`); 365 | } 366 | } 367 | 368 | async updateThread(threadId: string, metadata?: string) { 369 | const url = `${this.sdkBase}/threads/${threadId}` 370 | const response = await fetch(url, { 371 | method: "POST", 372 | headers: { 373 | Authorization: `Bearer ${this.key}`, 374 | "Content-Type": "application/json", 375 | }, 376 | body: JSON.stringify({ 377 | metadata: metadata ? JSON.parse(metadata) : undefined 378 | }) 379 | }); 380 | if (response.ok) { 381 | return await response.json() as ThreadType; 382 | } else { 383 | throw Error(`Failed to update thread ${JSON.stringify(await response.json())}`); 384 | } 385 | } 386 | 387 | async createMessage(threadId: string, content: string, metadata?: string) { 388 | const url = `${this.sdkBase}/threads/${threadId}/messages` 389 | const message: MessageType = { 390 | role: "user", 391 | content, 392 | metadata: metadata ? JSON.parse(metadata) : undefined 393 | } 394 | const response = await fetch(url, { 395 | method: "POST", 396 | headers: { 397 | Authorization: `Bearer ${this.key}`, 398 | "Content-Type": "application/json", 399 | }, 400 | body: JSON.stringify(message) 401 | }); 402 | if (response.ok) { 403 | return await response.json() as MessageType; 404 | } else { 405 | throw Error(`Failed to create message ${JSON.stringify(await response.json())}`); 406 | } 407 | } 408 | 409 | async listMessages(threadId: string, query: ListQuery) { 410 | const url = `${this.sdkBase}/threads/${threadId}/messages?${listQueryString(query)}` 411 | const response = await fetch(url, { 412 | method: "GET", 413 | headers: { Authorization: `Bearer ${this.key}`}, 414 | }); 415 | if (response.ok) { 416 | return await response.json() as ListResult; 417 | } else { 418 | throw Error(`Failed to list messages ${JSON.stringify(await response.json())}`); 419 | } 420 | } 421 | 422 | async getMessage(threadId: string, messageId: string) { 423 | const url = `${this.sdkBase}/threads/${threadId}/messages/${messageId}` 424 | const response = await fetch(url, { 425 | method: "GET", 426 | headers: { Authorization: `Bearer ${this.key}`}, 427 | }); 428 | if (response.ok) { 429 | return await response.json() as MessageType; 430 | } else { 431 | throw Error(`Failed to get message ${JSON.stringify(await response.json())}`); 432 | } 433 | } 434 | 435 | async updateMessage(threadId: string, messageId: string, metadata?: string) { 436 | const url = `${this.sdkBase}/threads/${threadId}/messages/${messageId}` 437 | const response = await fetch(url, { 438 | method: "POST", 439 | headers: { 440 | Authorization: `Bearer ${this.key}`, 441 | "Content-Type": "application/json", 442 | }, 443 | body: JSON.stringify({ 444 | metadata: metadata ? JSON.parse(metadata) : undefined 445 | }) 446 | }); 447 | if (response.ok) { 448 | return await response.json() as MessageType; 449 | } else { 450 | throw Error(`Failed to update message ${JSON.stringify(await response.json())}`); 451 | } 452 | } 453 | 454 | async listRuns(threadId: string, query: ListQuery) { 455 | const url = `${this.sdkBase}/threads/${threadId}/runs?${listQueryString(query)}` 456 | const response = await fetch(url, { 457 | method: "GET", 458 | headers: { Authorization: `Bearer ${this.key}` }, 459 | }); 460 | if (response.ok) { 461 | return await response.json() as ListResult; 462 | } else { 463 | throw Error(`Failed to list runs ${JSON.stringify(await response.json())}`); 464 | } 465 | } 466 | 467 | async getRun(runId: string) { 468 | const url = `${this.sdkBase}/runs/${runId}` 469 | const response = await fetch(url, { 470 | method: "GET", 471 | headers: { Authorization: `Bearer ${this.key}`}, 472 | }); 473 | if (response.ok) { 474 | return await response.json() as RunType; 475 | } else { 476 | throw Error(`Failed to get run ${JSON.stringify(await response.json())}`); 477 | } 478 | } 479 | } 480 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import { RebyteAPI } from "./client.ts"; 2 | import { homedir } from "node:os"; 3 | 4 | const CONFIG_FILE_NAME = "config.json"; 5 | 6 | export type RebyteServer = { 7 | url: string; 8 | api_key: string; 9 | pId: string; 10 | }; 11 | 12 | class RebyteConfig { 13 | config_dir: string; 14 | api_key?: string; 15 | pId?: string; 16 | servers: RebyteServer[]; 17 | 18 | constructor() { 19 | const home = homedir(); 20 | if (!home) { 21 | throw Error("Can't find home dir"); 22 | } 23 | this.config_dir = home + "/.rebyte"; 24 | this.servers = []; 25 | } 26 | 27 | async restore() { 28 | const filePath = this.config_dir + "/" + CONFIG_FILE_NAME; 29 | try { 30 | const cachedConfig = JSON.parse(await Deno.readTextFile(filePath)); 31 | // deduplicate by api_key 32 | if (cachedConfig && cachedConfig.api_key && cachedConfig.pId) { 33 | this.api_key = cachedConfig.api_key; 34 | this.pId = cachedConfig.pId; 35 | } 36 | this.servers = cachedConfig.servers || []; 37 | // this.servers = cachedConfig.servers; 38 | } catch (_) { 39 | // ignore 40 | } 41 | } 42 | 43 | activeServer(): RebyteServer | undefined { 44 | if (!this.api_key || !this.pId) { 45 | return; 46 | } 47 | return this.servers.find((s) => s.api_key === this.api_key); 48 | } 49 | 50 | async save() { 51 | Deno.mkdirSync(this.config_dir, { recursive: true }); 52 | 53 | await this.writeJson(this.config_dir + "/" + CONFIG_FILE_NAME); 54 | } 55 | 56 | async writeJson(filePath: string) { 57 | await Deno.writeTextFile(filePath, JSON.stringify(this, null, 2), { 58 | create: true, 59 | }); 60 | } 61 | } 62 | export const config = new RebyteConfig(); 63 | await config.restore(); 64 | 65 | export async function login(api_key: string, url: string): Promise { 66 | const client = new RebyteAPI({ api_key, url, pId: "" }); 67 | const pId = await client.ping(); 68 | if (!pId) { 69 | return false; 70 | } 71 | config.api_key = api_key; 72 | config.pId = pId; 73 | const exists = config.servers.find( 74 | (server) => server.url == url && server.pId == pId, 75 | ); 76 | if (!exists) { 77 | config.servers.push({ api_key, url, pId }); 78 | } 79 | await config.save(); 80 | return true; 81 | } 82 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { cac } from "cac"; 2 | import { config, login } from "./config.ts"; 3 | import { 4 | createThread, 5 | listThreads, 6 | getThread, 7 | updateThread, 8 | createMessage, 9 | listMessages, 10 | getMessage, 11 | updateMessage, 12 | listRuns, 13 | getRun, 14 | deploy, 15 | import_dir, 16 | list_agent, 17 | list_extension, 18 | list_file, 19 | newRebyteJson, 20 | upload_file, 21 | createKnowledge, 22 | insertTextToKnowledge, 23 | get_file, 24 | delete_file, 25 | download_file, 26 | } from "./rebyte.ts"; 27 | import { version } from "./version.ts"; 28 | import { compareVersion } from "./utils.ts"; 29 | import { assert } from "assert"; 30 | 31 | const cli = cac("rebyte"); 32 | 33 | cli 34 | .command("update", "Update rebyte cli to latest version") 35 | .action(async () => { 36 | // get content https://api.github.com/repos/ReByteAI/rebyte-cli/releases/latest 37 | // download content 38 | 39 | const response = await fetch( 40 | "https://api.github.com/repos/ReByteAI/rebyte-cli/releases/latest", 41 | ); 42 | const latestVersion = JSON.parse(await response.text()).tag_name; 43 | // remove v from version 44 | const latestVersionNumber = latestVersion.substring(1); 45 | const currentVersionNumber = version.substring(1); 46 | if (compareVersion(currentVersionNumber, latestVersionNumber)) { 47 | console.log( 48 | `New version ${latestVersion} found, please update to latest version, run: wget -qO- https://raw.githubusercontent.com/rebyteai/rebyte-cli/main/install.sh | sudo sh -`, 49 | ); 50 | } else { 51 | console.log("You are using latest version"); 52 | } 53 | }); 54 | 55 | cli 56 | .command("login", "Login rebyte use your api key") 57 | .option("-k, --api-key ", "Your rebyte api key") 58 | .option( 59 | "-u, --url ", 60 | "Your rebyte server url, default is: https://rebyte.ai. For cn user, please use: https://colingo.ai", 61 | { 62 | default: "https://rebyte.ai", 63 | }, 64 | ) 65 | .action(async (options) => { 66 | const key = options.apiKey; 67 | const url = options.url; 68 | const success = await login(key, url); 69 | if (success) { 70 | console.log("Login successfully 🎉"); 71 | } else { 72 | console.log("Login failed, api key is invalidate"); 73 | } 74 | }); 75 | 76 | cli.command("get-context", "show current server context").action(async () => { 77 | console.log(config); 78 | }); 79 | 80 | cli.command("use-context", "use specific server context") 81 | .option("-k, --api-key ", "Your rebyte api key") 82 | .action(async (options) => { 83 | const key = options.apiKey; 84 | // lookup config to find api key match with key 85 | // if not found, return error 86 | 87 | const server = config.servers.find((c) => c.api_key === key); 88 | if (!server) { 89 | console.log("api key not found"); 90 | return; 91 | } 92 | const success = await login(key, server.url); 93 | if (success) { 94 | console.log("Login successfully 🎉"); 95 | } else { 96 | console.log("Login failed, api key is invalidate"); 97 | } 98 | }); 99 | 100 | cli.command("logout", "Logout current project").action(async () => { 101 | // todo(cj): implement logout 102 | console.log("logout not implement yet"); 103 | }); 104 | 105 | cli 106 | .command("list-agent", "List all agent belong to project") 107 | .action(async () => { 108 | await list_agent(); 109 | }); 110 | 111 | // cli 112 | // .command("list-knowledge", "List all knowledge belong to project") 113 | // .action(async () => { 114 | // await list_knowledge(); 115 | // }); 116 | 117 | cli 118 | .command("list-extension", "List all extensions belong to project") 119 | .action(async () => { 120 | await list_extension(); 121 | }); 122 | 123 | cli 124 | .command("list-file", "List all files belong to project") 125 | .action(async () => { 126 | await list_file(); 127 | }); 128 | 129 | cli 130 | .command("upload-file", "upload file to rebyte for further processing") 131 | .option("-f, --file ", "file path to upload") 132 | .action(async (options) => { 133 | const file = options.file; 134 | await upload_file(file); 135 | }); 136 | 137 | cli 138 | .command("get-file", "get file metadata from rebyte") 139 | .option("-f, --fileId ", "file id") 140 | .action(async (options) => { 141 | const fileId = options.fileId; 142 | await get_file(fileId); 143 | }); 144 | 145 | cli 146 | .command("download-file", "download file content from rebyte") 147 | .option("-o, --output ", "output file name to save") 148 | .option("-f, --fileId ", "file id") 149 | .action(async (options) => { 150 | const fileId = options.fileId; 151 | const output = options.output; 152 | assert(fileId, "fileId is required"); 153 | assert(output, "output file name is required"); 154 | await download_file(fileId, output); 155 | }); 156 | 157 | cli 158 | .command("delete-file", "delete file from rebyte") 159 | .option("-f, --fileId ", "file id") 160 | .action(async (options) => { 161 | const fileId = options.fileId; 162 | await delete_file(fileId); 163 | }); 164 | 165 | cli 166 | .command("deploy ", "deploy your extension to rebyte") 167 | .action(async (dir) => { 168 | const rebyte = await newRebyteJson(dir); 169 | await deploy(dir, rebyte); 170 | }) 171 | .example("rebyte deploy ."); 172 | 173 | cli 174 | .command("index ", "import files in directory to knowledge") 175 | .option("-k, --knowledge ", "knowledge name") 176 | .action(async (dir, options) => { 177 | await import_dir(dir, options.knowledge); 178 | }); 179 | 180 | cli 181 | .command("create-thread", "Create thread") 182 | .option("-m, --metadata ", "A key-value JSON string of metadata") 183 | .action(async (options) => { 184 | await createThread(options.metadata); 185 | }); 186 | 187 | cli 188 | .command("list-threads", "List threads") 189 | .option("-l, --limit ", "A limit on the number of objects. Defaults to 20") 190 | .option("-o, --order ", "asc for ascending order and desc for descending order. Defaults to desc") 191 | .option("-a, --after ", "An object ID that defines your place in the list") 192 | .option("-b, --before ", "An object ID that defines your place in the list") 193 | .action(async (options) => { 194 | await listThreads(options); 195 | }); 196 | 197 | cli 198 | .command("create-knowledge", "Create knowledge") 199 | .option("-n, --name ", "The name of the knowledge. Must unique in your project") 200 | .option("-d, --description ", "The description of the knowledge. Description must be less than 255 chars and more than 32 chars") 201 | .option("-v, --visibility ", "The visibility of the knowledge, 'private' or 'public'. Default: private") 202 | .option("-e, --embedder ", "The embedder id, available values is 'openai.text-embedding-ada-002', 'openai.text-embedding-3-small'(team only), 'openai.text-embedding-3-large'(team only), 'voyage.voyage-02'(team only), 'voyage.voyage-lite-02-instruct'(team only), 'voyage.voyage-code-02'(team only), Default: openai.text-embedding-ada-002") 203 | .option("-c, --chunkSize ", "The chunk size, must not be greater than embedder max context length, Default: 384") 204 | .action(async (options) => { 205 | await createKnowledge( 206 | options.name, 207 | options.description, 208 | options.visibility || "private", 209 | options.embedder || "openai.text-embedding-ada-002", 210 | options.chunkSize || 384 211 | ) 212 | }); 213 | cli 214 | .command("insert-text", "Insert text to knowledge") 215 | .option("-k, --knowledgeName ", "The name of the knowledge.") 216 | .option("-d, --documentId ", "The documentId in the knowledge of this text. Description unique in your project") 217 | .option("-t, --text ", "The text content to be inserted") 218 | .action(async (options) => { 219 | await insertTextToKnowledge( 220 | options.knowledgeName, 221 | options.documentId, 222 | options.text, 223 | ) 224 | }); 225 | 226 | cli 227 | .command("get-thread ", "Retrieve thread by ID") 228 | .action(async (thread) => { 229 | await getThread(thread); 230 | }); 231 | 232 | cli 233 | .command("update-thread ", "Modify thread by ID") 234 | .option("-m, --metadata ", "A key-value JSON string of metadata") 235 | .action(async (thread, options) => { 236 | await updateThread(thread, options.metadata); 237 | }); 238 | 239 | cli 240 | .command("create-message ", "Create message on thread") 241 | .option("-c, --content ", "Message content") 242 | .option("-m, --metadata ", "A key-value JSON string of metadata") 243 | .action(async (thread, options) => { 244 | await createMessage(thread, options.content, options.metadata); 245 | }); 246 | 247 | cli 248 | .command("list-messages ", "List messages on thread") 249 | .option("-l, --limit ", "A limit on the number of objects. Defaults to 20") 250 | .option("-o, --order ", "asc for ascending order and desc for descending order. Defaults to desc") 251 | .option("-a, --after ", "An object ID that defines your place in the list") 252 | .option("-b, --before ", "An object ID that defines your place in the list") 253 | .action(async (thread, options) => { 254 | await listMessages(thread, options); 255 | }); 256 | 257 | cli 258 | .command("get-message ", "Retrieve message by ID") 259 | .action(async (thread, message) => { 260 | await getMessage(thread, message); 261 | }); 262 | 263 | cli 264 | .command("update-message ", "Modify message by ID") 265 | .option("-m, --metadata ", "A key-value JSON string of metadata") 266 | .action(async (thread, message, options) => { 267 | await updateMessage(thread, message, options.metadata); 268 | }); 269 | 270 | cli 271 | .command("list-runs ", "List runs on thread") 272 | .option("-l, --limit ", "A limit on the number of objects. Defaults to 20") 273 | .option("-o, --order ", "asc for ascending order and desc for descending order. Defaults to desc") 274 | .option("-a, --after ", "An object ID that defines your place in the list") 275 | .option("-b, --before ", "An object ID that defines your place in the list") 276 | .action(async (thread, options) => { 277 | await listRuns(thread, options); 278 | }); 279 | 280 | cli 281 | .command("get-run ", "Retrieve run by ID") 282 | .action(async (run) => { 283 | await getRun(run); 284 | }); 285 | 286 | async function update() { 287 | const isDev= Deno.env.get("REBYTE_CLI_DEV") === "1"; 288 | if (isDev) { 289 | return true; 290 | } 291 | const response = await fetch( 292 | "https://api.github.com/repos/ReByteAI/rebyte-cli/releases/latest", 293 | ); 294 | const latestVersion = JSON.parse(await response.text()).tag_name; 295 | // remove v from version 296 | const latestVersionNumber = latestVersion.substring(1); 297 | const currentVersionNumber = version.substring(1); 298 | if (compareVersion(currentVersionNumber, latestVersionNumber)) { 299 | console.log( 300 | `New version ${latestVersion} found, please update to latest version, run: wget -qO- https://raw.githubusercontent.com/rebyteai/rebyte-cli/main/install.sh | sudo sh -`, 301 | ); 302 | return false; 303 | } else { 304 | console.log("You are using latest version"); 305 | return true; 306 | } 307 | } 308 | 309 | // whether we're running from prod or locally 310 | 311 | const latest = await update(); 312 | if (!latest) { 313 | Deno.exit(1); 314 | } 315 | cli.help(); 316 | cli.version(version); 317 | cli.outputHelp(); 318 | const parsed = cli.parse(); 319 | -------------------------------------------------------------------------------- /src/pagination.ts: -------------------------------------------------------------------------------- 1 | export type ListQuery = { 2 | // A limit on the number of objects to be returned. 3 | // Defaults to 20 4 | limit?: number 5 | // Sort order by the timestamp of the objects. asc for ascending order and desc for descending order. 6 | // Defaults to desc 7 | order?: "asc" | "desc" 8 | // A cursor for use in pagination. after is an object ID that defines your place in the list. 9 | // For instance, if you make a list request and receive 100 objects, ending with obj_foo, 10 | // your subsequent call can include after=obj_foo in order to fetch the next page of the list. 11 | after?: string 12 | // A cursor for use in pagination. before is an object ID that defines your place in the list. 13 | // For instance, if you make a list request and receive 100 objects, ending with obj_foo, 14 | // your subsequent call can include before=obj_foo in order to fetch the previous page of the list. 15 | before?: string 16 | } 17 | export type ListResult = { 18 | list: T[] 19 | } 20 | export function listQueryString(q: ListQuery) { 21 | return `limit=${q.limit ?? 20}&order=${q.order ?? "desc"}&after=${ 22 | q.after ?? "" 23 | }&before=${q.before ?? ""}` 24 | } 25 | 26 | export function displayListQuery(q: ListQuery) { 27 | return `limit: ${q.limit ?? 20} order: ${q.order ?? "desc"}${q.after ? ` after: ${q.after}` : ""}${q.before ? ` before: ${q.before}` : ""}`; 28 | } 29 | -------------------------------------------------------------------------------- /src/rebyte.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import * as esbuild from "esbuild"; 3 | import { denoPlugins } from "esbuild-deno-loader"; 4 | import { z } from "zod"; 5 | import { RebyteAPI } from "./client.ts"; 6 | import { config } from "./config.ts"; 7 | import AsciiTable, { AsciiAlign } from "asciitable"; 8 | import { chalk } from "./chalk.ts"; 9 | import { ListQuery, displayListQuery } from "./pagination.ts"; 10 | import { formatUnix } from "./utils.ts"; 11 | import { MessageType, ThreadType, RunType, KnowledgeVisibility, KnowledgeType } from "./types.ts"; 12 | import { assert } from "assert"; 13 | 14 | const REBYTE_JSON_FILE = "rebyte.json"; 15 | 16 | export const supportedFileTypes = [ 17 | "doc", 18 | "docx", 19 | "img", 20 | "epub", 21 | "jpeg", 22 | "jpg", 23 | "png", 24 | "xls", 25 | "xlsx", 26 | "ppt", 27 | "pptx", 28 | "md", 29 | "txt", 30 | "rtf", 31 | "rst", 32 | "pdf", 33 | "html", 34 | "eml", 35 | ]; 36 | 37 | function logSuccess(msg: string) { 38 | console.log(chalk.green(msg)); 39 | } 40 | 41 | const RebyteJson = z.object({ 42 | name: z 43 | .string() 44 | .min(5) 45 | .max(30) 46 | .refine((value: string) => /^[a-z0-9\_]*$/.test(value), { 47 | message: "Only lowercase letters, number and underline are allowed", 48 | }), 49 | displayName: z 50 | .string() 51 | .max(30, { 52 | message: "displayName must be less than 30 characters", 53 | }) 54 | .optional() 55 | .nullable(), 56 | description: z.string().optional().nullable(), 57 | version: z.string(), 58 | main: z.string().optional().nullable(), 59 | out: z.string().optional().nullable(), 60 | // link to doc 61 | docLink: z.string().optional().nullable(), 62 | // agent Id 63 | exampleAgent: z.string().optional().nullable(), 64 | inputArgs: z 65 | .array( 66 | z.object({ 67 | name: z.string(), 68 | description: z.string(), 69 | type: z.string(), 70 | required: z.boolean().optional(), 71 | }), 72 | ) 73 | .optional(), 74 | }); 75 | 76 | export type RebyteJson = z.infer; 77 | 78 | export async function newRebyteJson(dir: string): Promise { 79 | const file_path = path.join(dir, REBYTE_JSON_FILE); 80 | await Deno.stat(file_path); 81 | const data = JSON.parse(await Deno.readTextFile(file_path)); 82 | return RebyteJson.parse(data); 83 | } 84 | 85 | function getUploadFileName(rebyte: RebyteJson, pid: string): string { 86 | return ( 87 | pid + "-" + rebyte.name + "-" + rebyte.version + "-" + new Date().getTime() 88 | ); 89 | } 90 | 91 | export async function deploy(dir: string, rebyte: RebyteJson) { 92 | const activeServer = config.activeServer(); 93 | if (!activeServer) { 94 | throw Error("Please login first"); 95 | } 96 | // check name is available 97 | const client = new RebyteAPI(activeServer); 98 | 99 | Deno.chdir(dir); 100 | const entryPoint = path.join(Deno.cwd(), rebyte.main ?? "index.ts"); 101 | const output = path.join( 102 | Deno.cwd(), 103 | rebyte.out ?? "./dist/" + rebyte.name + ".js", 104 | ); 105 | 106 | await esbuild.build({ 107 | plugins: [...denoPlugins({ loader: "portable", nodeModulesDir: true })], 108 | // plugins: [...denoPlugins({ loader: "portable", configPath: "/Users/homo/src/callable/ext_diagram/deno.json"})], 109 | entryPoints: [entryPoint], 110 | outfile: output, 111 | bundle: true, 112 | format: "esm", 113 | write: true, 114 | }); 115 | esbuild.stop(); 116 | 117 | console.log("Build success 🎉"); 118 | 119 | await client.checkValidVersion(rebyte); 120 | 121 | const shouldProceed = confirm( 122 | `Are you sure you want to deploy ${rebyte.name} version ${rebyte.version} to ${activeServer.url}?`, 123 | ); 124 | if (!shouldProceed) { 125 | console.log("Deploy canceled"); 126 | return; 127 | } 128 | 129 | // get upload url 130 | const fileId = getUploadFileName(rebyte, activeServer.pId); 131 | const uploadURL = await client.getUploadURL(fileId); 132 | await client.uploadExtensionFile(uploadURL, output); 133 | await client.createExtension(rebyte, fileId); 134 | console.log( 135 | `Deploy ReByte Extension Success 🎉, you can go to ${activeServer.url}/p/${activeServer.pId}/settings/extensions to check it`, 136 | ); 137 | } 138 | 139 | export async function list_extension() { 140 | const activeServer = config.activeServer(); 141 | if (!activeServer) { 142 | throw Error("Please login first"); 143 | } 144 | const client = new RebyteAPI(activeServer); 145 | 146 | let extensions = await client.getExtensions(); 147 | // flatten 148 | extensions = extensions.reduce((acc: any, cur: any) => { 149 | acc.push(...cur[1]); 150 | return acc; 151 | }, []); 152 | 153 | // console.log(extensions) 154 | 155 | const table = AsciiTable.fromJSON({ 156 | title: "Action Extensions", 157 | heading: ["id", "name"], 158 | rows: extensions.map((a: any) => [a.name, a.version]), 159 | }); 160 | console.log(table.toString()); 161 | 162 | logSuccess("List extension success 🎉"); 163 | } 164 | 165 | // export async function list_knowledge() { 166 | // const activeServer = config.activeServer(); 167 | // if (!activeServer) { 168 | // throw Error("Please login first"); 169 | // } 170 | // const client = new RebyteAPI(activeServer); 171 | // const agents = await client.listAgents(); 172 | // 173 | // const table = AsciiTable.fromJSON({ 174 | // title: "Title", 175 | // heading: ["id", "name"], 176 | // rows: agents, 177 | // }); 178 | // console.log(table); 179 | // 180 | // logSuccess("List agent success"); 181 | // } 182 | 183 | export async function list_agent() { 184 | const activeServer = config.activeServer(); 185 | if (!activeServer) { 186 | throw Error("Please login first"); 187 | } 188 | const client = new RebyteAPI(activeServer); 189 | const agents = await client.listAgents(); 190 | const table = AsciiTable.fromJSON({ 191 | title: "Agents", 192 | heading: ["id", "name"], 193 | rows: agents.map((a: any) => [a.sId, a.name]), 194 | }); 195 | console.log(table.toString()); 196 | 197 | logSuccess("List agent success"); 198 | } 199 | 200 | export async function list_file() { 201 | const activeServer = config.activeServer(); 202 | if (!activeServer) { 203 | throw Error("Please login first"); 204 | } 205 | const client = new RebyteAPI(activeServer); 206 | const agents = await client.listFiles(); 207 | const table = AsciiTable.fromJSON({ 208 | title: "External Files", 209 | heading: ["uuid", "name"], 210 | rows: agents.map((a: any) => [a.uuid, a.name]), 211 | }); 212 | console.log(table.toString()); 213 | 214 | logSuccess("List files success"); 215 | } 216 | 217 | export async function upload_file(file: string) { 218 | const activeServer = config.activeServer(); 219 | if (!activeServer) { 220 | throw Error("Please login first"); 221 | } 222 | const client = new RebyteAPI(activeServer); 223 | const { fileId } = await client.uploadFile(file); 224 | logSuccess("Upload file success, file id: " + fileId); 225 | } 226 | 227 | export async function get_file(fileId: string) { 228 | const activeServer = config.activeServer(); 229 | if (!activeServer) { 230 | throw Error("Please login first"); 231 | } 232 | const client = new RebyteAPI(activeServer); 233 | const file_info = await client.getFileById(fileId); 234 | const table = AsciiTable.fromJSON({ 235 | title: "External Files", 236 | heading: ["uuid", "name", "size"], 237 | rows: [[file_info.uuid, file_info.name, file_info.size]], 238 | }); 239 | console.log(table.toString()); 240 | } 241 | 242 | export async function delete_file(fileId: string) { 243 | const activeServer = config.activeServer(); 244 | if (!activeServer) { 245 | throw Error("Please login first"); 246 | } 247 | const client = new RebyteAPI(activeServer); 248 | const { fileId: fId } = await client.deleteFileById(fileId); 249 | assert(fId === fileId, "Delete file failed"); 250 | console.log("File deleted"); 251 | } 252 | 253 | export async function download_file(fileId: string, output: string) { 254 | const activeServer = config.activeServer(); 255 | if (!activeServer) { 256 | throw Error("Please login first"); 257 | } 258 | const client = new RebyteAPI(activeServer); 259 | const msg = await client.downloadFileById(fileId, output); 260 | console.log(msg); 261 | } 262 | 263 | export async function import_dir(dir: string, knowledgeName: string) { 264 | const activeServer = config.activeServer(); 265 | if (!activeServer) { 266 | throw Error("Please login first"); 267 | } 268 | 269 | const files = []; 270 | for await (const entry of Deno.readDir(dir)) { 271 | if (entry.isFile) { 272 | const ext = path.extname(entry.name).slice(1); 273 | if (supportedFileTypes.includes(ext)) { 274 | files.push(entry); 275 | } 276 | } 277 | } 278 | // console.log(files.map((f) => f.name)) 279 | 280 | const table = AsciiTable.fromJSON({ 281 | title: "Files", 282 | heading: ["name"], 283 | rows: files.map((f) => [f.name]), 284 | }); 285 | 286 | console.log(table.toString()); 287 | 288 | const shouldProceed = confirm( 289 | `Found ${files.length} files, Do you want to proceed?`, 290 | ); 291 | if (!shouldProceed) { 292 | return; 293 | } 294 | 295 | // index files 296 | const client = new RebyteAPI(activeServer); 297 | // track progress and log failed files 298 | for (const file of files) { 299 | await client.upsertDoc(knowledgeName, file, dir); 300 | } 301 | 302 | logSuccess(`Index directory ${dir} success 🎉`); 303 | } 304 | 305 | function showThreadTable(title: string, threads: ThreadType[]) { 306 | const table = AsciiTable.fromJSON({ 307 | title, 308 | heading: ["ID", "Created", "More"], 309 | rows: threads.map((thread) => [ 310 | thread.id, 311 | formatUnix(thread.created_at), 312 | JSON.stringify({ 313 | ...thread, 314 | id: undefined, 315 | created_at: undefined, 316 | }) 317 | ]), 318 | }); 319 | console.log(table.toString()); 320 | } 321 | 322 | export async function createThread(metadata?: string) { 323 | const activeServer = config.activeServer(); 324 | if (!activeServer) { 325 | throw Error("Please login first"); 326 | } 327 | const client = new RebyteAPI(activeServer); 328 | const result = await client.createThread(metadata); 329 | showThreadTable(`Thread`, [result]) 330 | logSuccess("Create thread success"); 331 | } 332 | 333 | export async function listThreads(query: ListQuery) { 334 | const activeServer = config.activeServer(); 335 | if (!activeServer) { 336 | throw Error("Please login first"); 337 | } 338 | const client = new RebyteAPI(activeServer); 339 | const result = await client.listThreads(query); 340 | showThreadTable(`Threads (${displayListQuery(query)})`, result.list) 341 | logSuccess("List threads success"); 342 | } 343 | 344 | export async function createKnowledge( 345 | name: string, 346 | description: string, 347 | visibility: KnowledgeVisibility, 348 | embedder: string, 349 | chunkSize: number 350 | ) { 351 | const activeServer = config.activeServer(); 352 | if (!activeServer) { 353 | throw Error("Please login first"); 354 | } 355 | const client = new RebyteAPI(activeServer); 356 | const result = await client.createKnowledge( 357 | name, 358 | description, 359 | visibility, 360 | embedder, 361 | chunkSize, 362 | ); 363 | showKnowledgeTable(`Knowledge`, result.knowledge) 364 | logSuccess("Create knowledge success"); 365 | } 366 | 367 | export async function insertTextToKnowledge( 368 | knowledgeName: string, 369 | documentId: string, 370 | text: string, 371 | ) { 372 | if (text.length == 0) { 373 | throw Error("Must provide text") 374 | } 375 | const activeServer = config.activeServer(); 376 | if (!activeServer) { 377 | throw Error("Please login first"); 378 | } 379 | const client = new RebyteAPI(activeServer); 380 | const result = await client.insertContentToKnowledge( 381 | knowledgeName, 382 | documentId, 383 | text 384 | ); 385 | logSuccess(`Insert text to knowledge success, Document Size: ${result.textSize}`); 386 | } 387 | 388 | export async function getThread(threadId: string) { 389 | const activeServer = config.activeServer(); 390 | if (!activeServer) { 391 | throw Error("Please login first"); 392 | } 393 | const client = new RebyteAPI(activeServer); 394 | const result = await client.getThread(threadId); 395 | showThreadTable(`Thread`, [result]) 396 | logSuccess("Get thread success"); 397 | } 398 | 399 | export async function updateThread(threadId: string, metadata?: string) { 400 | const activeServer = config.activeServer(); 401 | if (!activeServer) { 402 | throw Error("Please login first"); 403 | } 404 | const client = new RebyteAPI(activeServer); 405 | const result = await client.updateThread(threadId, metadata); 406 | showThreadTable(`Thread`, [result]) 407 | logSuccess("Update thread success"); 408 | } 409 | 410 | function showMessageTable(title: string, messages: MessageType[]) { 411 | const table = AsciiTable.fromJSON({ 412 | title, 413 | heading: ["ID", "Created", "Role", "Agent ID", "Name", "Content", "Run ID", "More"], 414 | rows: messages.map((message) => [ 415 | message.id, 416 | formatUnix(message.created_at), 417 | message.role, 418 | message.agent_id, 419 | message.name, 420 | message.content, 421 | message.run_id, 422 | JSON.stringify({ 423 | ...message, 424 | id: undefined, 425 | created_at: undefined, 426 | thread_id: undefined, 427 | role: undefined, 428 | agent_id: undefined, 429 | name: undefined, 430 | content: undefined, 431 | run_id: undefined, 432 | }) 433 | ]), 434 | }); 435 | console.log(table.toString()); 436 | } 437 | 438 | function showKnowledgeTable( 439 | title: string, 440 | knowledge: KnowledgeType) 441 | { 442 | const table = AsciiTable.fromJSON({ 443 | title, 444 | heading: ["Name", "Descriptioin", "Visibility", "SID", "Hub Provider", "Hub ID"], 445 | rows: [knowledge].map((k) => [ 446 | k.name, 447 | k.description, 448 | k.visibility, 449 | k.sId, 450 | k.hub?.provider, 451 | k.hub?.id, 452 | ]), 453 | }); 454 | console.log(table.toString()); 455 | } 456 | 457 | export async function createMessage(threadId: string, content: string, metadata?: string) { 458 | const activeServer = config.activeServer(); 459 | if (!activeServer) { 460 | throw Error("Please login first"); 461 | } 462 | const client = new RebyteAPI(activeServer); 463 | const result = await client.createMessage(threadId, content, metadata); 464 | showMessageTable(`Messages (thread: ${threadId})`, [result]) 465 | logSuccess("Create message success"); 466 | } 467 | 468 | export async function listMessages(threadId: string, query: ListQuery) { 469 | const activeServer = config.activeServer(); 470 | if (!activeServer) { 471 | throw Error("Please login first"); 472 | } 473 | const client = new RebyteAPI(activeServer); 474 | const result = await client.listMessages(threadId, query); 475 | showMessageTable( 476 | `Messages (thread: ${threadId} ${displayListQuery(query)})`, 477 | result.list, 478 | ) 479 | logSuccess("List messages success"); 480 | } 481 | 482 | export async function getMessage(threadId: string, messageId: string) { 483 | const activeServer = config.activeServer(); 484 | if (!activeServer) { 485 | throw Error("Please login first"); 486 | } 487 | const client = new RebyteAPI(activeServer); 488 | const result = await client.getMessage(threadId, messageId); 489 | showMessageTable(`Message (thread: ${threadId})`, [result]) 490 | logSuccess("Get message success"); 491 | } 492 | 493 | export async function updateMessage(threadId: string, messageId: string, metadata?: string) { 494 | const activeServer = config.activeServer(); 495 | if (!activeServer) { 496 | throw Error("Please login first"); 497 | } 498 | const client = new RebyteAPI(activeServer); 499 | const result = await client.updateMessage(threadId, messageId, metadata); 500 | showMessageTable(`Message (thread: ${threadId})`, [result]) 501 | logSuccess("Update message success"); 502 | } 503 | 504 | function showRunTable(title: string, runs: RunType[]) { 505 | const table = AsciiTable.fromJSON({ 506 | title, 507 | heading: ["ID", "Created", "Agent ID", "Status", "More"], 508 | rows: runs.map((run) => [ 509 | run.id, 510 | formatUnix(run.created_at), 511 | run.agent_id, 512 | run.status, 513 | JSON.stringify({ 514 | ...run, 515 | id: undefined, 516 | created_at: undefined, 517 | thread_id: undefined, 518 | agent_id: undefined, 519 | status: undefined, 520 | }) 521 | ]), 522 | }); 523 | console.log(table.toString()); 524 | } 525 | 526 | export async function listRuns(threadId: string, query: ListQuery) { 527 | const activeServer = config.activeServer(); 528 | if (!activeServer) { 529 | throw Error("Please login first"); 530 | } 531 | const client = new RebyteAPI(activeServer); 532 | const result = await client.listRuns(threadId, query); 533 | showRunTable( 534 | `Runs (thread: ${threadId} ${displayListQuery(query)})`, 535 | result.list, 536 | ) 537 | logSuccess("List runs success"); 538 | } 539 | 540 | export async function getRun(runId: string) { 541 | const activeServer = config.activeServer(); 542 | if (!activeServer) { 543 | throw Error("Please login first"); 544 | } 545 | const client = new RebyteAPI(activeServer); 546 | const result = await client.getRun(runId); 547 | showRunTable(`Run (thread: ${result.thread_id ?? ""})`, [result]) 548 | logSuccess("Get run success"); 549 | } 550 | -------------------------------------------------------------------------------- /src/router.ts: -------------------------------------------------------------------------------- 1 | import { initTRPC } from "@trpc/server"; 2 | import { z } from "zod"; 3 | 4 | const t = initTRPC.create(); 5 | const router = t.router; 6 | const publicProcedure = t.procedure; 7 | 8 | export const appRouter = router({ 9 | "extension.get": publicProcedure.query(() => { 10 | return [ 11 | [ 12 | "extension1", 13 | [ 14 | { 15 | name: "extension1", 16 | description: "extension1", 17 | version: "1.0.0", 18 | }, 19 | ], 20 | ], 21 | ]; 22 | }), 23 | "callable.getCallables": publicProcedure.query(() => { 24 | return []; 25 | }), 26 | "gcp.listFiles": publicProcedure.query(() => { 27 | return [ 28 | { 29 | uuid: "uuid", 30 | name: "name", 31 | mimeType: "", 32 | size: 0, 33 | }, 34 | ]; 35 | }), 36 | "gcp.createUploadSignedUrl": publicProcedure 37 | .input( 38 | z.object({ 39 | fileName: z.string({ 40 | required_error: "File name is required", 41 | }), 42 | fileType: z.string({ 43 | required_error: "File type is required", 44 | }), 45 | }), 46 | ) 47 | .mutation((input) => { 48 | return { 49 | uploadUrl: "", 50 | downloadUrl: "", 51 | }; 52 | }), 53 | // "post.create": publicProceducre 54 | // .input( 55 | // z.object({ 56 | // name: z.string(), 57 | // }) 58 | // ) 59 | // .mutation(({ input }) => { 60 | // posts.push(input); 61 | // return input; 62 | // }), 63 | }); 64 | 65 | export type AppRouter = typeof appRouter; 66 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | 2 | export type ThreadType = { 3 | // The identifier, which can be referenced in API endpoints. 4 | id: string 5 | // The Unix timestamp (in seconds) for when the thread was created. 6 | created_at: number 7 | metadata: Record 8 | } 9 | 10 | export type MessageType = { 11 | // The identifier, which can be referenced in API endpoints. 12 | id?: string 13 | // The Unix timestamp (in seconds) for when the message was created. 14 | created_at?: number 15 | // The thread ID that this message belongs to. 16 | thread_id?: string 17 | // The entity that produced the message. Can be user or assistant. 18 | role: string 19 | // The content of the message 20 | content?: any 21 | // If applicable, the ID of the agent that authored this message. 22 | agent_id?: string 23 | // The display name of the agent that produced this message. 24 | name?: string 25 | // The ID of the run that produced this message. 26 | run_id?: string 27 | metadata?: any 28 | } 29 | 30 | export type RunType = { 31 | // The identifier, which can be referenced in API endpoints. 32 | id: string 33 | // The Unix timestamp (in seconds) for when the run was created. 34 | created_at: number 35 | // The ID of the thread that was executed on. 36 | thread_id?: string 37 | // The ID of the agent of this run. 38 | agent_id: string 39 | status: string 40 | } 41 | 42 | export type KnowledgeVisibility = "private" | "public" 43 | 44 | export type KnowledgeType = { 45 | name: string 46 | description?: string 47 | visibility: KnowledgeVisibility 48 | config?: string 49 | runnerProjectId: string 50 | lastUpdatedAt?: string 51 | // project owner's SId 52 | sId: string 53 | hub: { id: string; provider: string } | null 54 | } 55 | 56 | export type ExternalFileType = { 57 | name: string 58 | size: number 59 | mimeType: string 60 | uuid: string 61 | projectId: number 62 | createdAt: Date 63 | } 64 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import moment from "https://deno.land/x/momentjs/mod.ts"; 2 | 3 | export const VersionRegex = new RegExp("^[0-9]+.[0-9]+.[0-9]+$") 4 | 5 | // return true if newVersion is greater than latestVersion 6 | export const compareVersion = (latestVersion: string, newVersion: string) => { 7 | if (!VersionRegex.test(latestVersion)) { 8 | throw new Error( 9 | "version is not valid, please use x.x.x format: " + latestVersion 10 | ) 11 | } 12 | if (!VersionRegex.test(newVersion)) { 13 | throw new Error( 14 | "version is not valid, please use x.x.x format: " + newVersion 15 | ) 16 | } 17 | 18 | const latestVersionArray = latestVersion.split(".") 19 | const newVersionArray = newVersion.split(".") 20 | if (newVersionArray[0] < latestVersionArray[0]) { 21 | return false 22 | } 23 | if (newVersionArray[0] == latestVersionArray[0]) { 24 | if (newVersionArray[1] < latestVersionArray[1]) { 25 | return false 26 | } 27 | if (newVersionArray[1] == latestVersionArray[1]) { 28 | if (newVersionArray[2] <= latestVersionArray[2]) { 29 | return false 30 | } 31 | } 32 | } 33 | return true 34 | } 35 | 36 | export function formatUnix(seconds?: number) { 37 | return seconds ? moment.unix(seconds).format("YYYY-MM-DD HH:mm:ss") : ""; 38 | } 39 | -------------------------------------------------------------------------------- /src/version.ts: -------------------------------------------------------------------------------- 1 | export const version = "v0.2.3"; // note this version will overwrite by build script when release in github workflow 2 | --------------------------------------------------------------------------------