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
}
```
+
+
## 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;