diff --git a/.github/scripts/check_registry_site_health.sh b/.github/scripts/check_registry_site_health.sh index 0ad742ec..9cafec0c 100755 --- a/.github/scripts/check_registry_site_health.sh +++ b/.github/scripts/check_registry_site_health.sh @@ -82,7 +82,8 @@ create_incident() { # Function to check for existing unresolved incidents check_existing_incident() { # Fetch the latest incidents with status not equal to "RESOLVED" - local unresolved_incidents=$(curl -s -X GET "https://api.instatus.com/v1/$INSTATUS_PAGE_ID/incidents" \ + local unresolved_incidents + unresolved_incidents=$(curl -s -X GET "https://api.instatus.com/v1/$INSTATUS_PAGE_ID/incidents" \ -H "Authorization: Bearer $INSTATUS_API_KEY" \ -H "Content-Type: application/json" | jq -r '.incidents[] | select(.status != "RESOLVED") | .id') diff --git a/.github/workflows/check_registry_site_health.yaml b/.github/workflows/check_registry_site_health.yaml index 29e55176..fe4a22a0 100644 --- a/.github/workflows/check_registry_site_health.yaml +++ b/.github/workflows/check_registry_site_health.yaml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Run check.sh run: | diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 45dc17d6..5601ef6a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Detect changed files uses: dorny/paths-filter@v3 id: filter @@ -29,8 +29,11 @@ jobs: - 'scripts/ts_test_auto.sh' - 'scripts/terraform_test_all.sh' - 'scripts/terraform_validate.sh' + - 'scripts/shellcheck_validate.sh' modules: - 'registry/**/modules/**' + shell: + - '**/*.sh' all: - '**' - name: Set up Terraform @@ -64,12 +67,20 @@ jobs: SHARED_CHANGED: ${{ steps.filter.outputs.shared }} MODULE_CHANGED_FILES: ${{ steps.filter.outputs.modules_files }} run: bun terraform-validate + - name: Run ShellCheck + env: + ALL_CHANGED_FILES: ${{ steps.filter.outputs.all_files }} + SHARED_CHANGED: ${{ steps.filter.outputs.shared }} + SHELL_CHANGED_FILES: ${{ steps.filter.outputs.shell_files }} + run: bun shellcheck + - name: Validate set -u ordering + run: ./scripts/validate_set_u_order.sh validate-style: name: Check for typos and unformatted code runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Bun uses: oven-sh/setup-bun@v2 with: @@ -82,7 +93,7 @@ jobs: - name: Validate formatting run: bun fmt:ci - name: Check for typos - uses: crate-ci/typos@v1.39.2 + uses: crate-ci/typos@v1.40.0 with: config: .github/typos.toml validate-readme-files: @@ -93,7 +104,7 @@ jobs: needs: validate-style steps: - name: Check out code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go uses: actions/setup-go@v6 with: diff --git a/.github/workflows/deploy-registry.yaml b/.github/workflows/deploy-registry.yaml index c21ac9d6..cd90656a 100644 --- a/.github/workflows/deploy-registry.yaml +++ b/.github/workflows/deploy-registry.yaml @@ -28,7 +28,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Authenticate with Google Cloud uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 with: diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index c275a7af..5d58483f 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -14,7 +14,7 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8fa5da8c..898613e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/version-bump.yaml b/.github/workflows/version-bump.yaml index 5c3e434f..7c51d0ef 100644 --- a/.github/workflows/version-bump.yaml +++ b/.github/workflows/version-bump.yaml @@ -20,7 +20,7 @@ jobs: issues: write steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.icons/opencode.svg b/.icons/opencode.svg new file mode 100644 index 00000000..b79c7332 --- /dev/null +++ b/.icons/opencode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.icons/positron.svg b/.icons/positron.svg new file mode 100644 index 00000000..590372e4 --- /dev/null +++ b/.icons/positron.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 00000000..a2d4e444 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,22 @@ +# ShellCheck configuration for Coder Registry +# https://www.shellcheck.net/wiki/ + +# Set default shell dialect to bash (most scripts use bash) +shell=bash + +# Disable checks that conflict with Terraform templating syntax +# Many scripts use Terraform's templatefile() function with $${VAR} escape syntax +disable=SC2154 # Variable is referenced but not assigned (injected by Terraform) +disable=SC2034 # Variable appears unused (used via $${VAR} syntax) +disable=SC1083 # Literal braces (Terraform's $${VAR} escape syntax) +disable=SC2193 # Comparison arguments never equal (Terraform interpolation) +disable=SC2125 # Brace expansion/globs in assignments (Terraform syntax) +disable=SC2157 # Argument to -n/-z is always true/false (Terraform $${VAR} syntax) +disable=SC2066 # Loop will only run once (Terraform $${VAR} array syntax) + +# Disable checks that conflict with intentional patterns +disable=SC2076 # Quoted regex in =~ (intentional literal string match, not regex, for array membership checks) + +# Enable all optional checks for thorough analysis +enable=all + diff --git a/README.md b/README.md index 97f4677e..532b2d64 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" version = "1.0.19" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id } ``` diff --git a/bun.lock b/bun.lock index 16c21d09..7fcb771f 100644 --- a/bun.lock +++ b/bun.lock @@ -12,6 +12,7 @@ "prettier": "^3.6.2", "prettier-plugin-sh": "^0.18.0", "prettier-plugin-terraform-formatter": "^1.2.1", + "shellcheck": "^4.1.0", }, "peerDependencies": { "typescript": "^5.8.3", @@ -19,54 +20,296 @@ }, }, "packages": { + "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], + + "@felipecrs/decompress-tarxz": ["@felipecrs/decompress-tarxz@5.0.4", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.1.0", "file-type": "^20.5.0", "is-stream": "^2.0.1", "xz-decompress": "^0.2.3" } }, "sha512-a+nAnDsiUA84Sy/a+FKYJtjOjFvNtW8Jcbi3NwE8kJKPpYAxINFLYsC9mev9/wngiNEBA3jfHn0qNFwICeZNJw=="], + "@reteps/dockerfmt": ["@reteps/dockerfmt@0.3.6", "", {}, "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg=="], + "@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], "@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="], "@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="], + "@xhmikosr/decompress-tar": ["@xhmikosr/decompress-tar@8.1.0", "", { "dependencies": { "file-type": "^20.5.0", "is-stream": "^2.0.1", "tar-stream": "^3.1.7" } }, "sha512-m0q8x6lwxenh1CrsTby0Jrjq4vzW/QU1OLhTHMQLEdHpmjR1lgahGz++seZI0bXF3XcZw3U3xHfqZSz+JPP2Gg=="], + + "@xhmikosr/decompress-unzip": ["@xhmikosr/decompress-unzip@7.1.0", "", { "dependencies": { "file-type": "^20.5.0", "get-stream": "^6.0.1", "yauzl": "^3.1.2" } }, "sha512-oqTYAcObqTlg8owulxFTqiaJkfv2SHsxxxz9Wg4krJAHVzGWlZsU8tAB30R6ow+aHrfv4Kub6WQ8u04NWVPUpA=="], + "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="], + + "bare-events": ["bare-events@2.8.0", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-AOhh6Bg5QmFIXdViHbMc2tLDsBIRxdkIaIddPslJF9Z5De3APBScuqGP2uThXnIpqFrgoxMNC6km7uXNIMLHXA=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bl": ["bl@1.2.3", "", { "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww=="], + + "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "buffer-alloc": ["buffer-alloc@1.2.0", "", { "dependencies": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" } }, "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow=="], + + "buffer-alloc-unsafe": ["buffer-alloc-unsafe@1.1.0", "", {}, "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="], + + "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + + "buffer-fill": ["buffer-fill@1.0.0", "", {}, "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="], + "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decompress": ["decompress@4.2.1", "", { "dependencies": { "decompress-tar": "^4.0.0", "decompress-tarbz2": "^4.0.0", "decompress-targz": "^4.0.0", "decompress-unzip": "^4.0.1", "graceful-fs": "^4.1.10", "make-dir": "^1.0.0", "pify": "^2.3.0", "strip-dirs": "^2.0.0" } }, "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ=="], + + "decompress-tar": ["decompress-tar@4.1.1", "", { "dependencies": { "file-type": "^5.2.0", "is-stream": "^1.1.0", "tar-stream": "^1.5.2" } }, "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ=="], + + "decompress-tarbz2": ["decompress-tarbz2@4.1.1", "", { "dependencies": { "decompress-tar": "^4.1.0", "file-type": "^6.1.0", "is-stream": "^1.1.0", "seek-bzip": "^1.0.5", "unbzip2-stream": "^1.0.9" } }, "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A=="], + + "decompress-targz": ["decompress-targz@4.1.1", "", { "dependencies": { "decompress-tar": "^4.1.1", "file-type": "^5.2.0", "is-stream": "^1.1.0" } }, "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w=="], + + "decompress-unzip": ["decompress-unzip@4.0.1", "", { "dependencies": { "file-type": "^3.8.0", "get-stream": "^2.2.0", "pify": "^2.3.0", "yauzl": "^2.4.2" } }, "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw=="], + "dedent": ["dedent@1.6.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA=="], + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + + "envalid": ["envalid@8.1.0", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-OT6+qVhKVyCidaGoXflb2iK1tC8pd0OV2Q+v9n33wNhUJ+lus+rJobUj4vJaQBPxPZ0vYrPGuxdrenyCAIJcow=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], + "extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "file-type": ["file-type@20.5.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.6", "strtok3": "^10.2.0", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="], + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + "is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + "is-natural-number": ["is-natural-number@4.0.1", "", {}, "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + "js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], + "make-dir": ["make-dir@1.3.0", "", { "dependencies": { "pify": "^3.0.0" } }, "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ=="], + "marked": ["marked@16.2.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg=="], + "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + + "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], + + "pinkie": ["pinkie@2.0.4", "", {}, "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg=="], + + "pinkie-promise": ["pinkie-promise@2.0.1", "", { "dependencies": { "pinkie": "^2.0.0" } }, "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], "prettier-plugin-sh": ["prettier-plugin-sh@0.18.0", "", { "dependencies": { "@reteps/dockerfmt": "^0.3.6", "sh-syntax": "^0.5.8" }, "peerDependencies": { "prettier": "^3.6.0" } }, "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ=="], "prettier-plugin-terraform-formatter": ["prettier-plugin-terraform-formatter@1.2.1", "", { "peerDependencies": { "prettier": ">= 1.16.0" }, "optionalPeers": ["prettier"] }, "sha512-rdzV61Bs/Ecnn7uAS/vL5usTX8xUWM+nQejNLZxt3I1kJH5WSeLEmq7LYu1wCoEQF+y7Uv1xGvPRfl3lIe6+tA=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], + + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + "section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="], + "seek-bzip": ["seek-bzip@1.0.6", "", { "dependencies": { "commander": "^2.8.1" }, "bin": { "seek-bunzip": "bin/seek-bunzip", "seek-table": "bin/seek-bzip-table" } }, "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], + + "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + "sh-syntax": ["sh-syntax@0.5.8", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-JfVoxf4FxQI5qpsPbkHhZo+n6N9YMJobyl4oGEUBb/31oQYlgTjkXQD8PBiafS2UbWoxrTO0Z5PJUBXEPAG1Zw=="], + "shellcheck": ["shellcheck@4.1.0", "", { "dependencies": { "@felipecrs/decompress-tarxz": "5.0.4", "@xhmikosr/decompress-unzip": "7.1.0", "decompress": "4.2.1", "envalid": "8.1.0", "global-agent": "3.0.0" }, "bin": { "shellcheck": "bin/shellcheck.js" } }, "sha512-8143z6YGO4+Puwp9Ghn/g7+QxllSKlXaZSm3HXfvQXUfRXhM5P8TPORRHBBlyobl9BnniVne+d1Ff6RgNiccsQ=="], + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="], + "strip-dirs": ["strip-dirs@2.1.0", "", { "dependencies": { "is-natural-number": "^4.0.1" } }, "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g=="], + + "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], + + "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], + + "text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "to-buffer": ["to-buffer@1.2.2", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw=="], + + "token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + + "unbzip2-stream": ["unbzip2-stream@1.4.3", "", { "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" } }, "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg=="], + "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "xz-decompress": ["xz-decompress@0.2.3", "", {}, "sha512-O8v6HG8T0PrKBcpyWA13GkSYWFvncwzuzcLx5A7++l3HsE3atmoetXjIxrZ/JV/nbvSZ7WS4+3XvREZuVn+rEA=="], + + "yauzl": ["yauzl@3.2.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" } }, "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w=="], + + "decompress-tar/file-type": ["file-type@5.2.0", "", {}, "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ=="], + + "decompress-tar/is-stream": ["is-stream@1.1.0", "", {}, "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="], + + "decompress-tar/tar-stream": ["tar-stream@1.6.2", "", { "dependencies": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", "end-of-stream": "^1.0.0", "fs-constants": "^1.0.0", "readable-stream": "^2.3.0", "to-buffer": "^1.1.1", "xtend": "^4.0.0" } }, "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A=="], + + "decompress-tarbz2/file-type": ["file-type@6.2.0", "", {}, "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg=="], + + "decompress-tarbz2/is-stream": ["is-stream@1.1.0", "", {}, "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="], + + "decompress-targz/file-type": ["file-type@5.2.0", "", {}, "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ=="], + + "decompress-targz/is-stream": ["is-stream@1.1.0", "", {}, "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="], + + "decompress-unzip/file-type": ["file-type@3.9.0", "", {}, "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA=="], + + "decompress-unzip/get-stream": ["get-stream@2.3.1", "", { "dependencies": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" } }, "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA=="], + + "decompress-unzip/yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + + "make-dir/pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="], + + "roarr/sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + + "to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "to-buffer/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], } } diff --git a/cmd/readmevalidation/testSamples/sampleReadmeBody.md b/cmd/readmevalidation/testSamples/sampleReadmeBody.md index 9a37076b..b96662af 100644 --- a/cmd/readmevalidation/testSamples/sampleReadmeBody.md +++ b/cmd/readmevalidation/testSamples/sampleReadmeBody.md @@ -6,7 +6,7 @@ Run the [Goose](https://block.github.io/goose/) agent in your workspace to gener module "goose" { source = "registry.coder.com/coder/goose/coder" version = "1.0.31" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id folder = "/home/coder" install_goose = true goose_version = "v1.0.16" @@ -40,7 +40,7 @@ module "coder-login" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/coder-login/coder" version = "1.0.15" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id } variable "anthropic_api_key" { @@ -82,7 +82,7 @@ module "goose" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/goose/coder" version = "1.0.31" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id folder = "/home/coder" install_goose = true goose_version = "v1.0.16" @@ -110,7 +110,7 @@ Run Goose as a standalone app in your workspace. This will install Goose and run module "goose" { source = "registry.coder.com/coder/goose/coder" version = "1.0.31" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id folder = "/home/coder" install_goose = true goose_version = "v1.0.16" diff --git a/examples/modules/README.md b/examples/modules/README.md index da14e6a2..8eb06588 100644 --- a/examples/modules/README.md +++ b/examples/modules/README.md @@ -31,7 +31,7 @@ module "MODULE_NAME" { count = data.coder_workspace.me.start_count source = "registry.coder.com/NAMESPACE/MODULE_NAME/coder" version = "1.0.0" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id extensions = [ "dracula-theme.theme-dracula" ] @@ -49,7 +49,7 @@ module "MODULE_NAME" { count = data.coder_workspace.me.start_count source = "registry.coder.com/NAMESPACE/MODULE_NAME/coder" version = "1.0.0" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id extensions = ["dracula-theme.theme-dracula"] settings = { "workbench.colorTheme" = "Dracula" @@ -65,7 +65,7 @@ Run code-server in the background, don't fetch it from GitHub: module "MODULE_NAME" { source = "registry.coder.com/NAMESPACE/MODULE_NAME/coder" version = "1.0.0" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id offline = true } ``` diff --git a/package.json b/package.json index c1f73dd2..f1ca61f1 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "terraform-validate": "./scripts/terraform_validate.sh", "tftest": "./scripts/terraform_test_all.sh", "tstest": "./scripts/ts_test_auto.sh", + "shellcheck": "./scripts/shellcheck_validate.sh", "update-version": "./update-version.sh" }, "devDependencies": { @@ -16,7 +17,8 @@ "marked": "^16.2.0", "prettier": "^3.6.2", "prettier-plugin-sh": "^0.18.0", - "prettier-plugin-terraform-formatter": "^1.2.1" + "prettier-plugin-terraform-formatter": "^1.2.1", + "shellcheck": "^4.1.0" }, "peerDependencies": { "typescript": "^5.8.3" diff --git a/registry/AJ0070/modules/pgadmin/README.md b/registry/AJ0070/modules/pgadmin/README.md index 275861d1..dfc0552a 100644 --- a/registry/AJ0070/modules/pgadmin/README.md +++ b/registry/AJ0070/modules/pgadmin/README.md @@ -17,7 +17,7 @@ It can be served on a Coder subdomain for easy access, or on `localhost` if you module "pgadmin" { count = data.coder_workspace.me.start_count source = "registry.coder.com/AJ0070/pgadmin/coder" - version = "1.0.0" - agent_id = coder_agent.example.id + version = "1.0.1" + agent_id = coder_agent.main.id } ``` diff --git a/registry/BenraouaneSoufiane/modules/rustdesk/README.md b/registry/BenraouaneSoufiane/modules/rustdesk/README.md index ae7c2896..bddb4407 100644 --- a/registry/BenraouaneSoufiane/modules/rustdesk/README.md +++ b/registry/BenraouaneSoufiane/modules/rustdesk/README.md @@ -14,8 +14,8 @@ Launches RustDesk within your workspace with a virtual display to provide remote module "rustdesk" { count = data.coder_workspace.me.start_count source = "registry.coder.com/BenraouaneSoufiane/rustdesk/coder" - version = "1.0.0" - agent_id = coder_agent.example.id + version = "1.0.1" + agent_id = coder_agent.main.id } ``` @@ -41,8 +41,8 @@ module "rustdesk" { module "rustdesk" { count = data.coder_workspace.me.start_count source = "registry.coder.com/BenraouaneSoufiane/rustdesk/coder" - version = "1.0.0" - agent_id = coder_agent.example.id + version = "1.0.1" + agent_id = coder_agent.main.id rustdesk_password = "mycustompass" xvfb_resolution = "1920x1080x24" rustdesk_version = "1.4.1" diff --git a/registry/anomaly/modules/tmux/README.md b/registry/anomaly/modules/tmux/README.md index 2bba5234..d5f22ff5 100644 --- a/registry/anomaly/modules/tmux/README.md +++ b/registry/anomaly/modules/tmux/README.md @@ -15,7 +15,7 @@ up a default or custom tmux configuration with session save/restore capabilities ```tf module "tmux" { source = "registry.coder.com/anomaly/tmux/coder" - version = "1.0.1" + version = "1.0.3" agent_id = coder_agent.example.id } ``` @@ -39,7 +39,7 @@ module "tmux" { ```tf module "tmux" { source = "registry.coder.com/anomaly/tmux/coder" - version = "1.0.1" + version = "1.0.3" agent_id = coder_agent.example.id tmux_config = "" # Optional: custom tmux.conf content save_interval = 1 # Optional: save interval in minutes @@ -78,7 +78,7 @@ This module can provision multiple tmux sessions, each as a separate app in the ```tf module "tmux" { source = "registry.coder.com/anomaly/tmux/coder" - version = "1.0.1" + version = "1.0.3" agent_id = var.agent_id sessions = ["default", "dev", "anomaly"] tmux_config = <<-EOT diff --git a/registry/anomaly/modules/tmux/scripts/run.sh b/registry/anomaly/modules/tmux/scripts/run.sh index 5d6b7b56..b3c518c5 100755 --- a/registry/anomaly/modules/tmux/scripts/run.sh +++ b/registry/anomaly/modules/tmux/scripts/run.sh @@ -144,7 +144,7 @@ main() { printf "$${BOLD}✅ tmux setup complete! \n\n" printf "$${BOLD} Attempting to restore sessions\n" - tmux new-session -d \; source-file ~/.tmux.conf \; run-shell '~/.tmux/plugins/tmux-resurrect/scripts/restore.sh' + tmux new-session -d \; source-file ~/.tmux.conf \; run-shell "$HOME/.tmux/plugins/tmux-resurrect/scripts/restore.sh" printf "$${BOLD} Sessions restored: -> %s\n" "$(tmux ls)" } diff --git a/registry/coder-labs/modules/archive/README.md b/registry/coder-labs/modules/archive/README.md index 0c7e4ff7..08d08a6e 100644 --- a/registry/coder-labs/modules/archive/README.md +++ b/registry/coder-labs/modules/archive/README.md @@ -14,7 +14,7 @@ This module installs small, robust scripts in your workspace to create and extra module "archive" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/archive/coder" - version = "0.0.1" + version = "0.0.3" agent_id = coder_agent.example.id paths = ["./projects", "./code"] @@ -43,7 +43,7 @@ Basic example: module "archive" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/archive/coder" - version = "0.0.1" + version = "0.0.3" agent_id = coder_agent.example.id # Paths to include in the archive (files or directories). @@ -61,7 +61,7 @@ Customize compression and output: module "archive" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/archive/coder" - version = "0.0.1" + version = "0.0.3" agent_id = coder_agent.example.id directory = "/" @@ -78,7 +78,7 @@ Enable auto-archive on stop: module "archive" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/archive/coder" - version = "0.0.1" + version = "0.0.3" agent_id = coder_agent.example.id # Creates /tmp/coder-archive.tar.gz of the users home directory (defaults). @@ -92,7 +92,7 @@ Extract on start: module "archive" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/archive/coder" - version = "0.0.1" + version = "0.0.3" agent_id = coder_agent.example.id # Where to look for the archive file to extract: diff --git a/registry/coder-labs/modules/archive/run.sh b/registry/coder-labs/modules/archive/run.sh index ee4235c4..16be8bcf 100644 --- a/registry/coder-labs/modules/archive/run.sh +++ b/registry/coder-labs/modules/archive/run.sh @@ -6,8 +6,8 @@ EXTRACT_ON_START="${TF_EXTRACT_ON_START}" EXTRACT_WAIT_TIMEOUT="${TF_EXTRACT_WAIT_TIMEOUT}" # Set script defaults from Terraform. -DEFAULT_PATHS=(${TF_PATHS}) -DEFAULT_EXCLUDE_PATTERNS=(${TF_EXCLUDE_PATTERNS}) +IFS=' ' read -r -a DEFAULT_PATHS <<< "${TF_PATHS}" +IFS=' ' read -r -a DEFAULT_EXCLUDE_PATTERNS <<< "${TF_EXCLUDE_PATTERNS}" DEFAULT_COMPRESSION="${TF_COMPRESSION}" DEFAULT_ARCHIVE_PATH="${TF_ARCHIVE_PATH}" DEFAULT_DIRECTORY="${TF_DIRECTORY}" @@ -62,6 +62,7 @@ echo "Installed extract script to: $EXTRACT_WRAPPER_PATH" # 3) Optionally wait for and extract an archive on start. if [[ $EXTRACT_ON_START = true ]]; then + # shellcheck disable=SC1090 . "$LIB_PATH" archive_wait_and_extract "$EXTRACT_WAIT_TIMEOUT" quiet || { diff --git a/registry/coder-labs/modules/auggie/README.md b/registry/coder-labs/modules/auggie/README.md index 58651f37..fd1632fe 100644 --- a/registry/coder-labs/modules/auggie/README.md +++ b/registry/coder-labs/modules/auggie/README.md @@ -13,7 +13,7 @@ Run Auggie CLI in your workspace to access Augment's AI coding assistant with ad ```tf module "auggie" { source = "registry.coder.com/coder-labs/auggie/coder" - version = "0.2.1" + version = "0.2.2" agent_id = coder_agent.example.id folder = "/home/coder/project" } @@ -41,13 +41,13 @@ data "coder_parameter" "ai_prompt" { module "coder-login" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/coder-login/coder" - version = "1.0.31" + version = "0.2.2" agent_id = coder_agent.example.id } module "auggie" { source = "registry.coder.com/coder-labs/auggie/coder" - version = "0.2.1" + version = "0.2.2" agent_id = coder_agent.example.id folder = "/home/coder/project" @@ -57,7 +57,7 @@ module "auggie" { EOF # Required for tasks # Version - auggie_version = "0.3.0" + auggie_version = "0.2.2" # Task configuration ai_prompt = data.coder_parameter.ai_prompt.value @@ -103,7 +103,7 @@ EOF ```tf module "auggie" { source = "registry.coder.com/coder-labs/auggie/coder" - version = "0.2.1" + version = "0.2.2" agent_id = coder_agent.example.id folder = "/home/coder/project" diff --git a/registry/coder-labs/modules/auggie/scripts/install.sh b/registry/coder-labs/modules/auggie/scripts/install.sh index 1c38655c..b2f80ebe 100644 --- a/registry/coder-labs/modules/auggie/scripts/install.sh +++ b/registry/coder-labs/modules/auggie/scripts/install.sh @@ -1,7 +1,10 @@ #!/bin/bash -set -euo pipefail -source "$HOME"/.bashrc +if [ -f "$HOME/.bashrc" ]; then + source "$HOME"/.bashrc +fi + +set -euo pipefail BOLD='\033[0;1m' diff --git a/registry/coder-labs/modules/auggie/scripts/start.sh b/registry/coder-labs/modules/auggie/scripts/start.sh index 4660ea7c..4de4d829 100644 --- a/registry/coder-labs/modules/auggie/scripts/start.sh +++ b/registry/coder-labs/modules/auggie/scripts/start.sh @@ -1,7 +1,10 @@ #!/bin/bash -set -euo pipefail -source "$HOME"/.bashrc +if [ -f "$HOME/.bashrc" ]; then + source "$HOME"/.bashrc +fi + +set -euo pipefail command_exists() { command -v "$1" > /dev/null 2>&1 diff --git a/registry/coder-labs/modules/codex/README.md b/registry/coder-labs/modules/codex/README.md index 98062326..1d778240 100644 --- a/registry/coder-labs/modules/codex/README.md +++ b/registry/coder-labs/modules/codex/README.md @@ -13,7 +13,7 @@ Run Codex CLI in your workspace to access OpenAI's models through the Codex inte ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.0" + version = "3.1.1" agent_id = coder_agent.example.id openai_api_key = var.openai_api_key workdir = "/home/coder/project" @@ -33,7 +33,7 @@ module "codex" { module "codex" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.0" + version = "3.1.1" agent_id = coder_agent.example.id openai_api_key = "..." workdir = "/home/coder/project" @@ -55,13 +55,13 @@ data "coder_parameter" "ai_prompt" { module "coder-login" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/coder-login/coder" - version = "1.0.31" + version = "3.1.1" agent_id = coder_agent.example.id } module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.0" + version = "3.1.1" agent_id = coder_agent.example.id openai_api_key = "..." ai_prompt = data.coder_parameter.ai_prompt.value @@ -108,7 +108,7 @@ For custom Codex configuration, use `base_config_toml` and/or `additional_mcp_se ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.0" + version = "3.1.1" # ... other variables ... # Override default configuration diff --git a/registry/coder-labs/modules/codex/scripts/start.sh b/registry/coder-labs/modules/codex/scripts/start.sh index 663e80e5..38510fd0 100644 --- a/registry/coder-labs/modules/codex/scripts/start.sh +++ b/registry/coder-labs/modules/codex/scripts/start.sh @@ -38,7 +38,8 @@ find_session_for_directory() { return 1 fi - local session_id=$(grep "^$target_dir|" "$SESSION_TRACKING_FILE" | cut -d'|' -f2 | head -1) + local session_id + session_id=$(grep "^$target_dir|" "$SESSION_TRACKING_FILE" | cut -d'|' -f2 | head -1) if [ -n "$session_id" ]; then echo "$session_id" @@ -74,9 +75,12 @@ find_recent_session_file() { local latest_time=0 while IFS= read -r session_file; do - local file_time=$(stat -c %Y "$session_file" 2> /dev/null || stat -f %m "$session_file" 2> /dev/null || echo "0") - local first_line=$(head -n 1 "$session_file" 2> /dev/null) - local session_cwd=$(echo "$first_line" | grep -o '"cwd":"[^"]*"' | cut -d'"' -f4) + local file_time + file_time=$(stat -c %Y "$session_file" 2> /dev/null || stat -f %m "$session_file" 2> /dev/null || echo "0") + local first_line + first_line=$(head -n 1 "$session_file" 2> /dev/null) + local session_cwd + session_cwd=$(echo "$first_line" | grep -o '"cwd":"[^"]*"' | cut -d'"' -f4) if [ "$session_cwd" = "$target_dir" ] && [ "$file_time" -gt "$latest_time" ]; then latest_file="$session_file" @@ -85,8 +89,10 @@ find_recent_session_file() { done < <(find "$sessions_dir" -type f -name "*.jsonl" 2> /dev/null) if [ -n "$latest_file" ]; then - local first_line=$(head -n 1 "$latest_file") - local session_id=$(echo "$first_line" | grep -o '"id":"[^"]*"' | cut -d'"' -f4) + local first_line + first_line=$(head -n 1 "$latest_file") + local session_id + session_id=$(echo "$first_line" | grep -o '"id":"[^"]*"' | cut -d'"' -f4) if [ -n "$session_id" ]; then echo "$session_id" return 0 @@ -102,7 +108,8 @@ wait_for_session_file() { local attempt=0 while [ $attempt -lt $max_attempts ]; do - local session_id=$(find_recent_session_file "$target_dir" 2> /dev/null || echo "") + local session_id + session_id=$(find_recent_session_file "$target_dir" 2> /dev/null || echo "") if [ -n "$session_id" ]; then echo "$session_id" return 0 diff --git a/registry/coder-labs/modules/copilot/README.md b/registry/coder-labs/modules/copilot/README.md index e0b520e0..4ef2f6bc 100644 --- a/registry/coder-labs/modules/copilot/README.md +++ b/registry/coder-labs/modules/copilot/README.md @@ -13,7 +13,7 @@ Run [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-c ```tf module "copilot" { source = "registry.coder.com/coder-labs/copilot/coder" - version = "0.2.2" + version = "0.2.3" agent_id = coder_agent.example.id workdir = "/home/coder/projects" } @@ -51,7 +51,7 @@ data "coder_parameter" "ai_prompt" { module "copilot" { source = "registry.coder.com/coder-labs/copilot/coder" - version = "0.2.2" + version = "0.2.3" agent_id = coder_agent.example.id workdir = "/home/coder/projects" @@ -71,12 +71,12 @@ Customize tool permissions, MCP servers, and Copilot settings: ```tf module "copilot" { source = "registry.coder.com/coder-labs/copilot/coder" - version = "0.2.2" + version = "0.2.3" agent_id = coder_agent.example.id workdir = "/home/coder/projects" # Version pinning (defaults to "latest", use specific version if desired) - copilot_version = "0.0.334" + copilot_version = "0.2.3" # Tool permissions allow_tools = ["shell(git)", "shell(npm)", "write"] @@ -142,7 +142,7 @@ variable "github_token" { module "copilot" { source = "registry.coder.com/coder-labs/copilot/coder" - version = "0.2.2" + version = "0.2.3" agent_id = coder_agent.example.id workdir = "/home/coder/projects" github_token = var.github_token @@ -156,7 +156,7 @@ Run Copilot as a command-line tool without task reporting or web interface. This ```tf module "copilot" { source = "registry.coder.com/coder-labs/copilot/coder" - version = "0.2.2" + version = "0.2.3" agent_id = coder_agent.example.id workdir = "/home/coder" report_tasks = false diff --git a/registry/coder-labs/modules/copilot/scripts/install.sh b/registry/coder-labs/modules/copilot/scripts/install.sh index 0aabd761..44c480e3 100644 --- a/registry/coder-labs/modules/copilot/scripts/install.sh +++ b/registry/coder-labs/modules/copilot/scripts/install.sh @@ -1,7 +1,10 @@ #!/bin/bash -set -euo pipefail -source "$HOME"/.bashrc +if [ -f "$HOME/.bashrc" ]; then + source "$HOME"/.bashrc +fi + +set -euo pipefail command_exists() { command -v "$1" > /dev/null 2>&1 diff --git a/registry/coder-labs/modules/copilot/scripts/start.sh b/registry/coder-labs/modules/copilot/scripts/start.sh index 2653d593..98341e9b 100644 --- a/registry/coder-labs/modules/copilot/scripts/start.sh +++ b/registry/coder-labs/modules/copilot/scripts/start.sh @@ -1,7 +1,11 @@ #!/bin/bash + +if [ -f "$HOME/.bashrc" ]; then + source "$HOME"/.bashrc +fi + set -euo pipefail -source "$HOME"/.bashrc export PATH="$HOME/.local/bin:$PATH" command_exists() { diff --git a/registry/coder-labs/modules/cursor-cli/README.md b/registry/coder-labs/modules/cursor-cli/README.md index 24514eaa..6aa5ada3 100644 --- a/registry/coder-labs/modules/cursor-cli/README.md +++ b/registry/coder-labs/modules/cursor-cli/README.md @@ -13,8 +13,8 @@ Run the Cursor Agent CLI in your workspace for interactive coding assistance and ```tf module "cursor_cli" { source = "registry.coder.com/coder-labs/cursor-cli/coder" - version = "0.2.1" - agent_id = coder_agent.example.id + version = "0.2.2" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -42,8 +42,8 @@ module "coder-login" { module "cursor_cli" { source = "registry.coder.com/coder-labs/cursor-cli/coder" - version = "0.2.1" - agent_id = coder_agent.example.id + version = "0.2.2" + agent_id = coder_agent.main.id folder = "/home/coder/project" # Optional @@ -60,6 +60,7 @@ module "cursor_cli" { command = "npx" args = ["-y", "@playwright/mcp@latest", "--headless", "--isolated", "--no-sandbox"] } + desktop-commander = { command = "npx" args = ["-y", "@wonderwhy-er/desktop-commander"] diff --git a/registry/coder-labs/modules/gemini/README.md b/registry/coder-labs/modules/gemini/README.md index 3e8ed5ee..8e44c89b 100644 --- a/registry/coder-labs/modules/gemini/README.md +++ b/registry/coder-labs/modules/gemini/README.md @@ -13,8 +13,8 @@ Run [Gemini CLI](https://github.com/google-gemini/gemini-cli) in your workspace ```tf module "gemini" { source = "registry.coder.com/coder-labs/gemini/coder" - version = "2.1.1" - agent_id = coder_agent.example.id + version = "2.1.2" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -46,8 +46,8 @@ variable "gemini_api_key" { module "gemini" { source = "registry.coder.com/coder-labs/gemini/coder" - version = "2.1.1" - agent_id = coder_agent.example.id + version = "2.1.2" + agent_id = coder_agent.main.id gemini_api_key = var.gemini_api_key folder = "/home/coder/project" } @@ -80,7 +80,7 @@ module "coder-login" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/coder-login/coder" version = "~> 1.0" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id } data "coder_parameter" "ai_prompt" { @@ -94,8 +94,8 @@ data "coder_parameter" "ai_prompt" { module "gemini" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/gemini/coder" - version = "2.1.1" - agent_id = coder_agent.example.id + version = "2.1.2" + agent_id = coder_agent.main.id gemini_api_key = var.gemini_api_key gemini_model = "gemini-2.5-flash" folder = "/home/coder/project" @@ -118,8 +118,8 @@ For enterprise users who prefer Google's Vertex AI platform: ```tf module "gemini" { source = "registry.coder.com/coder-labs/gemini/coder" - version = "2.1.1" - agent_id = coder_agent.example.id + version = "2.1.2" + agent_id = coder_agent.main.id gemini_api_key = var.gemini_api_key folder = "/home/coder/project" use_vertexai = true diff --git a/registry/coder-labs/modules/nextflow/README.md b/registry/coder-labs/modules/nextflow/README.md index 7a62a3ab..7e6911dc 100644 --- a/registry/coder-labs/modules/nextflow/README.md +++ b/registry/coder-labs/modules/nextflow/README.md @@ -16,7 +16,7 @@ A module that adds Nextflow to your Coder template. module "nextflow" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/nextflow/coder" - version = "0.9.0" - agent_id = coder_agent.example.id + version = "0.9.1" + agent_id = coder_agent.main.id } ``` diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md new file mode 100644 index 00000000..711ad522 --- /dev/null +++ b/registry/coder-labs/modules/opencode/README.md @@ -0,0 +1,109 @@ +--- +display_name: OpenCode +icon: ../../../../.icons/opencode.svg +description: Run OpenCode AI coding assistant for AI-powered terminal assistance +verified: false +tags: [agent, opencode, ai, tasks] +--- + +# OpenCode + +Run [OpenCode](https://opencode.ai) AI coding assistant in your workspace for intelligent code generation, analysis, and development assistance. This module integrates with [AgentAPI](https://github.com/coder/agentapi) for seamless task reporting in the Coder UI. + +```tf +module "opencode" { + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.1" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" +} +``` + +## Prerequisites + +- **Authentication credentials** - OpenCode auth.json file is required for non-interactive authentication, you can find this file on your system: `$HOME/.local/share/opencode/auth.json` + +## Examples + +### Basic Usage with Tasks + +```tf +resource "coder_ai_task" "task" { + app_id = module.opencode.task_app_id +} + +module "opencode" { + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.1" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + + ai_prompt = coder_ai_task.task.prompt + + auth_json = <<-EOT +{ + "google": { + "type": "api", + "key": "gem-xxx-xxxx" + }, + "anthropic": { + "type": "api", + "key": "sk-ant-api03-xxx-xxxxxxx" + } + +} +EOT + + config_json = jsonencode({ + "$schema" = "https://opencode.ai/config.json" + mcp = { + filesystem = { + command = ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/home/coder/projects"] + enabled = true + type = "local" + environment = { + SOME_VARIABLE_X = "value" + } + } + playwright = { + command = ["npx", "-y", "@playwright/mcp@latest", "--headless", "--isolated"] + enabled = true + type = "local" + } + } + model = "anthropic/claude-sonnet-4-20250514" + }) + + pre_install_script = <<-EOT + #!/bin/bash + curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - + sudo apt-get install -y nodejs + EOT +} +``` + +### Standalone CLI Mode + +Run OpenCode as a command-line tool without web interface or task reporting: + +```tf +module "opencode" { + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.1" + agent_id = coder_agent.main.id + workdir = "/home/coder" + report_tasks = false + cli_app = true +} +``` + +## Troubleshooting + +If you encounter any issues, check the log files in the `~/.opencode-module` directory within your workspace for detailed information. + +## References + +- [Opencode JSON Config](https://opencode.ai/docs/config/) +- [OpenCode Documentation](https://opencode.ai/docs) +- [AgentAPI Documentation](https://github.com/coder/agentapi) +- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents) diff --git a/registry/coder-labs/modules/opencode/main.test.ts b/registry/coder-labs/modules/opencode/main.test.ts new file mode 100644 index 00000000..dec42a59 --- /dev/null +++ b/registry/coder-labs/modules/opencode/main.test.ts @@ -0,0 +1,362 @@ +import { + test, + afterEach, + describe, + setDefaultTimeout, + beforeAll, + expect, +} from "bun:test"; +import { execContainer, readFileContainer, runTerraformInit } from "~test"; +import { + loadTestFile, + writeExecutable, + setup as setupUtil, + execModuleScript, + expectAgentAPIStarted, +} from "../../../coder/modules/agentapi/test-util"; +import dedent from "dedent"; + +let cleanupFunctions: (() => Promise)[] = []; +const registerCleanup = (cleanup: () => Promise) => { + cleanupFunctions.push(cleanup); +}; +afterEach(async () => { + const cleanupFnsCopy = cleanupFunctions.slice().reverse(); + cleanupFunctions = []; + for (const cleanup of cleanupFnsCopy) { + try { + await cleanup(); + } catch (error) { + console.error("Error during cleanup:", error); + } + } +}); + +interface SetupProps { + skipAgentAPIMock?: boolean; + skipOpencodeMock?: boolean; + moduleVariables?: Record; + agentapiMockScript?: string; +} + +const setup = async (props?: SetupProps): Promise<{ id: string }> => { + const projectDir = "/home/coder/project"; + const { id } = await setupUtil({ + moduleDir: import.meta.dir, + moduleVariables: { + install_opencode: props?.skipOpencodeMock ? "true" : "false", + install_agentapi: props?.skipAgentAPIMock ? "true" : "false", + workdir: projectDir, + ...props?.moduleVariables, + }, + registerCleanup, + projectDir, + skipAgentAPIMock: props?.skipAgentAPIMock, + agentapiMockScript: props?.agentapiMockScript, + }); + if (!props?.skipOpencodeMock) { + await writeExecutable({ + containerId: id, + filePath: "/usr/bin/opencode", + content: await loadTestFile(import.meta.dir, "opencode-mock.sh"), + }); + } + return { id }; +}; + +setDefaultTimeout(60 * 1000); + +describe("opencode", async () => { + beforeAll(async () => { + await runTerraformInit(import.meta.dir); + }); + + test("happy-path", async () => { + const { id } = await setup(); + await execModuleScript(id); + await expectAgentAPIStarted(id); + }); + + test("install-opencode-version", async () => { + const version_to_install = "0.1.0"; + const { id } = await setup({ + skipOpencodeMock: true, + moduleVariables: { + install_opencode: "true", + opencode_version: version_to_install, + pre_install_script: dedent` + #!/usr/bin/env bash + set -euo pipefail + + # Mock the opencode install for testing + mkdir -p /home/coder/.opencode/bin + echo '#!/bin/bash\necho "opencode mock version ${version_to_install}"' > /home/coder/.opencode/bin/opencode + chmod +x /home/coder/.opencode/bin/opencode + `, + }, + }); + await execModuleScript(id); + const resp = await execContainer(id, [ + "bash", + "-c", + `cat /home/coder/.opencode-module/install.log`, + ]); + expect(resp.stdout).toContain(version_to_install); + }); + + test("check-latest-opencode-version-works", async () => { + const { id } = await setup({ + skipOpencodeMock: true, + skipAgentAPIMock: true, + moduleVariables: { + install_opencode: "true", + pre_install_script: dedent` + #!/usr/bin/env bash + set -euo pipefail + + # Mock the opencode install for testing + mkdir -p /home/coder/.opencode/bin + echo '#!/bin/bash\necho "opencode mock latest version"' > /home/coder/.opencode/bin/opencode + chmod +x /home/coder/.opencode/bin/opencode + `, + }, + }); + await execModuleScript(id); + await expectAgentAPIStarted(id); + }); + + test("opencode-auth-json", async () => { + const authJson = JSON.stringify({ + token: "test-auth-token-123", + user: "test-user", + }); + const { id } = await setup({ + moduleVariables: { + auth_json: authJson, + }, + }); + await execModuleScript(id); + + const authFile = await readFileContainer( + id, + "/home/coder/.local/share/opencode/auth.json", + ); + + expect(authFile).toContain("test-auth-token-123"); + expect(authFile).toContain("test-user"); + }); + + test("opencode-config-json", async () => { + const configJson = JSON.stringify({ + $schema: "https://opencode.ai/config.json", + mcp: { + test: { + command: ["test-cmd"], + type: "local", + }, + }, + model: "anthropic/claude-sonnet-4-20250514", + }); + const { id } = await setup({ + moduleVariables: { + config_json: configJson, + }, + }); + await execModuleScript(id); + + const configFile = await readFileContainer( + id, + "/home/coder/.config/opencode/opencode.json", + ); + expect(configFile).toContain("test-cmd"); + expect(configFile).toContain("anthropic/claude-sonnet-4-20250514"); + }); + + test("opencode-ai-prompt", async () => { + const prompt = "This is a task prompt for OpenCode."; + const { id } = await setup({ + moduleVariables: { + ai_prompt: prompt, + }, + }); + await execModuleScript(id); + + const resp = await execContainer(id, [ + "bash", + "-c", + `cat /home/coder/.opencode-module/agentapi-start.log`, + ]); + expect(resp.stdout).toContain(prompt); + }); + + test("opencode-continue-flag", async () => { + const { id } = await setup({ + moduleVariables: { + continue: "true", + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain("--continue"); + }); + + test("opencode-continue-with-session-id", async () => { + const sessionId = "session-123"; + const { id } = await setup({ + moduleVariables: { + continue: "true", + session_id: sessionId, + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain("--continue"); + expect(startLog.stdout).toContain(`--session ${sessionId}`); + }); + + test("opencode-session-id", async () => { + const sessionId = "session-123"; + const { id } = await setup({ + moduleVariables: { + session_id: sessionId, + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain(`--session ${sessionId}`); + }); + + test("opencode-report-tasks-enabled", async () => { + const { id } = await setup({ + moduleVariables: { + report_tasks: "true", + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain( + "report your progress using coder_report_task", + ); + }); + + test("opencode-report-tasks-disabled", async () => { + const { id } = await setup({ + moduleVariables: { + report_tasks: "false", + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).not.toContain( + "report your progress using coder_report_task", + ); + }); + + test("cli-app-creation", async () => { + const { id } = await setup({ + moduleVariables: { + cli_app: "true", + cli_app_display_name: "OpenCode Terminal", + }, + }); + await execModuleScript(id); + // CLI app creation is handled by the agentapi module + // We just verify the setup completed successfully + await expectAgentAPIStarted(id); + }); + + test("pre-post-install-scripts", async () => { + const { id } = await setup({ + moduleVariables: { + pre_install_script: "#!/bin/bash\necho 'opencode-pre-install-script'", + post_install_script: "#!/bin/bash\necho 'opencode-post-install-script'", + }, + }); + await execModuleScript(id); + + const preInstallLog = await readFileContainer( + id, + "/home/coder/.opencode-module/pre_install.log", + ); + expect(preInstallLog).toContain("opencode-pre-install-script"); + + const postInstallLog = await readFileContainer( + id, + "/home/coder/.opencode-module/post_install.log", + ); + expect(postInstallLog).toContain("opencode-post-install-script"); + }); + + test("workdir-variable", async () => { + const workdir = "/home/coder/opencode-test-folder"; + const { id } = await setup({ + skipOpencodeMock: false, + moduleVariables: { + workdir, + }, + }); + await execModuleScript(id); + + const resp = await readFileContainer( + id, + "/home/coder/.opencode-module/agentapi-start.log", + ); + expect(resp).toContain(workdir); + }); + + test("subdomain-enabled", async () => { + const { id } = await setup({ + moduleVariables: { + subdomain: "true", + }, + }); + await execModuleScript(id); + // Subdomain configuration is handled by the agentapi module + // We just verify the setup completed successfully + await expectAgentAPIStarted(id); + }); + + test("custom-display-names", async () => { + const { id } = await setup({ + moduleVariables: { + web_app_display_name: "Custom OpenCode Web", + cli_app_display_name: "Custom OpenCode CLI", + cli_app: "true", + }, + }); + await execModuleScript(id); + // Display names are handled by the agentapi module + // We just verify the setup completed successfully + await expectAgentAPIStarted(id); + }); +}); diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf new file mode 100644 index 00000000..df7f946f --- /dev/null +++ b/registry/coder-labs/modules/opencode/main.tf @@ -0,0 +1,203 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.12" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} + +variable "group" { + type = string + description = "The name of a group that this app belongs to." + default = null +} + +variable "icon" { + type = string + description = "The icon to use for the app." + default = "/icon/opencode.svg" +} + +variable "workdir" { + type = string + description = "The folder to run OpenCode in." +} + +variable "report_tasks" { + type = bool + description = "Whether to enable task reporting to Coder UI via AgentAPI" + default = true +} + +variable "cli_app" { + type = bool + description = "Whether to create a CLI app for OpenCode" + default = false +} + +variable "web_app_display_name" { + type = string + description = "Display name for the web app" + default = "OpenCode" +} + +variable "cli_app_display_name" { + type = string + description = "Display name for the CLI app" + default = "OpenCode CLI" +} + +variable "pre_install_script" { + type = string + description = "Custom script to run before installing OpenCode." + default = null +} + +variable "post_install_script" { + type = string + description = "Custom script to run after installing OpenCode." + default = null +} + +variable "install_agentapi" { + type = bool + description = "Whether to install AgentAPI." + default = true +} + +variable "agentapi_version" { + type = string + description = "The version of AgentAPI to install." + default = "v0.11.2" +} + +variable "ai_prompt" { + type = string + description = "Initial task prompt for OpenCode." + default = "" +} + +variable "subdomain" { + type = bool + description = "Whether to use a subdomain for AgentAPI." + default = false +} + +variable "install_opencode" { + type = bool + description = "Whether to install OpenCode." + default = true +} + +variable "opencode_version" { + type = string + description = "The version of OpenCode to install." + default = "latest" +} + +variable "continue" { + type = bool + description = "continue the last session. Uses the --continue flag" + default = false +} + +variable "session_id" { + type = string + description = "Session id to continue. Passed via --session" + default = "" +} + +variable "auth_json" { + type = string + description = "Your auth.json from $HOME/.local/share/opencode/auth.json, Required for non-interactive authentication" + default = "" +} + +variable "config_json" { + type = string + description = "OpenCode JSON config. https://opencode.ai/docs/config/" + default = "" +} + +locals { + workdir = trimsuffix(var.workdir, "/") + app_slug = "opencode" + install_script = file("${path.module}/scripts/install.sh") + start_script = file("${path.module}/scripts/start.sh") + module_dir_name = ".opencode-module" +} + +module "agentapi" { + source = "registry.coder.com/coder/agentapi/coder" + version = "2.0.0" + + agent_id = var.agent_id + web_app_slug = local.app_slug + web_app_order = var.order + web_app_group = var.group + web_app_icon = var.icon + web_app_display_name = var.web_app_display_name + cli_app = var.cli_app + cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null + cli_app_display_name = var.cli_app ? var.cli_app_display_name : null + agentapi_subdomain = var.subdomain + folder = local.workdir + module_dir_name = local.module_dir_name + install_agentapi = var.install_agentapi + agentapi_version = var.agentapi_version + pre_install_script = var.pre_install_script + post_install_script = var.post_install_script + start_script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh + chmod +x /tmp/start.sh + + ARG_WORKDIR='${local.workdir}' \ + ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \ + ARG_SESSION_ID='${var.session_id}' \ + ARG_REPORT_TASKS='${var.report_tasks}' \ + ARG_CONTINUE='${var.continue}' \ + /tmp/start.sh + EOT + + install_script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + + echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh + chmod +x /tmp/install.sh + ARG_OPENCODE_VERSION='${var.opencode_version}' \ + ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \ + ARG_INSTALL_OPENCODE='${var.install_opencode}' \ + ARG_REPORT_TASKS='${var.report_tasks}' \ + ARG_WORKDIR='${local.workdir}' \ + ARG_AUTH_JSON='${var.auth_json != null ? base64encode(replace(var.auth_json, "'", "'\\''")) : ""}' \ + ARG_OPENCODE_CONFIG='${var.config_json != null ? base64encode(replace(var.config_json, "'", "'\\''")) : ""}' \ + /tmp/install.sh + EOT +} + +output "task_app_id" { + value = module.agentapi.task_app_id +} diff --git a/registry/coder-labs/modules/opencode/main.tftest.hcl b/registry/coder-labs/modules/opencode/main.tftest.hcl new file mode 100644 index 00000000..e8c7954b --- /dev/null +++ b/registry/coder-labs/modules/opencode/main.tftest.hcl @@ -0,0 +1,374 @@ +run "defaults_are_correct" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + } + + assert { + condition = var.install_opencode == true + error_message = "OpenCode installation should be enabled by default" + } + + assert { + condition = var.install_agentapi == true + error_message = "AgentAPI installation should be enabled by default" + } + + assert { + condition = var.agentapi_version == "v0.11.2" + error_message = "Default AgentAPI version should be 'v0.11.2'" + } + + assert { + condition = var.opencode_version == "latest" + error_message = "Default OpenCode version should be 'latest'" + } + + assert { + condition = var.report_tasks == true + error_message = "Task reporting should be enabled by default" + } + + assert { + condition = var.cli_app == false + error_message = "CLI app should be disabled by default" + } + + assert { + condition = var.subdomain == false + error_message = "Subdomain should be disabled by default" + } + + assert { + condition = var.web_app_display_name == "OpenCode" + error_message = "Default web app display name should be 'OpenCode'" + } + + assert { + condition = var.cli_app_display_name == "OpenCode CLI" + error_message = "Default CLI app display name should be 'OpenCode CLI'" + } + + assert { + condition = local.app_slug == "opencode" + error_message = "App slug should be 'opencode'" + } + + assert { + condition = local.module_dir_name == ".opencode-module" + error_message = "Module dir name should be '.opencode-module'" + } + + assert { + condition = local.workdir == "/home/coder/project" + error_message = "Workdir should be trimmed of trailing slash" + } + + assert { + condition = var.continue == false + error_message = "Continue flag should be disabled by default" + } +} + +run "workdir_trailing_slash_trimmed" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project/" + } + + assert { + condition = local.workdir == "/home/coder/project" + error_message = "Workdir should be trimmed of trailing slash" + } +} + +run "opencode_version_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + opencode_version = "v1.0.0" + } + + assert { + condition = var.opencode_version == "v1.0.0" + error_message = "OpenCode version should be set correctly" + } +} + +run "agentapi_version_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + agentapi_version = "v0.9.0" + } + + assert { + condition = var.agentapi_version == "v0.9.0" + error_message = "AgentAPI version should be set correctly" + } +} + +run "cli_app_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + cli_app = true + cli_app_display_name = "Custom OpenCode CLI" + } + + assert { + condition = var.cli_app == true + error_message = "CLI app should be enabled when specified" + } + + assert { + condition = var.cli_app_display_name == "Custom OpenCode CLI" + error_message = "Custom CLI app display name should be set" + } +} + +run "web_app_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + web_app_display_name = "Custom OpenCode Web" + order = 5 + group = "AI Tools" + icon = "/custom/icon.svg" + } + + assert { + condition = var.web_app_display_name == "Custom OpenCode Web" + error_message = "Custom web app display name should be set" + } + + assert { + condition = var.order == 5 + error_message = "Custom order should be set" + } + + assert { + condition = var.group == "AI Tools" + error_message = "Custom group should be set" + } + + assert { + condition = var.icon == "/custom/icon.svg" + error_message = "Custom icon should be set" + } +} + +run "ai_configuration_variables" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + ai_prompt = "This is a test prompt" + session_id = "session-123" + continue = true + } + + assert { + condition = var.ai_prompt == "This is a test prompt" + error_message = "AI prompt should be set correctly" + } + + assert { + condition = var.session_id == "session-123" + error_message = "Session ID should be set correctly" + } + + assert { + condition = var.continue == true + error_message = "Continue flag should be set correctly" + } +} + +run "auth_json_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + auth_json = "{\"token\": \"test-token\", \"user\": \"test-user\"}" + } + + assert { + condition = var.auth_json != "" + error_message = "Auth JSON should be set" + } + + assert { + condition = can(jsondecode(var.auth_json)) + error_message = "Auth JSON should be valid JSON" + } +} + +run "config_json_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + config_json = "{\"$schema\": \"https://opencode.ai/config.json\", \"mcp\": {\"test\": {\"command\": [\"test-cmd\"], \"type\": \"local\"}}, \"model\": \"anthropic/claude-sonnet-4-20250514\"}" + } + + assert { + condition = var.config_json != "" + error_message = "OpenCode JSON configuration should be set" + } + + assert { + condition = can(jsondecode(var.config_json)) + error_message = "OpenCode JSON configuration should be valid JSON" + } +} + +run "task_reporting_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + report_tasks = false + } + + assert { + condition = var.report_tasks == false + error_message = "Task reporting should be disabled when specified" + } +} + +run "subdomain_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + subdomain = true + } + + assert { + condition = var.subdomain == true + error_message = "Subdomain should be enabled when specified" + } +} + +run "install_flags_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + install_opencode = false + install_agentapi = false + } + + assert { + condition = var.install_opencode == false + error_message = "OpenCode installation should be disabled when specified" + } + + assert { + condition = var.install_agentapi == false + error_message = "AgentAPI installation should be disabled when specified" + } +} + +run "custom_scripts_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + pre_install_script = "#!/bin/bash\necho 'pre-install'" + post_install_script = "#!/bin/bash\necho 'post-install'" + } + + assert { + condition = var.pre_install_script != null + error_message = "Pre-install script should be set" + } + + assert { + condition = var.post_install_script != null + error_message = "Post-install script should be set" + } + + assert { + condition = can(regex("pre-install", var.pre_install_script)) + error_message = "Pre-install script should contain expected content" + } + + assert { + condition = can(regex("post-install", var.post_install_script)) + error_message = "Post-install script should contain expected content" + } +} + +run "empty_variables_handled_correctly" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + ai_prompt = "" + session_id = "" + auth_json = "" + config_json = "" + continue = false + } + + assert { + condition = var.ai_prompt == "" + error_message = "Empty AI prompt should be handled correctly" + } + + assert { + condition = var.session_id == "" + error_message = "Empty session ID should be handled correctly" + } + + assert { + condition = var.auth_json == "" + error_message = "Empty auth JSON should be handled correctly" + } + + assert { + condition = var.config_json == "" + error_message = "Empty config JSON should be handled correctly" + } + + assert { + condition = var.continue == false + error_message = "Continue flag default should be handled correctly" + } +} + +run "continue_flag_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + continue = true + } + + assert { + condition = var.continue == true + error_message = "Continue flag should be enabled when specified" + } +} \ No newline at end of file diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh new file mode 100755 index 00000000..6d553108 --- /dev/null +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -0,0 +1,131 @@ +#!/bin/bash +set -euo pipefail + +command_exists() { + command -v "$1" > /dev/null 2>&1 +} + +ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} +ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} +ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-} +ARG_OPENCODE_VERSION=${ARG_OPENCODE_VERSION:-latest} +ARG_INSTALL_OPENCODE=${ARG_INSTALL_OPENCODE:-true} +ARG_AUTH_JSON=$(echo -n "$ARG_AUTH_JSON" | base64 -d 2> /dev/null || echo "") +ARG_OPENCODE_CONFIG=$(echo -n "$ARG_OPENCODE_CONFIG" | base64 -d 2> /dev/null || echo "") + +# Print all received environment variables +printf "=== INSTALL CONFIG ===\n" +printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" +printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" +printf "ARG_MCP_APP_STATUS_SLUG: %s\n" "$ARG_MCP_APP_STATUS_SLUG" +printf "ARG_OPENCODE_VERSION: %s\n" "$ARG_OPENCODE_VERSION" +printf "ARG_INSTALL_OPENCODE: %s\n" "$ARG_INSTALL_OPENCODE" +if [ -n "$ARG_AUTH_JSON" ]; then + printf "ARG_AUTH_JSON: [AUTH DATA RECEIVED]\n" +else + printf "ARG_AUTH_JSON: [NOT PROVIDED]\n" +fi +if [ -n "$ARG_OPENCODE_CONFIG" ]; then + printf "ARG_OPENCODE_CONFIG: [RECEIVED]\n" +else + printf "ARG_OPENCODE_CONFIG: [NOT PROVIDED]\n" +fi +printf "==================================\n" + +install_opencode() { + if [ "$ARG_INSTALL_OPENCODE" = "true" ]; then + if ! command_exists opencode; then + echo "Installing OpenCode (version: ${ARG_OPENCODE_VERSION})..." + if [ "$ARG_OPENCODE_VERSION" = "latest" ]; then + curl -fsSL https://opencode.ai/install | bash + else + VERSION=$ARG_OPENCODE_VERSION curl -fsSL https://opencode.ai/install | bash + fi + export PATH=/home/coder/.opencode/bin:$PATH + printf "Opencode location: %s\n" "$(which opencode)" + if ! command_exists opencode; then + echo "ERROR: Failed to install OpenCode" + exit 1 + fi + echo "OpenCode installed successfully" + else + echo "OpenCode already installed" + fi + else + echo "OpenCode installation skipped (ARG_INSTALL_OPENCODE=false)" + fi +} + +setup_opencode_config() { + local opencode_config_file="$HOME/.config/opencode/opencode.json" + local auth_json_file="$HOME/.local/share/opencode/auth.json" + + mkdir -p "$(dirname "$auth_json_file")" + mkdir -p "$(dirname "$opencode_config_file")" + + setup_opencode_auth "$auth_json_file" + + if [ -n "$ARG_OPENCODE_CONFIG" ]; then + echo "Writing to the config file" + echo "$ARG_OPENCODE_CONFIG" > "$opencode_config_file" + fi + + if [ "$ARG_REPORT_TASKS" = "true" ]; then + setup_coder_mcp_server "$opencode_config_file" + fi + + echo "MCP configuration completed: $opencode_config_file" +} + +setup_opencode_auth() { + local auth_json_file="$1" + + if [ -n "$ARG_AUTH_JSON" ]; then + echo "$ARG_AUTH_JSON" > "$auth_json_file" + printf "added auth json to %s" "$auth_json_file" + else + printf "auth json not provided" + fi +} + +setup_coder_mcp_server() { + local opencode_config_file="$1" + + # Set environment variables based on task reporting setting + echo "Configuring OpenCode task reporting" + export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + echo "Coder integration configured for task reporting" + + # Add coder MCP server configuration to the JSON file + echo "Adding Coder MCP server configuration" + + # Create the coder server configuration JSON + coder_config=$( + cat << EOF +{ + "type": "local", + "command": ["coder", "exp", "mcp", "server"], + "enabled": true, + "environment": { + "CODER_MCP_APP_STATUS_SLUG": "${CODER_MCP_APP_STATUS_SLUG:-}", + "CODER_MCP_AI_AGENTAPI_URL": "${CODER_MCP_AI_AGENTAPI_URL:-}", + "CODER_AGENT_URL": "${CODER_AGENT_URL:-}", + "CODER_AGENT_TOKEN": "${CODER_AGENT_TOKEN:-}", + "CODER_MCP_ALLOWED_TOOLS": "coder_report_task" + } +} +EOF + ) + + temp_file=$(mktemp) + jq --argjson coder_config "$coder_config" '.mcp.coder = $coder_config' "$opencode_config_file" > "$temp_file" + mv "$temp_file" "$opencode_config_file" + echo "Coder MCP server configuration added" + +} + +install_opencode +setup_opencode_config + +echo "OpenCode module setup completed." diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh new file mode 100755 index 00000000..c3c51beb --- /dev/null +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -0,0 +1,71 @@ +#!/bin/bash +set -euo pipefail + +export PATH=/home/coder/.opencode/bin:$PATH + +command_exists() { + command -v "$1" > /dev/null 2>&1 +} + +ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} +ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d 2> /dev/null || echo "") +ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} +ARG_SESSION_ID=${ARG_SESSION_ID:-} +ARG_CONTINUE=${ARG_CONTINUE:-false} + +# Print all received environment variables +printf "=== START CONFIG ===\n" +printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" +printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" +printf "ARG_CONTINUE: %s\n" "$ARG_CONTINUE" +printf "ARG_SESSION_ID: %s\n" "$ARG_SESSION_ID" +if [ -n "$ARG_AI_PROMPT" ]; then + printf "ARG_AI_PROMPT: [AI PROMPT RECEIVED]\n" +else + printf "ARG_AI_PROMPT: [NOT PROVIDED]\n" +fi +printf "==================================\n" + +OPENCODE_ARGS=() +AGENTAPI_ARGS=() + +validate_opencode_installation() { + if ! command_exists opencode; then + printf "ERROR: OpenCode not installed. Set install_opencode to true\n" + exit 1 + fi +} + +build_opencode_args() { + + if [ -n "$ARG_SESSION_ID" ]; then + OPENCODE_ARGS+=(--session "$ARG_SESSION_ID") + fi + + if [ "$ARG_CONTINUE" = "true" ]; then + OPENCODE_ARGS+=(--continue) + fi + + if [ -n "$ARG_AI_PROMPT" ]; then + if [ "$ARG_REPORT_TASKS" = "true" ]; then + PROMPT="Every step of the way, report your progress using coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_AI_PROMPT" + else + PROMPT="$ARG_AI_PROMPT" + fi + AGENTAPI_ARGS+=(-I "$PROMPT") + fi +} + +start_agentapi() { + printf "Starting in directory: %s\n" "$ARG_WORKDIR" + cd "$ARG_WORKDIR" + + build_opencode_args + + printf "Running OpenCode with args: %s\n" "${OPENCODE_ARGS[*]}" + echo agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" + agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" +} + +validate_opencode_installation +start_agentapi diff --git a/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh b/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh new file mode 100644 index 00000000..dcde8756 --- /dev/null +++ b/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Mock OpenCode CLI for testing purposes +# This script simulates the OpenCode command-line interface + +echo "OpenCode Mock CLI - Test Version" +echo "Args received: $*" + +# Simulate opencode behavior based on arguments +case "$1" in + --version | -v) + echo "opencode mock version 0.1.0-test" + ;; + --help | -h) + echo "OpenCode Mock Help" + echo "Usage: opencode [options] [command]" + echo "This is a mock version for testing" + ;; + *) + echo "Running OpenCode mock with arguments: $*" + echo "Mock execution completed successfully" + ;; +esac + +exit 0 diff --git a/registry/coder-labs/modules/sourcegraph-amp/README.md b/registry/coder-labs/modules/sourcegraph-amp/README.md index 608defd6..b0065318 100644 --- a/registry/coder-labs/modules/sourcegraph-amp/README.md +++ b/registry/coder-labs/modules/sourcegraph-amp/README.md @@ -13,11 +13,11 @@ Run [Amp CLI](https://ampcode.com/) in your workspace to access Sourcegraph's AI ```tf module "amp-cli" { source = "registry.coder.com/coder-labs/sourcegraph-amp/coder" - version = "2.0.1" + version = "2.0.2" agent_id = coder_agent.example.id sourcegraph_amp_api_key = var.sourcegraph_amp_api_key install_sourcegraph_amp = true - agentapi_version = "latest" + agentapi_version = "2.0.2" } ``` @@ -48,7 +48,7 @@ variable "amp_api_key" { module "amp-cli" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/sourcegraph-amp/coder" - amp_version = "2.0.1" + amp_version = "2.0.2" agent_id = coder_agent.example.id amp_api_key = var.amp_api_key # recommended for tasks usage workdir = "/home/coder/project" diff --git a/registry/coder-labs/modules/sourcegraph-amp/scripts/install.sh b/registry/coder-labs/modules/sourcegraph-amp/scripts/install.sh index 0af54e5e..123d7a1d 100644 --- a/registry/coder-labs/modules/sourcegraph-amp/scripts/install.sh +++ b/registry/coder-labs/modules/sourcegraph-amp/scripts/install.sh @@ -1,7 +1,10 @@ #!/bin/bash -set -euo pipefail -source "$HOME"/.bashrc +if [ -f "$HOME/.bashrc" ]; then + source "$HOME"/.bashrc +fi + +set -euo pipefail # ANSI colors BOLD='\033[1m' diff --git a/registry/coder-labs/modules/sourcegraph-amp/scripts/start.sh b/registry/coder-labs/modules/sourcegraph-amp/scripts/start.sh index 46dc2d76..7dbc22c1 100644 --- a/registry/coder-labs/modules/sourcegraph-amp/scripts/start.sh +++ b/registry/coder-labs/modules/sourcegraph-amp/scripts/start.sh @@ -1,14 +1,16 @@ #!/bin/bash -set -euo pipefail # Load user environment -# shellcheck source=/dev/null -source "$HOME/.bashrc" -# shellcheck source=/dev/null +if [ -f "$HOME/.bashrc" ]; then + source "$HOME/.bashrc" +fi + if [ -f "$HOME/.nvm/nvm.sh" ]; then source "$HOME/.nvm/nvm.sh" fi +set -euo pipefail + export PATH="$HOME/.local/bin:$HOME/.amp/bin:$HOME/.npm-global/bin:$PATH" function ensure_command() { diff --git a/registry/coder/.images/mux-product-hero.webp b/registry/coder/.images/mux-product-hero.webp new file mode 100644 index 00000000..bb991d24 Binary files /dev/null and b/registry/coder/.images/mux-product-hero.webp differ diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md index 3ce9c88e..6380fd40 100644 --- a/registry/coder/modules/aider/README.md +++ b/registry/coder/modules/aider/README.md @@ -19,8 +19,8 @@ variable "api_key" { module "aider" { source = "registry.coder.com/coder/aider/coder" - version = "2.0.0" - agent_id = coder_agent.example.id + version = "2.0.1" + agent_id = coder_agent.main.id api_key = var.api_key ai_provider = "google" model = "gemini" @@ -50,8 +50,8 @@ variable "gemini_api_key" { module "aider" { source = "registry.coder.com/coder/aider/coder" - version = "2.0.0" - agent_id = coder_agent.example.id + version = "2.0.1" + agent_id = coder_agent.main.id api_key = var.gemini_api_key install_aider = true workdir = "/home/coder" @@ -75,8 +75,8 @@ variable "custom_api_key" { module "aider" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/aider/coder" - version = "2.0.0" - agent_id = coder_agent.example.id + version = "2.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" ai_provider = "custom" custom_env_var_name = "MY_CUSTOM_API_KEY" diff --git a/registry/coder/modules/amazon-dcv-windows/README.md b/registry/coder/modules/amazon-dcv-windows/README.md index 52d5fc20..63f6797f 100644 --- a/registry/coder/modules/amazon-dcv-windows/README.md +++ b/registry/coder/modules/amazon-dcv-windows/README.md @@ -19,7 +19,7 @@ module "dcv" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/amazon-dcv-windows/coder" version = "1.1.1" - agent_id = resource.coder_agent.main.id + agent_id = coder_agent.main.id } resource "coder_metadata" "dcv" { diff --git a/registry/coder/modules/amazon-q/README.md b/registry/coder/modules/amazon-q/README.md index 71444a65..2a61c5ac 100644 --- a/registry/coder/modules/amazon-q/README.md +++ b/registry/coder/modules/amazon-q/README.md @@ -13,8 +13,8 @@ Run [Amazon Q](https://aws.amazon.com/q/) in your workspace to access Amazon's A ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" # Required: Authentication tarball (see below for generation) @@ -102,8 +102,8 @@ data "coder_parameter" "ai_prompt" { module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball ai_prompt = data.coder_parameter.ai_prompt.value @@ -228,8 +228,8 @@ If no custom `agent_config` is provided, the default agent name "agent" is used. ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball } @@ -258,8 +258,8 @@ This example will: ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball ai_prompt = "Help me set up a Python FastAPI project with proper testing structure" @@ -279,8 +279,8 @@ module "amazon-q" { ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball @@ -305,8 +305,8 @@ module "amazon-q" { ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball amazon_q_version = "1.14.0" # Specific version @@ -319,8 +319,8 @@ module "amazon-q" { ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball @@ -331,6 +331,7 @@ module "amazon-q" { "prompt": "You are a specialized DevOps assistant...", "tools": ["fs_read", "fs_write", "execute_bash", "use_aws"] } + EOT } ``` @@ -340,8 +341,8 @@ module "amazon-q" { ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball @@ -358,8 +359,8 @@ For environments without direct internet access, you can host Amazon Q installat ```tf module "amazon-q" { source = "registry.coder.com/coder/amazon-q/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id workdir = "/home/coder" auth_tarball = var.amazon_q_auth_tarball diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index c787c832..b467bc3b 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.2.1" + version = "4.2.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -46,12 +46,12 @@ This example shows how to configure the Claude Code module to run the agent behi module "claude-code" { source = "dev.registry.coder.com/coder/claude-code/coder" enable_boundary = true - boundary_version = "main" + boundary_version = "4.2.2" boundary_log_dir = "/tmp/boundary_logs" boundary_log_level = "WARN" boundary_additional_allowed_urls = ["GET *google.com"] boundary_proxy_port = "8087" - version = "4.2.1" + version = "4.2.2" } ``` @@ -70,7 +70,7 @@ data "coder_parameter" "ai_prompt" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.2.1" + version = "4.2.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" @@ -78,8 +78,8 @@ module "claude-code" { # OR claude_code_oauth_token = "xxxxx-xxxx-xxxx" - claude_code_version = "1.0.82" # Pin to a specific version - agentapi_version = "v0.10.0" + claude_code_version = "4.2.2" # Pin to a specific version + agentapi_version = "4.2.2" ai_prompt = data.coder_parameter.ai_prompt.value model = "sonnet" @@ -106,11 +106,11 @@ Run and configure Claude Code as a standalone CLI in your workspace. ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.2.1" + version = "4.2.2" agent_id = coder_agent.example.id workdir = "/home/coder" install_claude_code = true - claude_code_version = "latest" + claude_code_version = "4.2.2" report_tasks = false cli_app = true } @@ -129,7 +129,7 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.2.1" + version = "4.2.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token @@ -202,7 +202,7 @@ resource "coder_env" "bedrock_api_key" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.2.1" + version = "4.2.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" @@ -259,7 +259,7 @@ resource "coder_env" "google_application_credentials" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.2.1" + version = "4.2.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" model = "claude-sonnet-4@20250514" diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 80f84e6d..8aa0d1ac 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -68,13 +68,16 @@ function setup_claude_configurations() { mkdir -p "$module_path" if [ "$ARG_MCP" != "" ]; then - while IFS= read -r server_name && IFS= read -r server_json; do - echo "------------------------" - echo "Executing: claude mcp add \"$server_name\" '$server_json'" - claude mcp add "$server_name" "$server_json" - echo "------------------------" - echo "" - done < <(echo "$ARG_MCP" | jq -r '.mcpServers | to_entries[] | .key, (.value | @json)') + ( + cd "$ARG_WORKDIR" + while IFS= read -r server_name && IFS= read -r server_json; do + echo "------------------------" + echo "Executing: claude mcp add-json \"$server_name\" '$server_json' (in $ARG_WORKDIR)" + claude mcp add-json "$server_name" "$server_json" + echo "------------------------" + echo "" + done < <(echo "$ARG_MCP" | jq -r '.mcpServers | to_entries[] | .key, (.value | @json)') + ) fi if [ -n "$ARG_ALLOWED_TOOLS" ]; then diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index 4e6b2dc9..59983b9e 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -100,7 +100,8 @@ function validate_claude_installation() { TASK_SESSION_ID="cd32e253-ca16-4fd3-9825-d837e74ae3c2" task_session_exists() { - local workdir_normalized=$(echo "$ARG_WORKDIR" | tr '/' '-') + local workdir_normalized + workdir_normalized=$(echo "$ARG_WORKDIR" | tr '/' '-') local project_dir="$HOME/.claude/projects/${workdir_normalized}" printf "PROJECT_DIR: %s, workdir_normalized: %s\n" "$project_dir" "$workdir_normalized" @@ -226,15 +227,15 @@ function start_agentapi() { fi # Set HTTP Proxy port used by Boundary - BOUNDARY_ARGS+=(--proxy-port $ARG_BOUNDARY_PROXY_PORT) + BOUNDARY_ARGS+=(--proxy-port "$ARG_BOUNDARY_PROXY_PORT") # Set log level for boundary - BOUNDARY_ARGS+=(--log-level $ARG_BOUNDARY_LOG_LEVEL) + BOUNDARY_ARGS+=(--log-level "$ARG_BOUNDARY_LOG_LEVEL") if [ "${ARG_ENABLE_BOUNDARY_PPROF:-false}" = "true" ]; then # Enable boundary pprof server on specified port BOUNDARY_ARGS+=(--pprof) - BOUNDARY_ARGS+=(--pprof-port ${ARG_BOUNDARY_PPROF_PORT}) + BOUNDARY_ARGS+=(--pprof-port "$ARG_BOUNDARY_PPROF_PORT") fi agentapi server --type claude --term-width 67 --term-height 1190 -- \ diff --git a/registry/coder/modules/code-server/README.md b/registry/coder/modules/code-server/README.md index b9ed6b72..fca18909 100644 --- a/registry/coder/modules/code-server/README.md +++ b/registry/coder/modules/code-server/README.md @@ -14,7 +14,7 @@ Automatically install [code-server](https://github.com/coder/code-server) in a w module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id } ``` @@ -29,9 +29,9 @@ module "code-server" { module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id - install_version = "4.8.3" + install_version = "1.4.1" } ``` @@ -43,7 +43,7 @@ Install the Dracula theme from [OpenVSX](https://open-vsx.org/): module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id extensions = [ "dracula-theme.theme-dracula" @@ -61,7 +61,7 @@ Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarte module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id extensions = ["dracula-theme.theme-dracula"] settings = { @@ -78,7 +78,7 @@ Just run code-server in the background, don't fetch it from GitHub: module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"] } @@ -92,7 +92,7 @@ You can pass additional command-line arguments to code-server using the `additio module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id additional_args = "--disable-workspace-trust" } @@ -108,7 +108,7 @@ Run an existing copy of code-server if found, otherwise download from GitHub: module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id use_cached = true extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"] @@ -121,7 +121,7 @@ Just run code-server in the background, don't fetch it from GitHub: module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.example.id offline = true } diff --git a/registry/coder/modules/code-server/run.sh b/registry/coder/modules/code-server/run.sh index 55918fa4..33a6972a 100644 --- a/registry/coder/modules/code-server/run.sh +++ b/registry/coder/modules/code-server/run.sh @@ -88,6 +88,7 @@ function extension_installed() { if [ "${USE_CACHED_EXTENSIONS}" != true ]; then return 1 fi + # shellcheck disable=SC2066 for _extension in "$${EXTENSIONS_ARRAY[@]}"; do if [ "$_extension" == "$1" ]; then echo "Extension $1 was already installed." @@ -99,6 +100,7 @@ function extension_installed() { # Install each extension... IFS=',' read -r -a EXTENSIONLIST <<< "$${EXTENSIONS}" +# shellcheck disable=SC2066 for extension in "$${EXTENSIONLIST[@]}"; do if [ -z "$extension" ]; then continue diff --git a/registry/coder/modules/coder-login/README.md b/registry/coder/modules/coder-login/README.md index de0c3179..86609a02 100644 --- a/registry/coder/modules/coder-login/README.md +++ b/registry/coder/modules/coder-login/README.md @@ -14,8 +14,8 @@ Automatically logs the user into Coder when creating their workspace. module "coder-login" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/coder-login/coder" - version = "1.1.0" - agent_id = coder_agent.example.id + version = "1.1.1" + agent_id = coder_agent.main.id } ``` diff --git a/registry/coder/modules/cursor/README.md b/registry/coder/modules/cursor/README.md index c6178565..7a870ac0 100644 --- a/registry/coder/modules/cursor/README.md +++ b/registry/coder/modules/cursor/README.md @@ -16,8 +16,8 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" - version = "1.3.2" - agent_id = coder_agent.example.id + version = "1.4.0" + agent_id = coder_agent.main.id } ``` @@ -29,8 +29,8 @@ module "cursor" { module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" - version = "1.3.2" - agent_id = coder_agent.example.id + version = "1.4.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -45,8 +45,8 @@ The following example configures Cursor to use the GitHub MCP server with authen module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" - version = "1.3.2" - agent_id = coder_agent.example.id + version = "1.4.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" mcp = jsonencode({ mcpServers = { @@ -57,6 +57,8 @@ module "cursor" { }, "type" : "http" } + + } }) } diff --git a/registry/coder/modules/cursor/main.test.ts b/registry/coder/modules/cursor/main.test.ts index 618f987e..fdba8501 100644 --- a/registry/coder/modules/cursor/main.test.ts +++ b/registry/coder/modules/cursor/main.test.ts @@ -26,7 +26,10 @@ describe("cursor", async () => { ); const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "cursor", + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", ); expect(coder_app).not.toBeNull(); @@ -76,21 +79,6 @@ describe("cursor", async () => { ); }); - it("expect order to be set", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - order: "22", - }); - - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "cursor", - ); - - expect(coder_app).not.toBeNull(); - expect(coder_app?.instances.length).toBe(1); - expect(coder_app?.instances[0].attributes.order).toBe(22); - }); - it("writes ~/.cursor/mcp.json when mcp provided", async () => { const id = await runContainer("alpine"); try { diff --git a/registry/coder/modules/cursor/main.tf b/registry/coder/modules/cursor/main.tf index d26000a8..0c0f8aa2 100644 --- a/registry/coder/modules/cursor/main.tf +++ b/registry/coder/modules/cursor/main.tf @@ -64,26 +64,21 @@ locals { mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : "" } -resource "coder_app" "cursor" { - agent_id = var.agent_id - external = true - icon = "/icon/cursor.svg" - slug = var.slug - display_name = var.display_name - order = var.order - group = var.group - url = join("", [ - "cursor://coder.coder-remote/open", - "?owner=", - data.coder_workspace_owner.me.name, - "&workspace=", - data.coder_workspace.me.name, - var.folder != "" ? join("", ["&folder=", var.folder]) : "", - var.open_recent ? "&openRecent" : "", - "&url=", - data.coder_workspace.me.access_url, - "&token=$SESSION_TOKEN", - ]) +module "vscode-desktop-core" { + source = "registry.coder.com/coder/vscode-desktop-core/coder" + version = "1.0.0" + + agent_id = var.agent_id + + coder_app_icon = "/icon/cursor.svg" + coder_app_slug = var.slug + coder_app_display_name = var.display_name + coder_app_order = var.order + coder_app_group = var.group + + folder = var.folder + open_recent = var.open_recent + protocol = "cursor" } resource "coder_script" "cursor_mcp" { @@ -103,6 +98,6 @@ resource "coder_script" "cursor_mcp" { } output "cursor_url" { - value = coder_app.cursor.url + value = module.vscode-desktop-core.ide_uri description = "Cursor IDE Desktop URL." -} +} \ No newline at end of file diff --git a/registry/coder/modules/devcontainers-cli/README.md b/registry/coder/modules/devcontainers-cli/README.md index 9622cceb..bb5ec6de 100644 --- a/registry/coder/modules/devcontainers-cli/README.md +++ b/registry/coder/modules/devcontainers-cli/README.md @@ -15,7 +15,7 @@ The devcontainers-cli module provides an easy way to install [`@devcontainers/cl ```tf module "devcontainers-cli" { source = "registry.coder.com/coder/devcontainers-cli/coder" - version = "1.0.32" + version = "1.0.34" agent_id = coder_agent.example.id } ``` diff --git a/registry/coder/modules/devcontainers-cli/run.sh b/registry/coder/modules/devcontainers-cli/run.sh index faa6e933..d155cd59 100755 --- a/registry/coder/modules/devcontainers-cli/run.sh +++ b/registry/coder/modules/devcontainers-cli/run.sh @@ -4,7 +4,7 @@ # might contain a `package.json` with `packageManager` set to something # other than the detected package manager. When this happens, it can # cause the installation to fail. -cd "$CODER_SCRIPT_DATA_DIR" +cd "$CODER_SCRIPT_DATA_DIR" || exit # If @devcontainers/cli is already installed, we can skip if command -v devcontainer > /dev/null 2>&1; then diff --git a/registry/coder/modules/dotfiles/README.md b/registry/coder/modules/dotfiles/README.md index 02c62004..e35033a6 100644 --- a/registry/coder/modules/dotfiles/README.md +++ b/registry/coder/modules/dotfiles/README.md @@ -18,7 +18,7 @@ Under the hood, this module uses the [coder dotfiles](https://coder.com/docs/v2/ module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.1" + version = "1.2.3" agent_id = coder_agent.example.id } ``` @@ -31,7 +31,7 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.1" + version = "1.2.3" agent_id = coder_agent.example.id } ``` @@ -42,7 +42,7 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.1" + version = "1.2.3" agent_id = coder_agent.example.id user = "root" } @@ -54,14 +54,14 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.1" + version = "1.2.3" agent_id = coder_agent.example.id } module "dotfiles-root" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.1" + version = "1.2.3" agent_id = coder_agent.example.id user = "root" dotfiles_uri = module.dotfiles.dotfiles_uri @@ -76,7 +76,7 @@ You can set a default dotfiles repository for all users by setting the `default_ module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.1" + version = "1.2.3" agent_id = coder_agent.example.id default_dotfiles_uri = "https://github.com/coder/dotfiles" } diff --git a/registry/coder/modules/dotfiles/run.sh b/registry/coder/modules/dotfiles/run.sh index e0599418..91229589 100644 --- a/registry/coder/modules/dotfiles/run.sh +++ b/registry/coder/modules/dotfiles/run.sh @@ -5,6 +5,7 @@ set -euo pipefail DOTFILES_URI="${DOTFILES_URI}" DOTFILES_USER="${DOTFILES_USER}" +# shellcheck disable=SC2157 if [ -n "$${DOTFILES_URI// }" ]; then if [ -z "$DOTFILES_USER" ]; then DOTFILES_USER="$USER" diff --git a/registry/coder/modules/filebrowser/README.md b/registry/coder/modules/filebrowser/README.md index 821768b1..19120fed 100644 --- a/registry/coder/modules/filebrowser/README.md +++ b/registry/coder/modules/filebrowser/README.md @@ -14,8 +14,8 @@ A file browser for your workspace. module "filebrowser" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/filebrowser/coder" - version = "1.1.2" - agent_id = coder_agent.example.id + version = "1.1.3" + agent_id = coder_agent.main.id } ``` @@ -29,8 +29,8 @@ module "filebrowser" { module "filebrowser" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/filebrowser/coder" - version = "1.1.2" - agent_id = coder_agent.example.id + version = "1.1.3" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -41,8 +41,8 @@ module "filebrowser" { module "filebrowser" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/filebrowser/coder" - version = "1.1.2" - agent_id = coder_agent.example.id + version = "1.1.3" + agent_id = coder_agent.main.id database_path = ".config/filebrowser.db" } ``` @@ -53,8 +53,8 @@ module "filebrowser" { module "filebrowser" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/filebrowser/coder" - version = "1.1.2" - agent_id = coder_agent.example.id + version = "1.1.3" + agent_id = coder_agent.main.id agent_name = "main" subdomain = false } diff --git a/registry/coder/modules/git-clone/README.md b/registry/coder/modules/git-clone/README.md index 6ec2ccbe..94d2ddac 100644 --- a/registry/coder/modules/git-clone/README.md +++ b/registry/coder/modules/git-clone/README.md @@ -14,7 +14,7 @@ This module allows you to automatically clone a repository by URL and skip if it module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" } @@ -28,7 +28,7 @@ module "git-clone" { module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" base_dir = "~/projects/coder" @@ -43,7 +43,7 @@ To use with [Git Authentication](https://coder.com/docs/v2/latest/admin/git-prov module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" } @@ -69,7 +69,7 @@ data "coder_parameter" "git_repo" { module "git_clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = data.coder_parameter.git_repo.value } @@ -78,7 +78,7 @@ module "git_clone" { module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.0.18" + version = "1.2.2" agent_id = coder_agent.example.id order = 1 folder = "/home/${local.username}/${module.git_clone[count.index].folder_name}" @@ -103,7 +103,7 @@ Configuring `git-clone` for a self-hosted GitHub Enterprise Server running at `g module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.example.com/coder/coder/tree/feat/example" git_providers = { @@ -122,7 +122,7 @@ To GitLab clone with a specific branch like `feat/example` module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://gitlab.com/coder/coder/-/tree/feat/example" } @@ -134,7 +134,7 @@ Configuring `git-clone` for a self-hosted GitLab running at `gitlab.example.com` module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://gitlab.example.com/coder/coder/-/tree/feat/example" git_providers = { @@ -155,7 +155,7 @@ For example, to clone the `feat/example` branch: module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" branch_name = "feat/example" @@ -173,7 +173,7 @@ For example, this will clone into the `~/projects/coder/coder-dev` folder: module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" folder_name = "coder-dev" @@ -192,7 +192,7 @@ If not defined, the default, `0`, performs a full clone. module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/modules/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" depth = 1 @@ -208,7 +208,7 @@ This is useful for running initialization tasks like installing dependencies or module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.0" + version = "1.2.2" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" post_clone_script = <<-EOT diff --git a/registry/coder/modules/git-clone/run.sh b/registry/coder/modules/git-clone/run.sh index 07c970e9..4b91ee68 100644 --- a/registry/coder/modules/git-clone/run.sh +++ b/registry/coder/modules/git-clone/run.sh @@ -60,7 +60,7 @@ if [ -n "$POST_CLONE_SCRIPT" ]; then echo "Running post-clone script..." echo "$POST_CLONE_SCRIPT" | base64 -d > /tmp/post_clone.sh chmod +x /tmp/post_clone.sh - cd "$CLONE_PATH" + cd "$CLONE_PATH" || exit /tmp/post_clone.sh rm /tmp/post_clone.sh fi diff --git a/registry/coder/modules/git-commit-signing/README.md b/registry/coder/modules/git-commit-signing/README.md index de67febc..87c49da6 100644 --- a/registry/coder/modules/git-commit-signing/README.md +++ b/registry/coder/modules/git-commit-signing/README.md @@ -22,7 +22,7 @@ This module has a chance of conflicting with the user's dotfiles / the personali module "git-commit-signing" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-commit-signing/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id } ``` diff --git a/registry/coder/modules/git-config/README.md b/registry/coder/modules/git-config/README.md index ba618d81..753e8de3 100644 --- a/registry/coder/modules/git-config/README.md +++ b/registry/coder/modules/git-config/README.md @@ -14,8 +14,8 @@ Runs a script that updates git credentials in the workspace to match the user's module "git-config" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-config/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id } ``` @@ -29,8 +29,8 @@ TODO: Add screenshot module "git-config" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-config/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id allow_email_change = true } ``` @@ -43,8 +43,8 @@ TODO: Add screenshot module "git-config" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-config/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id allow_username_change = false allow_email_change = false } diff --git a/registry/coder/modules/github-upload-public-key/README.md b/registry/coder/modules/github-upload-public-key/README.md index 92c2c1c9..fa2c10bd 100644 --- a/registry/coder/modules/github-upload-public-key/README.md +++ b/registry/coder/modules/github-upload-public-key/README.md @@ -14,8 +14,8 @@ Templates that utilize Github External Auth can automatically ensure that the Co module "github-upload-public-key" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/github-upload-public-key/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id } ``` @@ -47,8 +47,8 @@ data "coder_external_auth" "github" { module "github-upload-public-key" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/github-upload-public-key/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id external_auth_id = data.coder_external_auth.github.id } ``` diff --git a/registry/coder/modules/goose/README.md b/registry/coder/modules/goose/README.md index 89fd7280..d3a17c5a 100644 --- a/registry/coder/modules/goose/README.md +++ b/registry/coder/modules/goose/README.md @@ -13,8 +13,8 @@ Run the [Goose](https://block.github.io/goose/) agent in your workspace to gener ```tf module "goose" { source = "registry.coder.com/coder/goose/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id folder = "/home/coder" install_goose = true goose_version = "v1.0.31" @@ -39,7 +39,7 @@ module "coder-login" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/coder-login/coder" version = "1.0.15" - agent_id = coder_agent.example.id + agent_id = coder_agent.main.id } variable "anthropic_api_key" { @@ -79,8 +79,8 @@ resource "coder_agent" "main" { module "goose" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/goose/coder" - version = "3.0.0" - agent_id = coder_agent.example.id + version = "3.0.1" + agent_id = coder_agent.main.id folder = "/home/coder" install_goose = true goose_version = "v1.0.31" diff --git a/registry/coder/modules/hcp-vault-secrets/README.md b/registry/coder/modules/hcp-vault-secrets/README.md index 52edd8ef..ce0ec242 100644 --- a/registry/coder/modules/hcp-vault-secrets/README.md +++ b/registry/coder/modules/hcp-vault-secrets/README.md @@ -26,8 +26,8 @@ This module lets you fetch all or selective secrets from a [HCP Vault Secrets](h ```tf module "vault" { source = "registry.coder.com/coder/hcp-vault-secrets/coder" - version = "1.0.34" - agent_id = coder_agent.example.id + version = "1.0.35" + agent_id = coder_agent.main.id app_name = "demo-app" project_id = "aaa-bbb-ccc" } @@ -52,8 +52,8 @@ To fetch all secrets from the HCP Vault Secrets app, skip the `secrets` input. ```tf module "vault" { source = "registry.coder.com/coder/hcp-vault-secrets/coder" - version = "1.0.34" - agent_id = coder_agent.example.id + version = "1.0.35" + agent_id = coder_agent.main.id app_name = "demo-app" project_id = "aaa-bbb-ccc" } @@ -66,8 +66,8 @@ To fetch selective secrets from the HCP Vault Secrets app, set the `secrets` inp ```tf module "vault" { source = "registry.coder.com/coder/hcp-vault-secrets/coder" - version = "1.0.34" - agent_id = coder_agent.example.id + version = "1.0.35" + agent_id = coder_agent.main.id app_name = "demo-app" project_id = "aaa-bbb-ccc" secrets = ["MY_SECRET_1", "MY_SECRET_2"] @@ -81,8 +81,8 @@ Set `client_id` and `client_secret` as module inputs. ```tf module "vault" { source = "registry.coder.com/coder/hcp-vault-secrets/coder" - version = "1.0.34" - agent_id = coder_agent.example.id + version = "1.0.35" + agent_id = coder_agent.main.id app_name = "demo-app" project_id = "aaa-bbb-ccc" client_id = "HCP_CLIENT_ID" diff --git a/registry/coder/modules/jetbrains-fleet/README.md b/registry/coder/modules/jetbrains-fleet/README.md index dadf10a8..c004f95c 100644 --- a/registry/coder/modules/jetbrains-fleet/README.md +++ b/registry/coder/modules/jetbrains-fleet/README.md @@ -16,8 +16,8 @@ JetBrains Fleet is a next-generation IDE that supports collaborative development module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id } ``` @@ -37,8 +37,8 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id } ``` @@ -48,8 +48,8 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -60,8 +60,8 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id display_name = "Fleet" group = "JetBrains IDEs" order = 1 @@ -74,8 +74,8 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id agent_name = coder_agent.example.name } ``` diff --git a/registry/coder/modules/jetbrains-gateway/README.md b/registry/coder/modules/jetbrains-gateway/README.md index 0c5c8ff8..abd008ce 100644 --- a/registry/coder/modules/jetbrains-gateway/README.md +++ b/registry/coder/modules/jetbrains-gateway/README.md @@ -20,8 +20,8 @@ Consult the [JetBrains documentation](https://www.jetbrains.com/help/idea/prereq module "jetbrains_gateway" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-gateway/coder" - version = "1.2.5" - agent_id = coder_agent.example.id + version = "1.2.6" + agent_id = coder_agent.main.id folder = "/home/coder/example" jetbrains_ides = ["CL", "GO", "IU", "PY", "WS"] default = "GO" @@ -38,8 +38,8 @@ module "jetbrains_gateway" { module "jetbrains_gateway" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-gateway/coder" - version = "1.2.5" - agent_id = coder_agent.example.id + version = "1.2.6" + agent_id = coder_agent.main.id folder = "/home/coder/example" jetbrains_ides = ["GO", "WS"] default = "GO" @@ -52,8 +52,8 @@ module "jetbrains_gateway" { module "jetbrains_gateway" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-gateway/coder" - version = "1.2.5" - agent_id = coder_agent.example.id + version = "1.2.6" + agent_id = coder_agent.main.id folder = "/home/coder/example" jetbrains_ides = ["IU", "PY"] default = "IU" @@ -67,8 +67,8 @@ module "jetbrains_gateway" { module "jetbrains_gateway" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-gateway/coder" - version = "1.2.5" - agent_id = coder_agent.example.id + version = "1.2.6" + agent_id = coder_agent.main.id folder = "/home/coder/example" jetbrains_ides = ["IU", "PY"] default = "IU" @@ -76,8 +76,9 @@ module "jetbrains_gateway" { jetbrains_ide_versions = { "IU" = { build_number = "243.21565.193" - version = "2024.3" + version = "1.2.6" } + "PY" = { build_number = "243.21565.199" version = "2024.3" @@ -92,8 +93,8 @@ module "jetbrains_gateway" { module "jetbrains_gateway" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-gateway/coder" - version = "1.2.5" - agent_id = coder_agent.example.id + version = "1.2.6" + agent_id = coder_agent.main.id folder = "/home/coder/example" jetbrains_ides = ["GO", "WS"] default = "GO" @@ -110,8 +111,8 @@ Due to the highest priority of the `ide_download_link` parameter in the `(jetbra module "jetbrains_gateway" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-gateway/coder" - version = "1.2.5" - agent_id = coder_agent.example.id + version = "1.2.6" + agent_id = coder_agent.main.id folder = "/home/coder/example" jetbrains_ides = ["GO", "WS"] releases_base_link = "https://releases.internal.site/" diff --git a/registry/coder/modules/jetbrains/README.md b/registry/coder/modules/jetbrains/README.md index 7b55232c..71861359 100644 --- a/registry/coder/modules/jetbrains/README.md +++ b/registry/coder/modules/jetbrains/README.md @@ -14,8 +14,8 @@ This module adds JetBrains IDE buttons to launch IDEs directly from the dashboar module "jetbrains" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/home/coder/project" # tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button." # Optional } @@ -40,8 +40,8 @@ When `default` contains IDE codes, those IDEs are created directly without user module "jetbrains" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/home/coder/project" default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA } @@ -53,8 +53,8 @@ module "jetbrains" { module "jetbrains" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/home/coder/project" # Show parameter with limited options options = ["IU", "PY"] # Only these IDEs are available for selection @@ -67,8 +67,8 @@ module "jetbrains" { module "jetbrains" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/home/coder/project" default = ["IU", "PY"] channel = "eap" # Use Early Access Preview versions @@ -82,8 +82,8 @@ module "jetbrains" { module "jetbrains" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/workspace/project" # Custom IDE metadata (display names and icons) @@ -93,6 +93,7 @@ module "jetbrains" { icon = "/custom/icons/intellij.svg" build = "251.26927.53" } + "PY" = { name = "PyCharm" icon = "/custom/icons/pycharm.svg" @@ -108,8 +109,8 @@ module "jetbrains" { module "jetbrains_pycharm" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/workspace/project" default = ["PY"] # Only PyCharm @@ -128,8 +129,8 @@ Add helpful tooltip text that appears when users hover over the IDE app buttons: module "jetbrains" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id folder = "/home/coder/project" default = ["IU", "PY"] tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button." diff --git a/registry/coder/modules/jfrog-oauth/README.md b/registry/coder/modules/jfrog-oauth/README.md index 50311de7..30727f08 100644 --- a/registry/coder/modules/jfrog-oauth/README.md +++ b/registry/coder/modules/jfrog-oauth/README.md @@ -16,8 +16,8 @@ Install the JF CLI and authenticate package managers with Artifactory using OAut module "jfrog" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jfrog-oauth/coder" - version = "1.2.2" - agent_id = coder_agent.example.id + version = "1.2.3" + agent_id = coder_agent.main.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" @@ -29,6 +29,7 @@ module "jfrog" { conda = ["conda", "conda-local"] maven = ["maven", "maven-local"] } + } ``` @@ -56,14 +57,15 @@ Configure the Python pip package manager to fetch packages from Artifactory whil module "jfrog" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jfrog-oauth/coder" - version = "1.2.2" - agent_id = coder_agent.example.id + version = "1.2.3" + agent_id = coder_agent.main.id jfrog_url = "https://example.jfrog.io" username_field = "email" package_managers = { pypi = ["pypi"] } + } ``` @@ -85,8 +87,8 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio module "jfrog" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jfrog-oauth/coder" - version = "1.2.2" - agent_id = coder_agent.example.id + version = "1.2.3" + agent_id = coder_agent.main.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" configure_code_server = true # Add JFrog extension configuration for code-server @@ -95,6 +97,7 @@ module "jfrog" { go = ["go"] pypi = ["pypi"] } + } ``` diff --git a/registry/coder/modules/jfrog-token/README.md b/registry/coder/modules/jfrog-token/README.md index c457cc6e..5252a864 100644 --- a/registry/coder/modules/jfrog-token/README.md +++ b/registry/coder/modules/jfrog-token/README.md @@ -13,8 +13,8 @@ Install the JF CLI and authenticate package managers with Artifactory using Arti ```tf module "jfrog" { source = "registry.coder.com/coder/jfrog-token/coder" - version = "1.2.1" - agent_id = coder_agent.example.id + version = "1.2.2" + agent_id = coder_agent.main.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token package_managers = { @@ -25,6 +25,7 @@ module "jfrog" { conda = ["conda", "conda-local"] maven = ["maven", "maven-local"] } + } ``` @@ -42,8 +43,8 @@ For detailed instructions, please see this [guide](https://coder.com/docs/v2/lat ```tf module "jfrog" { source = "registry.coder.com/coder/jfrog-token/coder" - version = "1.2.1" - agent_id = coder_agent.example.id + version = "1.2.2" + agent_id = coder_agent.main.id jfrog_url = "https://YYYY.jfrog.io" artifactory_access_token = var.artifactory_access_token # An admin access token package_managers = { @@ -53,6 +54,7 @@ module "jfrog" { conda = ["conda-local"] maven = ["maven-local"] } + } ``` @@ -81,8 +83,8 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio ```tf module "jfrog" { source = "registry.coder.com/coder/jfrog-token/coder" - version = "1.2.1" - agent_id = coder_agent.example.id + version = "1.2.2" + agent_id = coder_agent.main.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token configure_code_server = true # Add JFrog extension configuration for code-server @@ -91,6 +93,7 @@ module "jfrog" { go = ["go"] pypi = ["pypi"] } + } ``` @@ -101,14 +104,15 @@ data "coder_workspace" "me" {} module "jfrog" { source = "registry.coder.com/coder/jfrog-token/coder" - version = "1.2.1" - agent_id = coder_agent.example.id + version = "1.2.2" + agent_id = coder_agent.main.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token token_description = "Token for Coder workspace: ${data.coder_workspace_owner.me.name}/${data.coder_workspace.me.name}" package_managers = { npm = ["npm"] } + } ``` diff --git a/registry/coder/modules/jupyter-notebook/README.md b/registry/coder/modules/jupyter-notebook/README.md index a509df6a..ea625d81 100644 --- a/registry/coder/modules/jupyter-notebook/README.md +++ b/registry/coder/modules/jupyter-notebook/README.md @@ -16,7 +16,7 @@ A module that adds Jupyter Notebook in your Coder template. module "jupyter-notebook" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jupyter-notebook/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id } ``` diff --git a/registry/coder/modules/jupyterlab/README.md b/registry/coder/modules/jupyterlab/README.md index 6c401ded..b4e812fe 100644 --- a/registry/coder/modules/jupyterlab/README.md +++ b/registry/coder/modules/jupyterlab/README.md @@ -16,8 +16,8 @@ A module that adds JupyterLab in your Coder template. module "jupyterlab" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jupyterlab/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id } ``` @@ -29,8 +29,8 @@ JupyterLab is automatically configured to work with Coder's iframe embedding. Fo module "jupyterlab" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jupyterlab/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.2.1" + agent_id = coder_agent.main.id config = { ServerApp = { # Required for Coder Tasks iFrame embedding - do not remove @@ -38,6 +38,7 @@ module "jupyterlab" { headers = { "Content-Security-Policy" = "frame-ancestors 'self' ${data.coder_workspace.me.access_url}" } + } # Your additional configuration here root_dir = "/workspace/notebooks" diff --git a/registry/coder/modules/kasmvnc/README.md b/registry/coder/modules/kasmvnc/README.md index 7f01b45b..c769cd85 100644 --- a/registry/coder/modules/kasmvnc/README.md +++ b/registry/coder/modules/kasmvnc/README.md @@ -14,7 +14,7 @@ Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and module "kasmvnc" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kasmvnc/coder" - version = "1.2.5" + version = "1.2.6" agent_id = coder_agent.example.id desktop_environment = "xfce" subdomain = true diff --git a/registry/coder/modules/kasmvnc/run.sh b/registry/coder/modules/kasmvnc/run.sh index 089dce3e..6238bdb6 100644 --- a/registry/coder/modules/kasmvnc/run.sh +++ b/registry/coder/modules/kasmvnc/run.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash -# Exit on error, undefined variables, and pipe failures -set -euo pipefail +set -eo pipefail error() { printf "💀 ERROR: %s\n" "$@" @@ -121,6 +120,9 @@ fi # shellcheck disable=SC1091 source /etc/os-release + +set -u + distro="$ID" distro_version="$VERSION_ID" codename="$VERSION_CODENAME" diff --git a/registry/coder/modules/kiro/README.md b/registry/coder/modules/kiro/README.md index 10d2117f..23c17885 100644 --- a/registry/coder/modules/kiro/README.md +++ b/registry/coder/modules/kiro/README.md @@ -18,8 +18,8 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "kiro" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kiro/coder" - version = "1.1.0" - agent_id = coder_agent.example.id + version = "1.2.0" + agent_id = coder_agent.main.id } ``` @@ -31,8 +31,8 @@ module "kiro" { module "kiro" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kiro/coder" - version = "1.1.0" - agent_id = coder_agent.example.id + version = "1.2.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -47,8 +47,8 @@ The following example configures Kiro to use the GitHub MCP server with authenti module "kiro" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kiro/coder" - version = "1.1.0" - agent_id = coder_agent.example.id + version = "1.2.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" mcp = jsonencode({ mcpServers = { @@ -59,6 +59,8 @@ module "kiro" { }, "type" : "http" } + + } }) } diff --git a/registry/coder/modules/kiro/kiro.tftest.hcl b/registry/coder/modules/kiro/kiro.tftest.hcl index b132551a..5fb51311 100644 --- a/registry/coder/modules/kiro/kiro.tftest.hcl +++ b/registry/coder/modules/kiro/kiro.tftest.hcl @@ -17,11 +17,6 @@ run "default_output" { condition = output.kiro_url == "kiro://coder.coder-remote/open?owner=default&workspace=default&url=https://mydeployment.coder.com&token=$SESSION_TOKEN" error_message = "Default kiro_url must match expected value" } - - assert { - condition = coder_app.kiro.order == null - error_message = "coder_app order must be null by default" - } } run "adds_folder" { @@ -53,54 +48,6 @@ run "folder_and_open_recent" { } } -run "custom_slug_display_name" { - command = plan - - variables { - agent_id = "foo" - slug = "kiro-ai" - display_name = "Kiro AI IDE" - } - - assert { - condition = coder_app.kiro.slug == "kiro-ai" - error_message = "coder_app slug must be set to kiro-ai" - } - - assert { - condition = coder_app.kiro.display_name == "Kiro AI IDE" - error_message = "coder_app display_name must be set to Kiro AI IDE" - } -} - -run "sets_order" { - command = plan - - variables { - agent_id = "foo" - order = 5 - } - - assert { - condition = coder_app.kiro.order == 5 - error_message = "coder_app order must be set to 5" - } -} - -run "sets_group" { - command = plan - - variables { - agent_id = "foo" - group = "AI IDEs" - } - - assert { - condition = coder_app.kiro.group == "AI IDEs" - error_message = "coder_app group must be set to AI IDEs" - } -} - run "writes_mcp_json" { command = plan diff --git a/registry/coder/modules/kiro/main.test.ts b/registry/coder/modules/kiro/main.test.ts index 2d268a84..608abf89 100644 --- a/registry/coder/modules/kiro/main.test.ts +++ b/registry/coder/modules/kiro/main.test.ts @@ -26,7 +26,10 @@ describe("kiro", async () => { ); const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "kiro", + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", ); expect(coder_app).not.toBeNull(); @@ -55,47 +58,6 @@ describe("kiro", async () => { ); }); - it("custom slug and display_name", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - slug: "kiro-ai", - display_name: "Kiro AI IDE", - }); - - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "kiro", - ); - - expect(coder_app?.instances[0].attributes.slug).toBe("kiro-ai"); - expect(coder_app?.instances[0].attributes.display_name).toBe("Kiro AI IDE"); - }); - - it("sets order", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - order: "5", - }); - - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "kiro", - ); - - expect(coder_app?.instances[0].attributes.order).toBe(5); - }); - - it("sets group", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - group: "AI IDEs", - }); - - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "kiro", - ); - - expect(coder_app?.instances[0].attributes.group).toBe("AI IDEs"); - }); - it("writes ~/.kiro/settings/mcp.json when mcp provided", async () => { const id = await runContainer("alpine"); try { diff --git a/registry/coder/modules/kiro/main.tf b/registry/coder/modules/kiro/main.tf index fed8407b..c48364bc 100644 --- a/registry/coder/modules/kiro/main.tf +++ b/registry/coder/modules/kiro/main.tf @@ -38,18 +38,6 @@ variable "group" { default = null } -variable "slug" { - type = string - description = "The slug of the app." - default = "kiro" -} - -variable "display_name" { - type = string - description = "The display name of the app." - default = "Kiro IDE" -} - variable "mcp" { type = string description = "JSON-encoded string to configure MCP servers for Kiro. When set, writes ~/.kiro/settings/mcp.json." @@ -63,26 +51,21 @@ locals { mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : "" } -resource "coder_app" "kiro" { - agent_id = var.agent_id - external = true - icon = "/icon/kiro.svg" - slug = var.slug - display_name = var.display_name - order = var.order - group = var.group - url = join("", [ - "kiro://coder.coder-remote/open", - "?owner=", - data.coder_workspace_owner.me.name, - "&workspace=", - data.coder_workspace.me.name, - var.folder != "" ? join("", ["&folder=", var.folder]) : "", - var.open_recent ? "&openRecent" : "", - "&url=", - data.coder_workspace.me.access_url, - "&token=$SESSION_TOKEN", - ]) +module "vscode-desktop-core" { + source = "registry.coder.com/coder/vscode-desktop-core/coder" + version = "1.0.0" + + agent_id = var.agent_id + + coder_app_icon = "/icon/kiro.svg" + coder_app_slug = "kiro-ai" + coder_app_display_name = "Kiro AI IDE" + coder_app_order = var.order + coder_app_group = var.group + + folder = var.folder + open_recent = var.open_recent + protocol = "kiro" } resource "coder_script" "kiro_mcp" { @@ -102,6 +85,6 @@ resource "coder_script" "kiro_mcp" { } output "kiro_url" { - value = coder_app.kiro.url + value = module.vscode-desktop-core.ide_uri description = "Kiro IDE URL." -} +} \ No newline at end of file diff --git a/registry/coder/modules/local-windows-rdp/README.md b/registry/coder/modules/local-windows-rdp/README.md index ad445dba..93bb4594 100644 --- a/registry/coder/modules/local-windows-rdp/README.md +++ b/registry/coder/modules/local-windows-rdp/README.md @@ -24,7 +24,7 @@ This module enables Remote Desktop Protocol (RDP) on Windows workspaces and adds module "rdp_desktop" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/local-windows-rdp/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id agent_name = coder_agent.main.name } @@ -57,7 +57,7 @@ Uses default credentials (Username: `Administrator`, Password: `coderRDP!`): module "rdp_desktop" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/local-windows-rdp/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id agent_name = coder_agent.main.name } @@ -71,8 +71,8 @@ Specify a custom display name for the `coder_app` button: module "rdp_desktop" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/local-windows-rdp/coder" - version = "1.0.2" - agent_id = coder_agent.windows.id + version = "1.0.3" + agent_id = coder_agent.main.id agent_name = "windows" display_name = "Windows Desktop" order = 1 diff --git a/registry/coder/modules/mux/README.md b/registry/coder/modules/mux/README.md index e6132ea6..78925ed3 100644 --- a/registry/coder/modules/mux/README.md +++ b/registry/coder/modules/mux/README.md @@ -2,23 +2,25 @@ display_name: mux description: Coding Agent Multiplexer - Run multiple AI agents in parallel icon: ../../../../.icons/mux.svg -verified: false +verified: true tags: [ai, agents, development, multiplexer] --- # mux -Automatically install and run mux in a Coder workspace. By default, the module installs `mux@next` from npm (with a fallback to downloading the npm tarball if npm is unavailable). mux is a desktop application for parallel agentic development that enables developers to run multiple AI agents simultaneously across isolated workspaces. +Automatically install and run [mux](https://github.com/coder/mux) in a Coder workspace. By default, the module installs `mux@next` from npm (with a fallback to downloading the npm tarball if npm is unavailable). mux is a desktop application for parallel agentic development that enables developers to run multiple AI agents simultaneously across isolated workspaces. ```tf module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.4" + agent_id = coder_agent.main.id } ``` +![mux](../../.images/mux-product-hero.webp) + ## Features - **Parallel Agent Execution**: Run multiple AI agents simultaneously on different tasks @@ -35,8 +37,8 @@ module "mux" { module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.4" + agent_id = coder_agent.main.id } ``` @@ -46,8 +48,8 @@ module "mux" { module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.4" + agent_id = coder_agent.main.id # Default is "latest"; set to a specific version to pin install_version = "0.4.0" } @@ -59,8 +61,8 @@ module "mux" { module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.4" + agent_id = coder_agent.main.id port = 8080 } ``` @@ -73,8 +75,8 @@ Run an existing copy of mux if found, otherwise install from npm: module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.3" + agent_id = coder_agent.main.id use_cached = true } ``` @@ -87,8 +89,8 @@ Run without installing from the network (requires mux to be pre-installed): module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.4" + agent_id = coder_agent.main.id install = false } ``` diff --git a/registry/coder/modules/personalize/README.md b/registry/coder/modules/personalize/README.md index 2e70eccb..70426593 100644 --- a/registry/coder/modules/personalize/README.md +++ b/registry/coder/modules/personalize/README.md @@ -14,7 +14,7 @@ Run a script on workspace start that allows developers to run custom commands to module "personalize" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/personalize/coder" - version = "1.0.31" - agent_id = coder_agent.example.id + version = "1.0.32" + agent_id = coder_agent.main.id } ``` diff --git a/registry/coder/modules/rstudio-server/README.md b/registry/coder/modules/rstudio-server/README.md index 3bae5434..4492329d 100644 --- a/registry/coder/modules/rstudio-server/README.md +++ b/registry/coder/modules/rstudio-server/README.md @@ -19,7 +19,7 @@ Deploy the Rocker Project distribution of RStudio Server in your Coder workspace module "rstudio-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/rstudio-server/coder" - version = "0.9.0" - agent_id = coder_agent.example.id + version = "0.9.1" + agent_id = coder_agent.main.id } ``` diff --git a/registry/coder/modules/slackme/README.md b/registry/coder/modules/slackme/README.md index 999ab71f..d09f7c3d 100644 --- a/registry/coder/modules/slackme/README.md +++ b/registry/coder/modules/slackme/README.md @@ -14,7 +14,7 @@ Add the `slackme` command to your workspace that DMs you on Slack when your comm module "slackme" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/slackme/coder" - version = "1.0.31" + version = "1.0.33" agent_id = coder_agent.example.id auth_provider_id = "slack" } @@ -74,7 +74,7 @@ slackme npm run long-build module "slackme" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/slackme/coder" - version = "1.0.31" + version = "1.0.33" agent_id = coder_agent.example.id auth_provider_id = "slack" slack_message = < [!CAUTION] > We do not recommend using this module directly. Instead, please consider using one of our [Desktop IDE modules](https://registry.coder.com/modules?search=tag%3Aide). -The VSCode Desktop Core module is a building block for modules that need to expose access to VSCode-based IDEs. It is intended primarily to be used as a library to create modules for VSCode-based IDEs. +The VSCode Desktop Core module is a building block for modules that need to expose access to VSCode-based IDEs. It is intended primarily for internal use by Coder to create modules for VSCode-based IDEs. ```tf module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.0" + version = "1.0.1" agent_id = var.agent_id - coder_app_icon = "/icon/code.svg" - coder_app_slug = "vscode" - coder_app_display_name = "VS Code Desktop" - coder_app_order = var.order - coder_app_group = var.group + web_app_icon = "/icon/code.svg" + web_app_slug = "vscode" + web_app_display_name = "VS Code Desktop" + web_app_order = var.order + web_app_group = var.group folder = var.folder open_recent = var.open_recent diff --git a/registry/coder/modules/vscode-desktop-core/main.test.ts b/registry/coder/modules/vscode-desktop-core/main.test.ts index 6777b1d5..46c51227 100644 --- a/registry/coder/modules/vscode-desktop-core/main.test.ts +++ b/registry/coder/modules/vscode-desktop-core/main.test.ts @@ -10,9 +10,11 @@ const appName = "vscode-desktop"; const defaultVariables = { agent_id: "foo", - coder_app_icon: "/icon/code.svg", - coder_app_slug: "vscode", - coder_app_display_name: "VS Code Desktop", + + web_app_icon: "/icon/code.svg", + web_app_slug: "vscode", + web_app_display_name: "VS Code Desktop", + protocol: "vscode", }; @@ -21,80 +23,115 @@ describe("vscode-desktop-core", async () => { testRequiredVariables(import.meta.dir, defaultVariables); - it("default output", async () => { - const state = await runTerraformApply(import.meta.dir, defaultVariables); - expect(state.outputs.ide_uri.value).toBe( - `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, - ); + describe("coder_app", () => { + describe("IDE URI attributes", () => { + it("default output", async () => { + const state = await runTerraformApply( + import.meta.dir, + defaultVariables, + ); + expect(state.outputs.ide_uri.value).toBe( + `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, + ); - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === appName, - ); + const coder_app = state.resources.find( + (res) => res.type === "coder_app" && res.name === appName, + ); - expect(coder_app).not.toBeNull(); - expect(coder_app?.instances.length).toBe(1); - expect(coder_app?.instances[0].attributes.order).toBeNull(); - }); + expect(coder_app).not.toBeNull(); + expect(coder_app?.instances.length).toBe(1); + expect(coder_app?.instances[0].attributes.order).toBeNull(); + }); - it("adds folder", async () => { - const state = await runTerraformApply(import.meta.dir, { - folder: "/foo/bar", + it("adds folder", async () => { + const state = await runTerraformApply(import.meta.dir, { + folder: "/foo/bar", - ...defaultVariables, + ...defaultVariables, + }); + + expect(state.outputs.ide_uri.value).toBe( + `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, + ); + }); + + it("adds folder and open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + folder: "/foo/bar", + open_recent: "true", + + ...defaultVariables, + }); + expect(state.outputs.ide_uri.value).toBe( + `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, + ); + }); + + it("adds folder but not open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + folder: "/foo/bar", + openRecent: "false", + + ...defaultVariables, + }); + expect(state.outputs.ide_uri.value).toBe( + `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, + ); + }); + + it("adds open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + open_recent: "true", + + ...defaultVariables, + }); + expect(state.outputs.ide_uri.value).toBe( + `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, + ); + }); }); - expect(state.outputs.ide_uri.value).toBe( - `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, - ); - }); + it("sets custom slug and display_name", async () => { + const state = await runTerraformApply(import.meta.dir, defaultVariables); - it("adds folder and open_recent", async () => { - const state = await runTerraformApply(import.meta.dir, { - folder: "/foo/bar", - open_recent: "true", + const coder_app = state.resources.find( + (res) => res.type === "coder_app" && res.name === appName, + ); - ...defaultVariables, - }); - expect(state.outputs.ide_uri.value).toBe( - `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, - ); - }); - - it("adds folder but not open_recent", async () => { - const state = await runTerraformApply(import.meta.dir, { - folder: "/foo/bar", - openRecent: "false", - - ...defaultVariables, - }); - expect(state.outputs.ide_uri.value).toBe( - `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, - ); - }); - - it("adds open_recent", async () => { - const state = await runTerraformApply(import.meta.dir, { - open_recent: "true", - - ...defaultVariables, - }); - expect(state.outputs.ide_uri.value).toBe( - `${defaultVariables.protocol}://coder.coder-remote/open?owner=default&workspace=default&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN`, - ); - }); - - it("expect order to be set", async () => { - const state = await runTerraformApply(import.meta.dir, { - coder_app_order: "22", - ...defaultVariables, + expect(coder_app?.instances[0].attributes.slug).toBe( + defaultVariables.web_app_slug, + ); + expect(coder_app?.instances[0].attributes.display_name).toBe( + defaultVariables.web_app_display_name, + ); }); - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === appName, - ); + it("sets order", async () => { + const state = await runTerraformApply(import.meta.dir, { + web_app_order: "5", - expect(coder_app).not.toBeNull(); - expect(coder_app?.instances.length).toBe(1); - expect(coder_app?.instances[0].attributes.order).toBe(22); + ...defaultVariables, + }); + + const coder_app = state.resources.find( + (res) => res.type === "coder_app" && res.name === appName, + ); + + expect(coder_app?.instances[0].attributes.order).toBe(5); + }); + + it("sets group", async () => { + const state = await runTerraformApply(import.meta.dir, { + web_app_group: "web-app-group", + + ...defaultVariables, + }); + + const coder_app = state.resources.find( + (res) => res.type === "coder_app" && res.name === appName, + ); + + expect(coder_app?.instances[0].attributes.group).toBe("web-app-group"); + }); }); }); diff --git a/registry/coder/modules/vscode-desktop-core/main.tf b/registry/coder/modules/vscode-desktop-core/main.tf index 3bed8e79..7e675712 100644 --- a/registry/coder/modules/vscode-desktop-core/main.tf +++ b/registry/coder/modules/vscode-desktop-core/main.tf @@ -28,31 +28,31 @@ variable "open_recent" { variable "protocol" { type = string - description = "The URI protocol for the IDE." + description = "The URI protocol the IDE." } -variable "coder_app_icon" { +variable "web_app_icon" { type = string description = "The icon of the coder_app." } -variable "coder_app_slug" { +variable "web_app_slug" { type = string description = "The slug of the coder_app." } -variable "coder_app_display_name" { +variable "web_app_display_name" { type = string description = "The display name of the coder_app." } -variable "coder_app_order" { +variable "web_app_order" { type = number description = "The order of the coder_app." default = null } -variable "coder_app_group" { +variable "web_app_group" { type = string description = "The group of the coder_app." default = null @@ -65,25 +65,38 @@ resource "coder_app" "vscode-desktop" { agent_id = var.agent_id external = true - icon = var.coder_app_icon - slug = var.coder_app_slug - display_name = var.coder_app_display_name + icon = var.web_app_icon + slug = var.web_app_slug + display_name = var.web_app_display_name - order = var.coder_app_order - group = var.coder_app_group + order = var.web_app_order + group = var.web_app_group - # While the call to "join" is not strictly necessary, it makes the URL more readable. url = join("", [ - "${var.protocol}://coder.coder-remote/open", + var.protocol, + "://coder.coder-remote/open", + "?owner=", + data.coder_workspace_owner.me.name, + "&workspace=", + data.coder_workspace.me.name, + var.folder != "" ? join("", ["&folder=", var.folder]) : "", + var.open_recent ? "&openRecent" : "", + "&url=", + data.coder_workspace.me.access_url, + "&token=$SESSION_TOKEN", + ]) + + /* + url = join("", [ + "vscode://coder.coder-remote/open", "?owner=${data.coder_workspace_owner.me.name}", "&workspace=${data.coder_workspace.me.name}", var.folder != "" ? join("", ["&folder=", var.folder]) : "", var.open_recent ? "&openRecent" : "", "&url=${data.coder_workspace.me.access_url}", - # NOTE: There is a protocol whitelist for the token replacement, so this will only work with the protocols hardcoded in the front-end. - # (https://github.com/coder/coder/blob/6ba4b5bbc95e2e528d7f5b1e31fffa200ae1a6db/site/src/modules/apps/apps.ts#L18) "&token=$SESSION_TOKEN", ]) + */ } output "ide_uri" { diff --git a/registry/coder/modules/vscode-desktop/README.md b/registry/coder/modules/vscode-desktop/README.md index 23f02bfe..56f39bf7 100644 --- a/registry/coder/modules/vscode-desktop/README.md +++ b/registry/coder/modules/vscode-desktop/README.md @@ -16,8 +16,8 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "vscode" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-desktop/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.2.0" + agent_id = coder_agent.main.id } ``` @@ -29,8 +29,8 @@ module "vscode" { module "vscode" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-desktop/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.2.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` diff --git a/registry/coder/modules/vscode-desktop/main.test.ts b/registry/coder/modules/vscode-desktop/main.test.ts index b59ef5dc..3c1321b9 100644 --- a/registry/coder/modules/vscode-desktop/main.test.ts +++ b/registry/coder/modules/vscode-desktop/main.test.ts @@ -22,7 +22,10 @@ describe("vscode-desktop", async () => { ); const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "vscode", + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", ); expect(coder_app).not.toBeNull(); @@ -71,19 +74,4 @@ describe("vscode-desktop", async () => { "vscode://coder.coder-remote/open?owner=default&workspace=default&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", ); }); - - it("expect order to be set", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - order: "22", - }); - - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "vscode", - ); - - expect(coder_app).not.toBeNull(); - expect(coder_app?.instances.length).toBe(1); - expect(coder_app?.instances[0].attributes.order).toBe(22); - }); }); diff --git a/registry/coder/modules/vscode-desktop/main.tf b/registry/coder/modules/vscode-desktop/main.tf index f93d14e3..c9e6dd35 100644 --- a/registry/coder/modules/vscode-desktop/main.tf +++ b/registry/coder/modules/vscode-desktop/main.tf @@ -38,33 +38,24 @@ variable "group" { default = null } -data "coder_workspace" "me" {} -data "coder_workspace_owner" "me" {} +module "vscode-desktop-core" { + source = "registry.coder.com/coder/vscode-desktop-core/coder" + version = "1.0.0" -resource "coder_app" "vscode" { - agent_id = var.agent_id - external = true - icon = "/icon/code.svg" - slug = "vscode" - display_name = "VS Code Desktop" - order = var.order - group = var.group + agent_id = var.agent_id - url = join("", [ - "vscode://coder.coder-remote/open", - "?owner=", - data.coder_workspace_owner.me.name, - "&workspace=", - data.coder_workspace.me.name, - var.folder != "" ? join("", ["&folder=", var.folder]) : "", - var.open_recent ? "&openRecent" : "", - "&url=", - data.coder_workspace.me.access_url, - "&token=$SESSION_TOKEN", - ]) + coder_app_icon = "/icon/code.svg" + coder_app_slug = "vscode" + coder_app_display_name = "VS Code Desktop" + coder_app_order = var.order + coder_app_group = var.group + + folder = var.folder + open_recent = var.open_recent + protocol = "vscode" } output "vscode_url" { - value = coder_app.vscode.url + value = module.vscode-desktop-core.ide_uri description = "VS Code Desktop URL." -} +} \ No newline at end of file diff --git a/registry/coder/modules/vscode-web/README.md b/registry/coder/modules/vscode-web/README.md index d4ca481e..43b1eb9d 100644 --- a/registry/coder/modules/vscode-web/README.md +++ b/registry/coder/modules/vscode-web/README.md @@ -14,7 +14,7 @@ Automatically install [Visual Studio Code Server](https://code.visualstudio.com/ module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.4.1" + version = "1.4.3" agent_id = coder_agent.example.id accept_license = true } @@ -30,7 +30,7 @@ module "vscode-web" { module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.4.1" + version = "1.4.3" agent_id = coder_agent.example.id install_prefix = "/home/coder/.vscode-web" folder = "/home/coder" @@ -44,7 +44,7 @@ module "vscode-web" { module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.4.1" + version = "1.4.3" agent_id = coder_agent.example.id extensions = ["github.copilot", "ms-python.python", "ms-toolsai.jupyter"] accept_license = true @@ -59,7 +59,7 @@ Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarte module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.4.1" + version = "1.4.3" agent_id = coder_agent.example.id extensions = ["dracula-theme.theme-dracula"] settings = { @@ -77,7 +77,7 @@ By default, this module installs the latest. To pin a specific version, retrieve module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.4.1" + version = "1.4.3" agent_id = coder_agent.example.id commit_id = "e54c774e0add60467559eb0d1e229c6452cf8447" accept_license = true @@ -93,7 +93,7 @@ Note: Either `workspace` or `folder` can be used, but not both simultaneously. T module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.4.1" + version = "1.4.3" agent_id = coder_agent.example.id workspace = "/home/coder/coder.code-workspace" } diff --git a/registry/coder/modules/vscode-web/run.sh b/registry/coder/modules/vscode-web/run.sh index 6711819f..57bb760f 100644 --- a/registry/coder/modules/vscode-web/run.sh +++ b/registry/coder/modules/vscode-web/run.sh @@ -94,6 +94,7 @@ printf "$${BOLD}VS Code Web has been installed.\n" # Install each extension... IFS=',' read -r -a EXTENSIONLIST <<< "$${EXTENSIONS}" +# shellcheck disable=SC2066 for extension in "$${EXTENSIONLIST[@]}"; do if [ -z "$extension" ]; then continue diff --git a/registry/coder/modules/windows-rdp/README.md b/registry/coder/modules/windows-rdp/README.md index 92c5ac17..111e8d7f 100644 --- a/registry/coder/modules/windows-rdp/README.md +++ b/registry/coder/modules/windows-rdp/README.md @@ -16,7 +16,7 @@ module "windows_rdp" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windows-rdp/coder" version = "1.3.0" - agent_id = resource.coder_agent.main.id + agent_id = coder_agent.main.id } ``` @@ -33,7 +33,7 @@ module "windows_rdp" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windows-rdp/coder" version = "1.3.0" - agent_id = resource.coder_agent.main.id + agent_id = coder_agent.main.id } ``` @@ -44,7 +44,7 @@ module "windows_rdp" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windows-rdp/coder" version = "1.3.0" - agent_id = resource.coder_agent.main.id + agent_id = coder_agent.main.id } ``` @@ -55,7 +55,7 @@ module "windows_rdp" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windows-rdp/coder" version = "1.3.0" - agent_id = resource.coder_agent.main.id + agent_id = coder_agent.main.id devolutions_gateway_version = "2025.2.2" # Specify a specific version } ``` diff --git a/registry/coder/modules/windsurf/README.md b/registry/coder/modules/windsurf/README.md index e727cf11..77c57d40 100644 --- a/registry/coder/modules/windsurf/README.md +++ b/registry/coder/modules/windsurf/README.md @@ -16,8 +16,8 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "windsurf" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windsurf/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.3.0" + agent_id = coder_agent.main.id } ``` @@ -29,8 +29,8 @@ module "windsurf" { module "windsurf" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windsurf/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.3.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -45,8 +45,8 @@ The following example configures Windsurf to use the GitHub MCP server with auth module "windsurf" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windsurf/coder" - version = "1.2.0" - agent_id = coder_agent.example.id + version = "1.3.0" + agent_id = coder_agent.main.id folder = "/home/coder/project" mcp = jsonencode({ mcpServers = { @@ -57,6 +57,8 @@ module "windsurf" { }, "type" : "http" } + + } }) } diff --git a/registry/coder/modules/windsurf/main.test.ts b/registry/coder/modules/windsurf/main.test.ts index f5aa5e1f..27e61039 100644 --- a/registry/coder/modules/windsurf/main.test.ts +++ b/registry/coder/modules/windsurf/main.test.ts @@ -26,7 +26,10 @@ describe("windsurf", async () => { ); const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "windsurf", + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", ); expect(coder_app).not.toBeNull(); @@ -76,21 +79,6 @@ describe("windsurf", async () => { ); }); - it("expect order to be set", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - order: 22, - }); - - const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "windsurf", - ); - - expect(coder_app).not.toBeNull(); - expect(coder_app?.instances.length).toBe(1); - expect(coder_app?.instances[0].attributes.order).toBe(22); - }); - it("writes ~/.codeium/windsurf/mcp_config.json when mcp provided", async () => { const id = await runContainer("alpine"); try { diff --git a/registry/coder/modules/windsurf/main.tf b/registry/coder/modules/windsurf/main.tf index b75f8638..3ec29d5b 100644 --- a/registry/coder/modules/windsurf/main.tf +++ b/registry/coder/modules/windsurf/main.tf @@ -16,7 +16,7 @@ variable "agent_id" { variable "folder" { type = string - description = "The folder to open in Cursor IDE." + description = "The folder to open in Windsurf Editor." default = "" } @@ -63,26 +63,21 @@ locals { mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : "" } -resource "coder_app" "windsurf" { - agent_id = var.agent_id - external = true - icon = "/icon/windsurf.svg" - slug = var.slug - display_name = var.display_name - order = var.order - group = var.group - url = join("", [ - "windsurf://coder.coder-remote/open", - "?owner=", - data.coder_workspace_owner.me.name, - "&workspace=", - data.coder_workspace.me.name, - var.folder != "" ? join("", ["&folder=", var.folder]) : "", - var.open_recent ? "&openRecent" : "", - "&url=", - data.coder_workspace.me.access_url, - "&token=$SESSION_TOKEN", - ]) +module "vscode-desktop-core" { + source = "registry.coder.com/coder/vscode-desktop-core/coder" + version = "1.0.0" + + agent_id = var.agent_id + + coder_app_icon = "/icon/windsurf.svg" + coder_app_slug = "windsurf" + coder_app_display_name = "Windsurf Editor" + coder_app_order = var.order + coder_app_group = var.group + + folder = var.folder + open_recent = var.open_recent + protocol = "windsurf" } resource "coder_script" "windsurf_mcp" { @@ -102,6 +97,6 @@ resource "coder_script" "windsurf_mcp" { } output "windsurf_url" { - value = coder_app.windsurf.url + value = module.vscode-desktop-core.ide_uri description = "Windsurf Editor URL." -} +} \ No newline at end of file diff --git a/registry/coder/modules/zed/README.md b/registry/coder/modules/zed/README.md index 132e489c..e4615d55 100644 --- a/registry/coder/modules/zed/README.md +++ b/registry/coder/modules/zed/README.md @@ -19,8 +19,8 @@ Zed is a high-performance, multiplayer code editor from the creators of Atom and module "zed" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/zed/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.1.2" + agent_id = coder_agent.main.id } ``` @@ -32,8 +32,8 @@ module "zed" { module "zed" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/zed/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.1.2" + agent_id = coder_agent.main.id folder = "/home/coder/project" } ``` @@ -44,8 +44,8 @@ module "zed" { module "zed" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/zed/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.1.2" + agent_id = coder_agent.main.id display_name = "Zed Editor" order = 1 } @@ -57,8 +57,8 @@ module "zed" { module "zed" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/zed/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.1.2" + agent_id = coder_agent.main.id agent_name = coder_agent.example.name } ``` @@ -73,8 +73,8 @@ You can declaratively set/merge settings with the `settings` input. Provide a JS module "zed" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/zed/coder" - version = "1.1.1" - agent_id = coder_agent.example.id + version = "1.1.2" + agent_id = coder_agent.main.id settings = jsonencode({ context_servers = { @@ -84,6 +84,7 @@ module "zed" { args = ["arg-1", "arg-2"] env = {} } + } }) } diff --git a/registry/coder/templates/azure-windows/main.tf b/registry/coder/templates/azure-windows/main.tf index b7623be5..1d5dc657 100644 --- a/registry/coder/templates/azure-windows/main.tf +++ b/registry/coder/templates/azure-windows/main.tf @@ -36,7 +36,7 @@ module "windows_rdp" { admin_username = local.admin_username admin_password = random_password.admin_password.result - agent_id = resource.coder_agent.main.id + agent_id = coder_agent.main.id agent_name = "main" resource_id = null # Unused, to be removed in a future version } diff --git a/registry/cytoshahar/.images/avatar.jpeg b/registry/cytoshahar/.images/avatar.jpeg new file mode 100644 index 00000000..3e82d763 Binary files /dev/null and b/registry/cytoshahar/.images/avatar.jpeg differ diff --git a/registry/cytoshahar/README.md b/registry/cytoshahar/README.md new file mode 100644 index 00000000..14d45ea6 --- /dev/null +++ b/registry/cytoshahar/README.md @@ -0,0 +1,12 @@ +--- +display_name: "CytoShahar" +bio: "Data engineer by day, maker by night" +avatar: "./.images/avatar.jpeg" +github: "https://github.com/CytoShahar" +linkedin: "https://www.linkedin.com/in/shaharzrihen" # Optional +status: "community" +--- + +# Shahar Zrihen + +Data engineer by day, maker by night diff --git a/registry/cytoshahar/modules/positron/README.md b/registry/cytoshahar/modules/positron/README.md new file mode 100644 index 00000000..6de557be --- /dev/null +++ b/registry/cytoshahar/modules/positron/README.md @@ -0,0 +1,38 @@ +--- +display_name: Positron Desktop +description: Add a one-click button to launch Positron Desktop +icon: ../../../../.icons/positron.svg +verified: true +tags: [ide, positron] +--- + +# Positron Desktop + +Add a button to open any workspace with a single click. + +Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder). + +```tf +module "positron" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/cytoshahar/positron/coder" + version = "1.0.0" + agent_id = coder_agent.main.id +} +``` + +## Examples + +### Open in a specific directory + +```tf +module "positron" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/cytoshahar/positron/coder" + version = "1.0.1" + agent_id = coder_agent.main.id + folder = "/home/coder/project" +} +``` + +Based on the [Coder VS Code Desktop Module](https://github.com/coder/registry/tree/main/registry/coder/modules/vscode-desktop) diff --git a/registry/cytoshahar/modules/positron/main.test.ts b/registry/cytoshahar/modules/positron/main.test.ts new file mode 100644 index 00000000..fd1c5815 --- /dev/null +++ b/registry/cytoshahar/modules/positron/main.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, it } from "bun:test"; +import { + runTerraformApply, + runTerraformInit, + testRequiredVariables, +} from "~test"; + +describe("positron-desktop", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, { + agent_id: "foo", + }); + + it("default output", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + }); + expect(state.outputs.positron_url.value).toBe( + "positron://coder.coder-remote/open?owner=default&workspace=default&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + + const coder_app = state.resources.find( + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", + ); + + expect(coder_app).not.toBeNull(); + expect(coder_app?.instances.length).toBe(1); + expect(coder_app?.instances[0].attributes.order).toBeNull(); + }); + + it("adds folder", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + folder: "/foo/bar", + }); + expect(state.outputs.positron_url.value).toBe( + "positron://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("adds folder and open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + folder: "/foo/bar", + open_recent: "true", + }); + expect(state.outputs.positron_url.value).toBe( + "positron://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("adds folder but not open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + folder: "/foo/bar", + openRecent: "false", + }); + expect(state.outputs.positron_url.value).toBe( + "positron://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("adds open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + open_recent: "true", + }); + expect(state.outputs.positron_url.value).toBe( + "positron://coder.coder-remote/open?owner=default&workspace=default&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); +}); diff --git a/registry/cytoshahar/modules/positron/main.tf b/registry/cytoshahar/modules/positron/main.tf new file mode 100644 index 00000000..9365b444 --- /dev/null +++ b/registry/cytoshahar/modules/positron/main.tf @@ -0,0 +1,76 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.5" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "folder" { + type = string + description = "The folder to open in Positron." + default = "" +} + +variable "open_recent" { + type = bool + description = "Open the most recent workspace or folder. Falls back to the folder if there is no recent workspace or folder to open." + default = false +} + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} + +variable "group" { + type = string + description = "The name of a group that this app belongs to." + default = null +} + +variable "slug" { + type = string + description = "The slug of the app." + default = "cursor" +} + +variable "display_name" { + type = string + description = "The display name of the app." + default = "Cursor Desktop" +} + +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +module "vscode-desktop-core" { + source = "registry.coder.com/coder/vscode-desktop-core/coder" + version = "1.0.0" + + agent_id = var.agent_id + + coder_app_icon = "/icon/positron.svg" + coder_app_slug = var.slug + coder_app_display_name = var.display_name + coder_app_order = var.order + coder_app_group = var.group + + folder = var.folder + open_recent = var.open_recent + protocol = "positron" +} + +output "positron_url" { + value = module.vscode-desktop-core.ide_uri + description = "Positron Desktop URL." +} diff --git a/registry/djarbz/modules/copyparty/README.md b/registry/djarbz/modules/copyparty/README.md index 1209f852..85dce9b7 100644 --- a/registry/djarbz/modules/copyparty/README.md +++ b/registry/djarbz/modules/copyparty/README.md @@ -17,7 +17,7 @@ This module installs Copyparty, an alternative to Filebrowser. module "copyparty" { count = data.coder_workspace.me.start_count source = "registry.coder.com/djarbz/copyparty/coder" - version = "1.0.1" + version = "1.0.2" } ``` @@ -35,7 +35,7 @@ Some basic command line options: module "copyparty" { count = data.coder_workspace.me.start_count source = "registry.coder.com/djarbz/copyparty/coder" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.example.id arguments = [ "-v", "/home/coder/:/home:r", # Share home directory (read-only) @@ -51,7 +51,7 @@ module "copyparty" { module "copyparty" { count = data.coder_workspace.me.start_count source = "registry.coder.com/djarbz/copyparty/coder" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.example.id subdomain = true arguments = [ diff --git a/registry/djarbz/modules/copyparty/run.sh b/registry/djarbz/modules/copyparty/run.sh index 99388759..b5ee2b72 100755 --- a/registry/djarbz/modules/copyparty/run.sh +++ b/registry/djarbz/modules/copyparty/run.sh @@ -12,6 +12,7 @@ PINNED_VERSION="${PINNED_VERSION}" # Custom CLI Arguments # The variable from Terraform is a series of quoted and space separated strings. # We need to parse it into a proper bash array. +# shellcheck disable=SC2206 ARGUMENTS=(${ARGUMENTS}) # VARIABLE appears unused. Verify use (or export if used externally). diff --git a/registry/mavrickrishi/modules/auto-start-dev-server/README.md b/registry/mavrickrishi/modules/auto-start-dev-server/README.md index 432b453f..b9d91128 100644 --- a/registry/mavrickrishi/modules/auto-start-dev-server/README.md +++ b/registry/mavrickrishi/modules/auto-start-dev-server/README.md @@ -13,7 +13,7 @@ Automatically detect and start development servers for various project types whe ```tf module "auto_start_dev_servers" { source = "registry.coder.com/mavrickrishi/auto-start-dev-server/coder" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id } ``` @@ -51,7 +51,7 @@ module "auto_start_dev_servers" { ```tf module "auto_start" { source = "./modules/auto-start-dev-server" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id } ``` @@ -61,7 +61,7 @@ module "auto_start" { ```tf module "auto_start_dev_servers" { source = "./modules/auto-start-dev-server" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id # Optional: Configure which project types to detect @@ -100,7 +100,7 @@ module "auto_start_dev_servers" { ```tf module "auto_start" { source = "./modules/auto-start-dev-server" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id # Disable automatic preview app creation @@ -113,7 +113,7 @@ module "auto_start" { ```tf module "auto_start" { source = "./modules/auto-start-dev-server" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id # Only enable web development projects @@ -136,7 +136,7 @@ module "auto_start" { ```tf module "auto_start" { source = "./modules/auto-start-dev-server" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id workspace_directory = "/workspaces" diff --git a/registry/mavrickrishi/modules/auto-start-dev-server/run.sh b/registry/mavrickrishi/modules/auto-start-dev-server/run.sh index d0386e74..846bf2fd 100755 --- a/registry/mavrickrishi/modules/auto-start-dev-server/run.sh +++ b/registry/mavrickrishi/modules/auto-start-dev-server/run.sh @@ -50,13 +50,20 @@ is_frontend_project() { # Check package.json for frontend dependencies if [ -f "$project_dir/package.json" ] && command -v jq &> /dev/null; then # Check for common frontend frameworks - local has_react=$(jq '.dependencies.react // .devDependencies.react // empty' "$project_dir/package.json") - local has_vue=$(jq '.dependencies.vue // .devDependencies.vue // empty' "$project_dir/package.json") - local has_angular=$(jq '.dependencies["@angular/core"] // .devDependencies["@angular/core"] // empty' "$project_dir/package.json") - local has_next=$(jq '.dependencies.next // .devDependencies.next // empty' "$project_dir/package.json") - local has_nuxt=$(jq '.dependencies.nuxt // .devDependencies.nuxt // empty' "$project_dir/package.json") - local has_svelte=$(jq '.dependencies.svelte // .devDependencies.svelte // empty' "$project_dir/package.json") - local has_vite=$(jq '.dependencies.vite // .devDependencies.vite // empty' "$project_dir/package.json") + local has_react + has_react=$(jq '.dependencies.react // .devDependencies.react // empty' "$project_dir/package.json") + local has_vue + has_vue=$(jq '.dependencies.vue // .devDependencies.vue // empty' "$project_dir/package.json") + local has_angular + has_angular=$(jq '.dependencies["@angular/core"] // .devDependencies["@angular/core"] // empty' "$project_dir/package.json") + local has_next + has_next=$(jq '.dependencies.next // .devDependencies.next // empty' "$project_dir/package.json") + local has_nuxt + has_nuxt=$(jq '.dependencies.nuxt // .devDependencies.nuxt // empty' "$project_dir/package.json") + local has_svelte + has_svelte=$(jq '.dependencies.svelte // .devDependencies.svelte // empty' "$project_dir/package.json") + local has_vite + has_vite=$(jq '.dependencies.vite // .devDependencies.vite // empty' "$project_dir/package.json") if [ -n "$has_react" ] || [ -n "$has_vue" ] || [ -n "$has_angular" ] \ || [ -n "$has_next" ] || [ -n "$has_nuxt" ] || [ -n "$has_svelte" ] \ @@ -118,7 +125,8 @@ add_detected_project() { fi # Create JSON entry for this project - local project_json=$(jq -n \ + local project_json + project_json=$(jq -n \ --arg dir "$project_dir" \ --arg type "$project_type" \ --arg port "$port" \ diff --git a/registry/mavrickrishi/modules/nexus-repository/README.md b/registry/mavrickrishi/modules/nexus-repository/README.md index 6bf5431c..1e33e031 100644 --- a/registry/mavrickrishi/modules/nexus-repository/README.md +++ b/registry/mavrickrishi/modules/nexus-repository/README.md @@ -13,8 +13,8 @@ Configure package managers (Maven, npm, Go, PyPI, Docker) to use [Sonatype Nexus ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { @@ -24,6 +24,7 @@ module "nexus_repository" { pypi = ["pypi-public", "pypi-private"] docker = ["docker-public", "docker-private"] } + } ``` @@ -43,13 +44,14 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { maven = ["maven-public", "maven-releases", "maven-snapshots"] } + } ``` @@ -58,13 +60,14 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { npm = ["npm-public", "@mycompany:npm-private"] } + } ``` @@ -73,13 +76,14 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { go = ["go-public", "go-private"] } + } ``` @@ -88,13 +92,14 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { pypi = ["pypi-public", "pypi-private"] } + } ``` @@ -103,13 +108,14 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { docker = ["docker-public", "docker-private"] } + } ``` @@ -118,14 +124,15 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_username = "custom-user" nexus_password = var.nexus_api_token package_managers = { maven = ["maven-public"] } + } ``` @@ -134,8 +141,8 @@ module "nexus_repository" { ```tf module "nexus_repository" { source = "registry.coder.com/mavrickrishi/nexus-repository/coder" - version = "1.0.1" - agent_id = coder_agent.example.id + version = "1.0.2" + agent_id = coder_agent.main.id nexus_url = "https://nexus.example.com" nexus_password = var.nexus_api_token package_managers = { @@ -145,5 +152,6 @@ module "nexus_repository" { pypi = ["pypi-public", "pypi-private"] docker = ["docker-public", "docker-private"] } + } ``` diff --git a/registry/thezoker/modules/nodejs/README.md b/registry/thezoker/modules/nodejs/README.md index 27533b47..d7293aac 100644 --- a/registry/thezoker/modules/nodejs/README.md +++ b/registry/thezoker/modules/nodejs/README.md @@ -15,7 +15,7 @@ Automatically installs [Node.js](https://github.com/nodejs/node) via [`nvm`](htt module "nodejs" { count = data.coder_workspace.me.start_count source = "registry.coder.com/thezoker/nodejs/coder" - version = "1.0.11" + version = "1.0.13" agent_id = coder_agent.example.id } ``` @@ -28,14 +28,14 @@ This installs multiple versions of Node.js: module "nodejs" { count = data.coder_workspace.me.start_count source = "registry.coder.com/thezoker/nodejs/coder" - version = "1.0.11" + version = "1.0.13" agent_id = coder_agent.example.id node_versions = [ "18", "20", "node" ] - default_node_version = "20" + default_node_version = "1.0.13" } ``` @@ -47,15 +47,15 @@ A example with all available options: module "nodejs" { count = data.coder_workspace.me.start_count source = "registry.coder.com/thezoker/nodejs/coder" - version = "1.0.11" + version = "1.0.13" agent_id = coder_agent.example.id - nvm_version = "v0.39.7" + nvm_version = "1.0.13" nvm_install_prefix = "/opt/nvm" node_versions = [ "16", "18", "node" ] - default_node_version = "16" + default_node_version = "1.0.13" } ``` diff --git a/registry/thezoker/modules/nodejs/run.sh b/registry/thezoker/modules/nodejs/run.sh index 78e940a7..31044eb5 100644 --- a/registry/thezoker/modules/nodejs/run.sh +++ b/registry/thezoker/modules/nodejs/run.sh @@ -32,6 +32,7 @@ printf "🥳 nvm has been installed\n\n" # Install each node version... IFS=',' read -r -a VERSIONLIST <<< "$${NODE_VERSIONS}" +# shellcheck disable=SC2066 for version in "$${VERSIONLIST[@]}"; do if [ -z "$version" ]; then continue @@ -45,6 +46,7 @@ for version in "$${VERSIONLIST[@]}"; do done # Set default if provided +# shellcheck disable=SC2157 if [ -n "$${DEFAULT}" ]; then printf "🛠️ Setting default node version $${CODE}$DEFAULT$${RESET}...\n" output=$(nvm alias default $DEFAULT 2>&1) diff --git a/scripts/new_module.sh b/scripts/new_module.sh index 63333848..df32ba15 100755 --- a/scripts/new_module.sh +++ b/scripts/new_module.sh @@ -57,7 +57,7 @@ mkdir -p "registry/${NAMESPACE}/modules/${MODULE_NAME}" cp -r examples/modules/* "registry/${NAMESPACE}/modules/${MODULE_NAME}/" # Change to module directory -cd "registry/${NAMESPACE}/modules/${MODULE_NAME}" +cd "registry/${NAMESPACE}/modules/${MODULE_NAME}" || exit # Detect OS if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/scripts/new_template.sh b/scripts/new_template.sh index b06d108b..eda0481e 100755 --- a/scripts/new_template.sh +++ b/scripts/new_template.sh @@ -58,7 +58,7 @@ mkdir -p "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}" cp -r examples/templates/* "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}/" # Change to template directory -cd "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}" +cd "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}" || exit # Detect OS and replace placeholders if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/scripts/shellcheck_validate.sh b/scripts/shellcheck_validate.sh new file mode 100755 index 00000000..59fd9ac7 --- /dev/null +++ b/scripts/shellcheck_validate.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Auto-detect which shell scripts to validate based on changed files from paths-filter +# Uses paths-filter outputs from GitHub Actions: +# ALL_CHANGED_FILES - all files changed in the PR (for logging) +# SHARED_CHANGED - boolean indicating if shared infrastructure changed +# SHELL_CHANGED_FILES - only .sh files (for processing) +# Validates all shell scripts if shared infrastructure changes +# +# This script validates all shell scripts across the repository + +validate_shell_script() { + local file="$1" + echo "Validating $file" + + # Run shellcheck with warning severity level + # Using gcc format for better IDE/editor integration + if ! shellcheck --severity=warning --format=gcc "$file"; then + return 1 + fi + return 0 +} + +main() { + echo "==> Detecting changed files..." + + if [[ -n "${ALL_CHANGED_FILES:-}" ]]; then + echo "Changed files in PR:" + echo "$ALL_CHANGED_FILES" | tr ' ' '\n' | sed 's/^/ - /' + echo "" + fi + + # Determine which files to check + local files_to_check=() + + if [[ "${SHARED_CHANGED:-false}" == "true" ]]; then + echo "==> Shared infrastructure changed" + echo "==> Validating all shell scripts for safety" + + # Find all .sh files in the repository, excluding node_modules, .git, and .terraform + mapfile -t files_to_check < <(find . -type f -name "*.sh" ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/.terraform/*" | sort) + elif [[ -z "${SHELL_CHANGED_FILES:-}" ]]; then + echo "✓ No shell script files changed, skipping validation" + exit 0 + else + # Process only changed shell scripts + CHANGED_FILES=$(echo "$SHELL_CHANGED_FILES" | tr ' ' '\n') + + while IFS= read -r file; do + if [[ -f "$file" && "$file" == *.sh ]]; then + files_to_check+=("$file") + fi + done <<< "$CHANGED_FILES" + fi + + if [[ ${#files_to_check[@]} -eq 0 ]]; then + echo "✓ No shell scripts to validate" + exit 0 + fi + + echo "==> Validating ${#files_to_check[@]} shell script(s):" + for file in "${files_to_check[@]}"; do + echo " - $file" + done + echo "" + + # Validate each file + local status=0 + local failed_files=() + + for file in "${files_to_check[@]}"; do + if ! validate_shell_script "$file"; then + status=1 + failed_files+=("$file") + fi + done + + # Report results + if [[ $status -eq 0 ]]; then + echo "" + echo "✓ All shell scripts passed validation" + else + echo "" + echo "❌ ShellCheck validation failed for ${#failed_files[@]} file(s):" + for file in "${failed_files[@]}"; do + echo " - $file" + done + fi + + exit $status +} + +main diff --git a/scripts/terraform_test_all.sh b/scripts/terraform_test_all.sh index 2da60d63..8cc47830 100755 --- a/scripts/terraform_test_all.sh +++ b/scripts/terraform_test_all.sh @@ -45,7 +45,7 @@ else module="${BASH_REMATCH[2]}" module_dir="registry/${namespace}/modules/${module}" - if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " ${module_dir} " ]]; then + if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " $module_dir " ]]; then MODULE_DIRS+=("$module_dir") fi fi @@ -67,7 +67,7 @@ else for module_dir in "${MODULE_DIRS[@]}"; do while IFS= read -r test_file; do test_dir=$(dirname "$test_file") - if [[ ! " ${test_dirs[*]} " =~ " ${test_dir} " ]]; then + if [[ ! " ${test_dirs[*]} " =~ " $test_dir " ]]; then test_dirs+=("$test_dir") fi done < <(find "$module_dir" -type f -name "*.tftest.hcl") diff --git a/scripts/terraform_validate.sh b/scripts/terraform_validate.sh index 5eb75f63..9126e28e 100755 --- a/scripts/terraform_validate.sh +++ b/scripts/terraform_validate.sh @@ -29,13 +29,16 @@ main() { echo "" fi - local script_dir=$(dirname "$(readlink -f "$0")") - local registry_dir=$(readlink -f "$script_dir/../registry") + local script_dir + script_dir=$(dirname "$(readlink -f "$0")") + local registry_dir + registry_dir=$(readlink -f "$script_dir/../registry") if [[ "${SHARED_CHANGED:-false}" == "true" ]]; then echo "==> Shared infrastructure changed" echo "==> Validating all modules for safety" - local subdirs=$(find "$registry_dir" -mindepth 3 -maxdepth 3 -path "*/modules/*" -type d | sort) + local subdirs + subdirs=$(find "$registry_dir" -mindepth 3 -maxdepth 3 -path "*/modules/*" -type d | sort) elif [[ -z "${MODULE_CHANGED_FILES:-}" ]]; then echo "✓ No module files changed, skipping validation" exit 0 @@ -49,11 +52,14 @@ main() { fi if [[ "$file" =~ ^registry/([^/]+)/modules/([^/]+)/ ]]; then + local namespace namespace="${BASH_REMATCH[1]}" + local module module="${BASH_REMATCH[2]}" + local module_dir module_dir="registry/${namespace}/modules/${module}" - if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " ${module_dir} " ]]; then + if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " $module_dir " ]]; then MODULE_DIRS+=("$module_dir") fi fi diff --git a/scripts/ts_test_auto.sh b/scripts/ts_test_auto.sh index 5f28e338..ecb8e7a2 100755 --- a/scripts/ts_test_auto.sh +++ b/scripts/ts_test_auto.sh @@ -42,7 +42,7 @@ while IFS= read -r file; do module="${BASH_REMATCH[2]}" module_dir="registry/${namespace}/modules/${module}" - if [[ -f "$module_dir/main.test.ts" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " ${module_dir} " ]]; then + if [[ -f "$module_dir/main.test.ts" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " $module_dir " ]]; then MODULE_DIRS+=("$module_dir") fi fi diff --git a/scripts/validate_set_u_order.sh b/scripts/validate_set_u_order.sh new file mode 100755 index 00000000..ea2e0270 --- /dev/null +++ b/scripts/validate_set_u_order.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +set -eo pipefail + +# Validates that shell scripts source external files BEFORE enabling 'set -u' +# This prevents failures when sourced files (like /etc/bashrc) reference undefined variables +# +# Background: When 'set -u' is active, any reference to undefined variables causes the script to exit. +# System files like /etc/bashrc may reference variables (like $EUID) that aren't set in the script context. +# +# Correct pattern: +# #!/bin/bash +# source "$HOME/.bashrc" # Source first +# set -euo pipefail # Then enable strict mode +# +# Incorrect pattern: +# #!/bin/bash +# set -euo pipefail # set -u enabled first +# source "$HOME/.bashrc" # This may fail if bashrc references undefined vars + +echo "==> Validating 'set -u' usage order in shell scripts..." + +# Track if we found any issues +found_issues=0 +total_checked=0 + +# Find all shell scripts +while IFS= read -r file; do + # Skip if file doesn't exist (should not happen, but be safe) + [[ -f "$file" ]] || continue + + # Check if file has both 'set -u' and 'source'/'.' + # Look for: set -u, set -eu, set -euo, set -uo, etc. + # Only check for sourcing common system/user files that might have undefined variables + if grep -q "^set -[a-z]*u" "$file" && grep -q -E "^\s*(source|\.)\s+.*(\\\$HOME/\.bashrc|/etc/bashrc|/etc/os-release)" "$file"; then + total_checked=$((total_checked + 1)) + + # Get the first occurrence of each pattern with line numbers + set_u_line=$(grep -n "^set -[a-z]*u" "$file" | head -1 | cut -d: -f1) + source_line=$(grep -n -E "^\s*(source|\.)\s+.*(\\\$HOME/\.bashrc|/etc/bashrc|/etc/os-release)" "$file" | head -1 | cut -d: -f1) + + # Check if set -u comes before source (which is problematic) + if [[ "$set_u_line" -lt "$source_line" ]]; then + echo "ERROR: $file" + echo " 'set -u' at line $set_u_line comes before 'source' at line $source_line" + echo " This may cause failures when sourcing system files with undefined variables." + echo "" + found_issues=$((found_issues + 1)) + fi + fi +done < <(find registry -name "*.sh" -type f ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/.terraform/*" | sort) + +# Report results +if [[ $found_issues -gt 0 ]]; then + echo "================================================================" + echo "FAILED: Found $found_issues script(s) with incorrect 'set -u' order" + echo "" + echo "Fix: Move 'source' statements BEFORE 'set -u' to prevent failures" + echo "Example:" + echo " #!/bin/bash" + echo " source \"\$HOME/.bashrc\" # Source first" + echo " set -euo pipefail # Then enable strict mode" + echo "" + echo "See: SHELLCHECK_RESEARCH_REPORT.md for detailed analysis" + echo "================================================================" + exit 1 +fi + +if [[ $total_checked -eq 0 ]]; then + echo "No scripts found with both 'set -u' and 'source' statements" +else + echo "All $total_checked script(s) have correct 'set -u' ordering" +fi diff --git a/test/test.ts b/test/test.ts index 6851f8de..7a956205 100644 --- a/test/test.ts +++ b/test/test.ts @@ -112,6 +112,8 @@ type JsonValue = | { [key: string]: JsonValue }; type TerraformStateResource = { + module: string; + mode: string; type: string; name: string; provider: string;