chore: improve Prettier configuration (#392)

This commit is contained in:
Atif Ali
2025-08-27 01:57:43 +05:00
committed by GitHub
parent 6bebc02122
commit 62951f1fca
48 changed files with 627 additions and 485 deletions
+2 -2
View File
@@ -192,8 +192,8 @@ main() {
# Always run formatter to ensure consistent formatting # Always run formatter to ensure consistent formatting
echo "🔧 Running formatter to ensure consistent formatting..." echo "🔧 Running formatter to ensure consistent formatting..."
if command -v bun >/dev/null 2>&1; then if command -v bun > /dev/null 2>&1; then
bun fmt >/dev/null 2>&1 || echo "⚠️ Warning: bun fmt failed, but continuing..." bun fmt > /dev/null 2>&1 || echo "⚠️ Warning: bun fmt failed, but continuing..."
else else
echo "⚠️ Warning: bun not found, skipping formatting" echo "⚠️ Warning: bun not found, skipping formatting"
fi fi
+22
View File
@@ -0,0 +1,22 @@
# Ignore symlinks to avoid Prettier errors
CLAUDE.md
.github/copilot-instructions.md
# Ignore node_modules and dependencies
node_modules/
# Ignore Terraform files (formatted by terraform fmt)
*.tf
*.hcl
*.tfvars
# Ignore generated and temporary files
.terraform/
*.tfstate
*.tfstate.backup
*.tfstate.lock.info
# Ignore other files that shouldn't be formatted
bun.lock
go.sum
go.mod
+6 -6
View File
@@ -4,11 +4,11 @@
"": { "": {
"name": "registry", "name": "registry",
"devDependencies": { "devDependencies": {
"@types/bun": "^1.2.18", "@types/bun": "^1.2.21",
"bun-types": "^1.2.18", "bun-types": "^1.2.21",
"dedent": "^1.6.0", "dedent": "^1.6.0",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"marked": "^16.0.0", "marked": "^16.2.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"prettier-plugin-sh": "^0.18.0", "prettier-plugin-sh": "^0.18.0",
"prettier-plugin-terraform-formatter": "^1.2.1", "prettier-plugin-terraform-formatter": "^1.2.1",
@@ -21,7 +21,7 @@
"packages": { "packages": {
"@reteps/dockerfmt": ["@reteps/dockerfmt@0.3.6", "", {}, "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg=="], "@reteps/dockerfmt": ["@reteps/dockerfmt@0.3.6", "", {}, "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg=="],
"@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="], "@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/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
@@ -29,7 +29,7 @@
"argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
"bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="], "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
@@ -47,7 +47,7 @@
"kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
"marked": ["marked@16.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-MUKMXDjsD/eptB7GPzxo4xcnLS6oo7/RHimUMHEDRhUooPwmN9BEpMl7AEOJv3bmso169wHI2wUF9VQgL7zfmA=="], "marked": ["marked@16.2.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg=="],
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
+5 -5
View File
@@ -1,18 +1,18 @@
{ {
"name": "registry", "name": "registry",
"scripts": { "scripts": {
"fmt": "bun x prettier --write **/*.sh **/*.ts **/*.md *.md && terraform fmt -recursive -diff", "fmt": "bun x prettier --write . && terraform fmt -recursive -diff",
"fmt:ci": "bun x prettier --check **/*.sh **/*.ts **/*.md *.md && terraform fmt -check -recursive -diff", "fmt:ci": "bun x prettier --check . && terraform fmt -check -recursive -diff",
"terraform-validate": "./scripts/terraform_validate.sh", "terraform-validate": "./scripts/terraform_validate.sh",
"test": "./scripts/terraform_test_all.sh", "test": "./scripts/terraform_test_all.sh",
"update-version": "./update-version.sh" "update-version": "./update-version.sh"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.2.18", "@types/bun": "^1.2.21",
"bun-types": "^1.2.18", "bun-types": "^1.2.21",
"dedent": "^1.6.0", "dedent": "^1.6.0",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"marked": "^16.0.0", "marked": "^16.2.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"prettier-plugin-sh": "^0.18.0", "prettier-plugin-sh": "^0.18.0",
"prettier-plugin-terraform-formatter": "^1.2.1" "prettier-plugin-terraform-formatter": "^1.2.1"
+3 -1
View File
@@ -28,7 +28,9 @@ describe("tmux module", async () => {
// check that the script contains expected lines // check that the script contains expected lines
expect(scriptResource.script).toContain("Installing tmux"); expect(scriptResource.script).toContain("Installing tmux");
expect(scriptResource.script).toContain("Installing Tmux Plugin Manager (TPM)"); expect(scriptResource.script).toContain(
"Installing Tmux Plugin Manager (TPM)",
);
expect(scriptResource.script).toContain("tmux configuration created at"); expect(scriptResource.script).toContain("tmux configuration created at");
expect(scriptResource.script).toContain("✅ tmux setup complete!"); expect(scriptResource.script).toContain("✅ tmux setup complete!");
}); });
@@ -16,7 +16,7 @@ handle_session() {
local session_name="$1" local session_name="$1"
# Check if the session exists # Check if the session exists
if tmux has-session -t "$session_name" 2>/dev/null; then if tmux has-session -t "$session_name" 2> /dev/null; then
echo "Session '$session_name' exists, attaching to it..." echo "Session '$session_name' exists, attaching to it..."
tmux attach-session -t "$session_name" tmux attach-session -t "$session_name"
else else
@@ -165,9 +165,9 @@ describe("auggie", async () => {
mcpServers: { mcpServers: {
test: { test: {
command: "test-cmd", command: "test-cmd",
type: "stdio" type: "stdio",
} },
} },
}); });
const { id } = await setup({ const { id } = await setup({
moduleVariables: { moduleVariables: {
@@ -193,7 +193,10 @@ describe("auggie", async () => {
}); });
await execModuleScript(id); await execModuleScript(id);
const rulesFile = await readFileContainer(id, "/home/coder/.augment/rules.md"); const rulesFile = await readFileContainer(
id,
"/home/coder/.augment/rules.md",
);
expect(rulesFile).toContain(rules); expect(rulesFile).toContain(rules);
}); });
@@ -314,7 +317,10 @@ describe("auggie", async () => {
}); });
await execModuleScript(id); await execModuleScript(id);
const mcpConfig = await readFileContainer(id, "/home/coder/.augment/coder_mcp.json"); const mcpConfig = await readFileContainer(
id,
"/home/coder/.augment/coder_mcp.json",
);
expect(mcpConfig).toContain("mcpServers"); expect(mcpConfig).toContain("mcpServers");
expect(mcpConfig).toContain("coder"); expect(mcpConfig).toContain("coder");
expect(mcpConfig).toContain("CODER_MCP_APP_STATUS_SLUG"); expect(mcpConfig).toContain("CODER_MCP_APP_STATUS_SLUG");
@@ -25,7 +25,6 @@ printf "rules: %s\n" "$ARG_AUGGIE_RULES"
echo "--------------------------------" echo "--------------------------------"
function check_dependencies() { function check_dependencies() {
if ! command_exists node; then if ! command_exists node; then
printf "Error: Node.js is not installed. Please install Node.js manually or use the pre_install_script to install it.\n" printf "Error: Node.js is not installed. Please install Node.js manually or use the pre_install_script to install it.\n"
@@ -72,7 +71,6 @@ function install_auggie() {
fi fi
} }
function create_coder_mcp() { function create_coder_mcp() {
AUGGIE_CODER_MCP_FILE="$HOME/.augment/coder_mcp.json" AUGGIE_CODER_MCP_FILE="$HOME/.augment/coder_mcp.json"
CODER_MCP=$( CODER_MCP=$(
@@ -39,7 +39,6 @@ printf "report_tasks: %s\n" "$ARG_REPORT_TASKS"
echo "--------------------------------" echo "--------------------------------"
function validate_auggie_installation() { function validate_auggie_installation() {
if command_exists auggie; then if command_exists auggie; then
printf "Auggie is installed\n" printf "Auggie is installed\n"
+12 -9
View File
@@ -124,8 +124,8 @@ describe("codex", async () => {
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.codex/config.toml"); const resp = await readFileContainer(id, "/home/coder/.codex/config.toml");
expect(resp).toContain("sandbox_mode = \"danger-full-access\""); expect(resp).toContain('sandbox_mode = "danger-full-access"');
expect(resp).toContain("preferred_auth_method = \"apikey\""); expect(resp).toContain('preferred_auth_method = "apikey"');
expect(resp).toContain("[custom_section]"); expect(resp).toContain("[custom_section]");
expect(resp).toContain("[mcp_servers.Coder]"); expect(resp).toContain("[mcp_servers.Coder]");
}); });
@@ -246,11 +246,11 @@ describe("codex", async () => {
const resp = await readFileContainer(id, "/home/coder/.codex/config.toml"); const resp = await readFileContainer(id, "/home/coder/.codex/config.toml");
// Check base config // Check base config
expect(resp).toContain("sandbox_mode = \"read-only\""); expect(resp).toContain('sandbox_mode = "read-only"');
expect(resp).toContain("preferred_auth_method = \"chatgpt\""); expect(resp).toContain('preferred_auth_method = "chatgpt"');
expect(resp).toContain("custom_setting = \"test-value\""); expect(resp).toContain('custom_setting = "test-value"');
expect(resp).toContain("[advanced_settings]"); expect(resp).toContain("[advanced_settings]");
expect(resp).toContain("logging_level = \"verbose\""); expect(resp).toContain('logging_level = "verbose"');
// Check MCP servers // Check MCP servers
expect(resp).toContain("[mcp_servers.Coder]"); expect(resp).toContain("[mcp_servers.Coder]");
@@ -270,8 +270,8 @@ describe("codex", async () => {
const resp = await readFileContainer(id, "/home/coder/.codex/config.toml"); const resp = await readFileContainer(id, "/home/coder/.codex/config.toml");
// Check default base config // Check default base config
expect(resp).toContain("sandbox_mode = \"workspace-write\""); expect(resp).toContain('sandbox_mode = "workspace-write"');
expect(resp).toContain("approval_policy = \"never\""); expect(resp).toContain('approval_policy = "never"');
expect(resp).toContain("[sandbox_workspace_write]"); expect(resp).toContain("[sandbox_workspace_write]");
expect(resp).toContain("network_access = true"); expect(resp).toContain("network_access = true");
@@ -328,7 +328,10 @@ describe("codex", async () => {
}, },
}); });
await execModuleScript(id_2); await execModuleScript(id_2);
const resp_2 = await readFileContainer(id_2, "/home/coder/.codex/AGENTS.md"); const resp_2 = await readFileContainer(
id_2,
"/home/coder/.codex/AGENTS.md",
);
expect(resp_2).toContain(prompt_1); expect(resp_2).toContain(prompt_1);
const count = (resp_2.match(new RegExp(prompt_1, "g")) || []).length; const count = (resp_2.match(new RegExp(prompt_1, "g")) || []).length;
expect(count).toBe(1); expect(count).toBe(1);
@@ -55,8 +55,6 @@ if [ -n "$ARG_CODEX_MODEL" ]; then
CODEX_ARGS+=("--model" "$ARG_CODEX_MODEL") CODEX_ARGS+=("--model" "$ARG_CODEX_MODEL")
fi fi
if [ -n "$ARG_CODEX_TASK_PROMPT" ]; then if [ -n "$ARG_CODEX_TASK_PROMPT" ]; then
printf "Running the task prompt %s\n" "$ARG_CODEX_TASK_PROMPT" printf "Running the task prompt %s\n" "$ARG_CODEX_TASK_PROMPT"
PROMPT="Complete the task at hand in one go. Every step of the way, report your progress using coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_CODEX_TASK_PROMPT" PROMPT="Complete the task at hand in one go. Every step of the way, report your progress using coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_CODEX_TASK_PROMPT"
@@ -65,7 +63,6 @@ else
printf "No task prompt given.\n" printf "No task prompt given.\n"
fi fi
# Terminal dimensions optimized for Coder Tasks UI sidebar: # Terminal dimensions optimized for Coder Tasks UI sidebar:
# - Width 67: fits comfortably in sidebar # - Width 67: fits comfortably in sidebar
# - Height 1190: adjusted due to Codex terminal height bug # - Height 1190: adjusted due to Codex terminal height bug
@@ -1,12 +1,22 @@
import { afterEach, beforeAll, describe, expect, setDefaultTimeout, test } from "bun:test"; import {
afterEach,
beforeAll,
describe,
expect,
setDefaultTimeout,
test,
} from "bun:test";
import { execContainer, runTerraformInit, writeFileContainer } from "~test"; import { execContainer, runTerraformInit, writeFileContainer } from "~test";
import { import {
execModuleScript, execModuleScript,
expectAgentAPIStarted, expectAgentAPIStarted,
loadTestFile, loadTestFile,
setup as setupUtil setup as setupUtil,
} from "../../../coder/modules/agentapi/test-util";
import {
setupContainer,
writeExecutable,
} from "../../../coder/modules/agentapi/test-util"; } from "../../../coder/modules/agentapi/test-util";
import { setupContainer, writeExecutable } from "../../../coder/modules/agentapi/test-util";
let cleanupFns: (() => Promise<void>)[] = []; let cleanupFns: (() => Promise<void>)[] = [];
const registerCleanup = (fn: () => Promise<void>) => cleanupFns.push(fn); const registerCleanup = (fn: () => Promise<void>) => cleanupFns.push(fn);
@@ -72,11 +82,12 @@ describe("cursor-cli", async () => {
}); });
test("agentapi-mcp-json", async () => { test("agentapi-mcp-json", async () => {
const mcpJson = '{"mcpServers": {"test": {"command": "test-cmd", "type": "stdio"}}}'; const mcpJson =
'{"mcpServers": {"test": {"command": "test-cmd", "type": "stdio"}}}';
const { id } = await setup({ const { id } = await setup({
moduleVariables: { moduleVariables: {
mcp: mcpJson, mcp: mcpJson,
} },
}); });
const resp = await execModuleScript(id); const resp = await execModuleScript(id);
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
@@ -99,7 +110,7 @@ describe("cursor-cli", async () => {
const { id } = await setup({ const { id } = await setup({
moduleVariables: { moduleVariables: {
rules_files: JSON.stringify({ "typescript.md": rulesContent }), rules_files: JSON.stringify({ "typescript.md": rulesContent }),
} },
}); });
const resp = await execModuleScript(id); const resp = await execModuleScript(id);
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
@@ -118,7 +129,7 @@ describe("cursor-cli", async () => {
const { id } = await setup({ const { id } = await setup({
moduleVariables: { moduleVariables: {
api_key: apiKey, api_key: apiKey,
} },
}); });
const resp = await execModuleScript(id); const resp = await execModuleScript(id);
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
@@ -138,7 +149,7 @@ describe("cursor-cli", async () => {
model: model, model: model,
force: "true", force: "true",
ai_prompt: "test prompt", ai_prompt: "test prompt",
} },
}); });
const resp = await execModuleScript(id); const resp = await execModuleScript(id);
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
@@ -158,7 +169,7 @@ describe("cursor-cli", async () => {
moduleVariables: { moduleVariables: {
pre_install_script: "#!/bin/bash\necho 'cursor-pre-install-script'", pre_install_script: "#!/bin/bash\necho 'cursor-pre-install-script'",
post_install_script: "#!/bin/bash\necho 'cursor-post-install-script'", post_install_script: "#!/bin/bash\necho 'cursor-post-install-script'",
} },
}); });
const resp = await execModuleScript(id); const resp = await execModuleScript(id);
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
@@ -183,7 +194,7 @@ describe("cursor-cli", async () => {
const { id } = await setup({ const { id } = await setup({
moduleVariables: { moduleVariables: {
folder: folder, folder: folder,
} },
}); });
const resp = await execModuleScript(id); const resp = await execModuleScript(id);
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
@@ -205,8 +216,5 @@ describe("cursor-cli", async () => {
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
await expectAgentAPIStarted(id); await expectAgentAPIStarted(id);
}) });
}); });
+42 -11
View File
@@ -127,7 +127,10 @@ describe("gemini", async () => {
}, },
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.gemini/settings.json"); const resp = await readFileContainer(
id,
"/home/coder/.gemini/settings.json",
);
expect(resp).toContain("foo"); expect(resp).toContain("foo");
expect(resp).toContain("bar"); expect(resp).toContain("bar");
}); });
@@ -141,7 +144,10 @@ describe("gemini", async () => {
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log"); const resp = await readFileContainer(
id,
"/home/coder/.gemini-module/agentapi-start.log",
);
expect(resp).toContain("Using direct Gemini API with API key"); expect(resp).toContain("Using direct Gemini API with API key");
}); });
@@ -153,8 +159,11 @@ describe("gemini", async () => {
}, },
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log"); const resp = await readFileContainer(
expect(resp).toContain('GOOGLE_GENAI_USE_VERTEXAI=\'true\''); id,
"/home/coder/.gemini-module/agentapi-start.log",
);
expect(resp).toContain("GOOGLE_GENAI_USE_VERTEXAI='true'");
}); });
test("gemini-model", async () => { test("gemini-model", async () => {
@@ -166,7 +175,10 @@ describe("gemini", async () => {
}, },
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log"); const resp = await readFileContainer(
id,
"/home/coder/.gemini-module/agentapi-start.log",
);
expect(resp).toContain(model); expect(resp).toContain(model);
}); });
@@ -178,9 +190,15 @@ describe("gemini", async () => {
}, },
}); });
await execModuleScript(id); await execModuleScript(id);
const preInstallLog = await readFileContainer(id, "/home/coder/.gemini-module/pre_install.log"); const preInstallLog = await readFileContainer(
id,
"/home/coder/.gemini-module/pre_install.log",
);
expect(preInstallLog).toContain("pre-install-script"); expect(preInstallLog).toContain("pre-install-script");
const postInstallLog = await readFileContainer(id, "/home/coder/.gemini-module/post_install.log"); const postInstallLog = await readFileContainer(
id,
"/home/coder/.gemini-module/post_install.log",
);
expect(postInstallLog).toContain("post-install-script"); expect(postInstallLog).toContain("post-install-script");
}); });
@@ -193,7 +211,10 @@ describe("gemini", async () => {
}, },
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log"); const resp = await readFileContainer(
id,
"/home/coder/.gemini-module/agentapi-start.log",
);
expect(resp).toContain(folder); expect(resp).toContain(folder);
}); });
@@ -205,7 +226,10 @@ describe("gemini", async () => {
}, },
}); });
await execModuleScript(id); await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.gemini/settings.json"); const resp = await readFileContainer(
id,
"/home/coder/.gemini/settings.json",
);
expect(resp).toContain("custom"); expect(resp).toContain("custom");
expect(resp).toContain("enabled"); expect(resp).toContain("enabled");
}); });
@@ -232,14 +256,21 @@ describe("gemini", async () => {
await execModuleScript(id, { await execModuleScript(id, {
GEMINI_TASK_PROMPT: taskPrompt, GEMINI_TASK_PROMPT: taskPrompt,
}); });
const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log"); const resp = await readFileContainer(
id,
"/home/coder/.gemini-module/agentapi-start.log",
);
expect(resp).toContain("Running automated task:"); expect(resp).toContain("Running automated task:");
}); });
test("start-without-prompt", async () => { test("start-without-prompt", async () => {
const { id } = await setup(); const { id } = await setup();
await execModuleScript(id); await execModuleScript(id);
const prompt = await execContainer(id, ["ls", "-l", "/home/coder/GEMINI.md"]); const prompt = await execContainer(id, [
"ls",
"-l",
"/home/coder/GEMINI.md",
]);
expect(prompt.exitCode).not.toBe(0); expect(prompt.exitCode).not.toBe(0);
expect(prompt.stderr).toContain("No such file or directory"); expect(prompt.stderr).toContain("No such file or directory");
}); });
+14 -6
View File
@@ -164,7 +164,9 @@ describe("agentapi", async () => {
id, id,
"/home/coder/test-agentapi-start.log", "/home/coder/test-agentapi-start.log",
); );
expect(agentApiStartLog).toContain("Using AGENTAPI_CHAT_BASE_PATH: /@default/default.foo/apps/agentapi-web/chat"); expect(agentApiStartLog).toContain(
"Using AGENTAPI_CHAT_BASE_PATH: /@default/default.foo/apps/agentapi-web/chat",
);
}); });
test("validate-agentapi-version", async () => { test("validate-agentapi-version", async () => {
@@ -186,14 +188,16 @@ describe("agentapi", async () => {
agentapi_version: "v0.0.1", agentapi_version: "v0.0.1",
agentapi_subdomain: "false", agentapi_subdomain: "false",
}, },
shouldThrow: "Running with subdomain = false is only supported by agentapi >= v0.3.3.", shouldThrow:
"Running with subdomain = false is only supported by agentapi >= v0.3.3.",
}, },
{ {
moduleVariables: { moduleVariables: {
agentapi_version: "v0.3.2", agentapi_version: "v0.3.2",
agentapi_subdomain: "false", agentapi_subdomain: "false",
}, },
shouldThrow: "Running with subdomain = false is only supported by agentapi >= v0.3.3.", shouldThrow:
"Running with subdomain = false is only supported by agentapi >= v0.3.3.",
}, },
{ {
moduleVariables: { moduleVariables: {
@@ -226,13 +230,17 @@ describe("agentapi", async () => {
agentapi_version: "arbitrary-string-bypasses-validation", agentapi_version: "arbitrary-string-bypasses-validation",
}, },
shouldThrow: "", shouldThrow: "",
} },
]; ];
for (const { moduleVariables, shouldThrow } of cases) { for (const { moduleVariables, shouldThrow } of cases) {
if (shouldThrow) { if (shouldThrow) {
expect(setup({ moduleVariables: moduleVariables as Record<string, string> })).rejects.toThrow(shouldThrow); expect(
setup({ moduleVariables: moduleVariables as Record<string, string> }),
).rejects.toThrow(shouldThrow);
} else { } else {
expect(setup({ moduleVariables: moduleVariables as Record<string, string> })).resolves.toBeDefined(); expect(
setup({ moduleVariables: moduleVariables as Record<string, string> }),
).resolves.toBeDefined();
} }
} }
}); });
@@ -17,7 +17,7 @@ AGENTAPI_CHAT_BASE_PATH="${ARG_AGENTAPI_CHAT_BASE_PATH:-}"
set +o nounset set +o nounset
command_exists() { command_exists() {
command -v "$1" >/dev/null 2>&1 command -v "$1" > /dev/null 2>&1
} }
module_path="$HOME/${MODULE_DIR_NAME}" module_path="$HOME/${MODULE_DIR_NAME}"
@@ -31,13 +31,13 @@ if [ ! -d "${WORKDIR}" ]; then
fi fi
if [ -n "${PRE_INSTALL_SCRIPT}" ]; then if [ -n "${PRE_INSTALL_SCRIPT}" ]; then
echo "Running pre-install script..." echo "Running pre-install script..."
echo -n "${PRE_INSTALL_SCRIPT}" >"$module_path/pre_install.sh" echo -n "${PRE_INSTALL_SCRIPT}" > "$module_path/pre_install.sh"
chmod +x "$module_path/pre_install.sh" chmod +x "$module_path/pre_install.sh"
"$module_path/pre_install.sh" 2>&1 | tee "$module_path/pre_install.log" "$module_path/pre_install.sh" 2>&1 | tee "$module_path/pre_install.log"
fi fi
echo "Running install script..." echo "Running install script..."
echo -n "${INSTALL_SCRIPT}" >"$module_path/install.sh" echo -n "${INSTALL_SCRIPT}" > "$module_path/install.sh"
chmod +x "$module_path/install.sh" chmod +x "$module_path/install.sh"
"$module_path/install.sh" 2>&1 | tee "$module_path/install.log" "$module_path/install.sh" 2>&1 | tee "$module_path/install.log"
@@ -77,14 +77,14 @@ if ! command_exists agentapi; then
exit 1 exit 1
fi fi
echo -n "${START_SCRIPT}" >"$module_path/scripts/agentapi-start.sh" echo -n "${START_SCRIPT}" > "$module_path/scripts/agentapi-start.sh"
echo -n "${WAIT_FOR_START_SCRIPT}" >"$module_path/scripts/agentapi-wait-for-start.sh" echo -n "${WAIT_FOR_START_SCRIPT}" > "$module_path/scripts/agentapi-wait-for-start.sh"
chmod +x "$module_path/scripts/agentapi-start.sh" chmod +x "$module_path/scripts/agentapi-start.sh"
chmod +x "$module_path/scripts/agentapi-wait-for-start.sh" chmod +x "$module_path/scripts/agentapi-wait-for-start.sh"
if [ -n "${POST_INSTALL_SCRIPT}" ]; then if [ -n "${POST_INSTALL_SCRIPT}" ]; then
echo "Running post-install script..." echo "Running post-install script..."
echo -n "${POST_INSTALL_SCRIPT}" >"$module_path/post_install.sh" echo -n "${POST_INSTALL_SCRIPT}" > "$module_path/post_install.sh"
chmod +x "$module_path/post_install.sh" chmod +x "$module_path/post_install.sh"
"$module_path/post_install.sh" 2>&1 | tee "$module_path/post_install.log" "$module_path/post_install.sh" 2>&1 | tee "$module_path/post_install.log"
fi fi
@@ -97,5 +97,5 @@ cd "${WORKDIR}"
export AGENTAPI_CHAT_BASE_PATH="${AGENTAPI_CHAT_BASE_PATH:-}" export AGENTAPI_CHAT_BASE_PATH="${AGENTAPI_CHAT_BASE_PATH:-}"
# Disable host header check since AgentAPI is proxied by Coder (which does its own validation) # Disable host header check since AgentAPI is proxied by Coder (which does its own validation)
export AGENTAPI_ALLOWED_HOSTS="*" export AGENTAPI_ALLOWED_HOSTS="*"
nohup "$module_path/scripts/agentapi-start.sh" true "${AGENTAPI_PORT}" &>"$module_path/agentapi-start.log" & nohup "$module_path/scripts/agentapi-start.sh" true "${AGENTAPI_PORT}" &> "$module_path/agentapi-start.log" &
"$module_path/scripts/agentapi-wait-for-start.sh" "${AGENTAPI_PORT}" "$module_path/scripts/agentapi-wait-for-start.sh" "${AGENTAPI_PORT}"
+9 -3
View File
@@ -25,14 +25,20 @@ export const setupContainer = async ({
const coderScript = findResourceInstance(state, "coder_script"); const coderScript = findResourceInstance(state, "coder_script");
const id = await runContainer(image ?? "codercom/enterprise-node:latest"); const id = await runContainer(image ?? "codercom/enterprise-node:latest");
return { return {
id, coderScript, cleanup: async () => { id,
if (process.env["DEBUG"] === "true" || process.env["DEBUG"] === "1" || process.env["DEBUG"] === "yes") { coderScript,
cleanup: async () => {
if (
process.env["DEBUG"] === "true" ||
process.env["DEBUG"] === "1" ||
process.env["DEBUG"] === "yes"
) {
console.log(`Not removing container ${id} in debug mode`); console.log(`Not removing container ${id} in debug mode`);
console.log(`Run "docker rm -f ${id}" to remove it manually.`); console.log(`Run "docker rm -f ${id}" to remove it manually.`);
} else { } else {
await removeContainer(id); await removeContainer(id);
} }
} },
}; };
}; };
+4 -1
View File
@@ -7,7 +7,10 @@ const portIdx = args.findIndex((arg) => arg === "--port") + 1;
const port = portIdx ? args[portIdx] : 3284; const port = portIdx ? args[portIdx] : 3284;
console.log(`starting server on port ${port}`); console.log(`starting server on port ${port}`);
fs.writeFileSync("/home/coder/agentapi-mock.log", `AGENTAPI_ALLOWED_HOSTS: ${process.env.AGENTAPI_ALLOWED_HOSTS}`); fs.writeFileSync(
"/home/coder/agentapi-mock.log",
`AGENTAPI_ALLOWED_HOSTS: ${process.env.AGENTAPI_ALLOWED_HOSTS}`,
);
http http
.createServer(function (_request, response) { .createServer(function (_request, response) {
+4 -4
View File
@@ -8,15 +8,15 @@ port=${2:-3284}
module_path="$HOME/.agentapi-module" module_path="$HOME/.agentapi-module"
log_file_path="$module_path/agentapi.log" log_file_path="$module_path/agentapi.log"
echo "using prompt: $use_prompt" >>/home/coder/test-agentapi-start.log echo "using prompt: $use_prompt" >> /home/coder/test-agentapi-start.log
echo "using port: $port" >>/home/coder/test-agentapi-start.log echo "using port: $port" >> /home/coder/test-agentapi-start.log
AGENTAPI_CHAT_BASE_PATH="${AGENTAPI_CHAT_BASE_PATH:-}" AGENTAPI_CHAT_BASE_PATH="${AGENTAPI_CHAT_BASE_PATH:-}"
if [ -n "$AGENTAPI_CHAT_BASE_PATH" ]; then if [ -n "$AGENTAPI_CHAT_BASE_PATH" ]; then
echo "Using AGENTAPI_CHAT_BASE_PATH: $AGENTAPI_CHAT_BASE_PATH" >>/home/coder/test-agentapi-start.log echo "Using AGENTAPI_CHAT_BASE_PATH: $AGENTAPI_CHAT_BASE_PATH" >> /home/coder/test-agentapi-start.log
export AGENTAPI_CHAT_BASE_PATH export AGENTAPI_CHAT_BASE_PATH
fi fi
agentapi server --port "$port" --term-width 67 --term-height 1190 -- \ agentapi server --port "$port" --term-width 67 --term-height 1190 -- \
bash -c aiagent \ bash -c aiagent \
>"$log_file_path" 2>&1 > "$log_file_path" 2>&1
@@ -22,7 +22,7 @@ fi
# see the remove-last-session-id.sh script for details # see the remove-last-session-id.sh script for details
# about why we need it # about why we need it
# avoid exiting if the script fails # avoid exiting if the script fails
bash "$scripts_dir/remove-last-session-id.sh" "$(pwd)" 2>/dev/null || true bash "$scripts_dir/remove-last-session-id.sh" "$(pwd)" 2> /dev/null || true
# we'll be manually handling errors from this point on # we'll be manually handling errors from this point on
set +o errexit set +o errexit
@@ -20,7 +20,10 @@ if (
process.exit(1); process.exit(1);
} }
fs.writeFileSync("/home/coder/agentapi-mock.log", `AGENTAPI_ALLOWED_HOSTS: ${process.env.AGENTAPI_ALLOWED_HOSTS}`); fs.writeFileSync(
"/home/coder/agentapi-mock.log",
`AGENTAPI_ALLOWED_HOSTS: ${process.env.AGENTAPI_ALLOWED_HOSTS}`,
);
console.log(`starting server on port ${port}`); console.log(`starting server on port ${port}`);
+8 -2
View File
@@ -94,12 +94,18 @@ describe("cursor", async () => {
it("writes ~/.cursor/mcp.json when mcp provided", async () => { it("writes ~/.cursor/mcp.json when mcp provided", async () => {
const id = await runContainer("alpine"); const id = await runContainer("alpine");
try { try {
const mcp = JSON.stringify({ servers: { demo: { url: "http://localhost:1234" } } }); const mcp = JSON.stringify({
servers: { demo: { url: "http://localhost:1234" } },
});
const state = await runTerraformApply(import.meta.dir, { const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo", agent_id: "foo",
mcp, mcp,
}); });
const script = findResourceInstance(state, "coder_script", "cursor_mcp").script; const script = findResourceInstance(
state,
"coder_script",
"cursor_mcp",
).script;
const resp = await execContainer(id, ["sh", "-c", script]); const resp = await execContainer(id, ["sh", "-c", script]);
if (resp.exitCode !== 0) { if (resp.exitCode !== 0) {
console.log(resp.stdout); console.log(resp.stdout);
@@ -7,22 +7,22 @@
cd "$CODER_SCRIPT_DATA_DIR" cd "$CODER_SCRIPT_DATA_DIR"
# If @devcontainers/cli is already installed, we can skip # If @devcontainers/cli is already installed, we can skip
if command -v devcontainer >/dev/null 2>&1; then if command -v devcontainer > /dev/null 2>&1; then
echo "🥳 @devcontainers/cli is already installed into $(which devcontainer)!" echo "🥳 @devcontainers/cli is already installed into $(which devcontainer)!"
exit 0 exit 0
fi fi
# Check if docker is installed # Check if docker is installed
if ! command -v docker >/dev/null 2>&1; then if ! command -v docker > /dev/null 2>&1; then
echo "WARNING: Docker was not found but is required to use @devcontainers/cli, please make sure it is available." echo "WARNING: Docker was not found but is required to use @devcontainers/cli, please make sure it is available."
fi fi
# Determine the package manager to use: npm, pnpm, or yarn # Determine the package manager to use: npm, pnpm, or yarn
if command -v yarn >/dev/null 2>&1; then if command -v yarn > /dev/null 2>&1; then
PACKAGE_MANAGER="yarn" PACKAGE_MANAGER="yarn"
elif command -v npm >/dev/null 2>&1; then elif command -v npm > /dev/null 2>&1; then
PACKAGE_MANAGER="npm" PACKAGE_MANAGER="npm"
elif command -v pnpm >/dev/null 2>&1; then elif command -v pnpm > /dev/null 2>&1; then
PACKAGE_MANAGER="pnpm" PACKAGE_MANAGER="pnpm"
else else
echo "ERROR: No supported package manager (npm, pnpm, yarn) is installed. Please install one first." 1>&2 echo "ERROR: No supported package manager (npm, pnpm, yarn) is installed. Please install one first." 1>&2
@@ -53,7 +53,7 @@ if ! install; then
exit 1 exit 1
fi fi
if ! command -v devcontainer >/dev/null 2>&1; then if ! command -v devcontainer > /dev/null 2>&1; then
echo "Installation completed but 'devcontainer' command not found in PATH" >&2 echo "Installation completed but 'devcontainer' command not found in PATH" >&2
exit 1 exit 1
fi fi
+2 -2
View File
@@ -7,7 +7,7 @@ BOLD='\033[[0;1m'
printf "$${BOLD}Installing filebrowser \n\n" printf "$${BOLD}Installing filebrowser \n\n"
# Check if filebrowser is installed # Check if filebrowser is installed
if ! command -v filebrowser &>/dev/null; then if ! command -v filebrowser &> /dev/null; then
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
fi fi
@@ -34,6 +34,6 @@ printf "👷 Starting filebrowser in background... \n\n"
printf "📂 Serving $${ROOT_DIR} at http://localhost:${PORT} \n\n" printf "📂 Serving $${ROOT_DIR} at http://localhost:${PORT} \n\n"
filebrowser >>${LOG_PATH} 2>&1 & filebrowser >> ${LOG_PATH} 2>&1 &
printf "📝 Logs at ${LOG_PATH} \n\n" printf "📝 Logs at ${LOG_PATH} \n\n"
+3 -1
View File
@@ -267,6 +267,8 @@ describe("goose", async () => {
await execModuleScript(id); await execModuleScript(id);
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog); const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain("AGENTAPI_CHAT_BASE_PATH=/@default/default.foo/apps/goose/chat"); expect(agentapiMockOutput).toContain(
"AGENTAPI_CHAT_BASE_PATH=/@default/default.foo/apps/goose/chat",
);
}); });
}); });
@@ -2,7 +2,7 @@
# Function to check if a command exists # Function to check if a command exists
command_exists() { command_exists() {
command -v "$1" >/dev/null 2>&1 command -v "$1" > /dev/null 2>&1
} }
set -o nounset set -o nounset
@@ -32,9 +32,9 @@ fi
if [ "${ARG_GOOSE_CONFIG}" != "" ]; then if [ "${ARG_GOOSE_CONFIG}" != "" ]; then
echo "Configuring Goose..." echo "Configuring Goose..."
mkdir -p "$HOME/.config/goose" mkdir -p "$HOME/.config/goose"
echo "GOOSE_PROVIDER: $ARG_PROVIDER" >"$HOME/.config/goose/config.yaml" echo "GOOSE_PROVIDER: $ARG_PROVIDER" > "$HOME/.config/goose/config.yaml"
echo "GOOSE_MODEL: $ARG_MODEL" >>"$HOME/.config/goose/config.yaml" echo "GOOSE_MODEL: $ARG_MODEL" >> "$HOME/.config/goose/config.yaml"
echo "$ARG_GOOSE_CONFIG" >>"$HOME/.config/goose/config.yaml" echo "$ARG_GOOSE_CONFIG" >> "$HOME/.config/goose/config.yaml"
else else
echo "Skipping Goose configuration" echo "Skipping Goose configuration"
fi fi
@@ -42,7 +42,7 @@ fi
if [ "${GOOSE_SYSTEM_PROMPT}" != "" ]; then if [ "${GOOSE_SYSTEM_PROMPT}" != "" ]; then
echo "Setting Goose system prompt..." echo "Setting Goose system prompt..."
mkdir -p "$HOME/.config/goose" mkdir -p "$HOME/.config/goose"
echo "$GOOSE_SYSTEM_PROMPT" >"$HOME/.config/goose/.goosehints" echo "$GOOSE_SYSTEM_PROMPT" > "$HOME/.config/goose/.goosehints"
else else
echo "Goose system prompt not set. use the GOOSE_SYSTEM_PROMPT environment variable to set it." echo "Goose system prompt not set. use the GOOSE_SYSTEM_PROMPT environment variable to set it."
fi fi
@@ -4,7 +4,7 @@ set -o errexit
set -o pipefail set -o pipefail
command_exists() { command_exists() {
command -v "$1" >/dev/null 2>&1 command -v "$1" > /dev/null 2>&1
} }
if command_exists goose; then if command_exists goose; then
@@ -24,7 +24,7 @@ if [ ! -z "$GOOSE_TASK_PROMPT" ]; then
echo "Starting with a prompt" echo "Starting with a prompt"
PROMPT="Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT" PROMPT="Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT"
PROMPT_FILE="$MODULE_DIR/prompt.txt" PROMPT_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" >"$PROMPT_FILE" echo -n "$PROMPT" > "$PROMPT_FILE"
GOOSE_ARGS=(run --interactive --instructions "$PROMPT_FILE") GOOSE_ARGS=(run --interactive --instructions "$PROMPT_FILE")
else else
echo "Starting without a prompt" echo "Starting without a prompt"
@@ -3,7 +3,9 @@
const http = require("http"); const http = require("http");
const args = process.argv.slice(2); const args = process.argv.slice(2);
console.log(args); console.log(args);
console.log(`AGENTAPI_CHAT_BASE_PATH=${process.env["AGENTAPI_CHAT_BASE_PATH"]}`); console.log(
`AGENTAPI_CHAT_BASE_PATH=${process.env["AGENTAPI_CHAT_BASE_PATH"]}`,
);
const port = 3284; const port = 3284;
console.log(`starting server on port ${port}`); console.log(`starting server on port ${port}`);
+13 -6
View File
@@ -115,22 +115,29 @@ describe("jupyterlab", async () => {
port: 8888, port: 8888,
token: "test-token", token: "test-token",
password: "", password: "",
allow_origin: "*" allow_origin: "*",
} },
}; };
const configJson = JSON.stringify(config); const configJson = JSON.stringify(config);
const state = await runTerraformApply(import.meta.dir, { const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo", agent_id: "foo",
config: configJson, config: configJson,
}); });
const script = findResourceInstance(state, "coder_script", "jupyterlab_config").script; const script = findResourceInstance(
state,
"coder_script",
"jupyterlab_config",
).script;
const resp = await execContainer(id, ["sh", "-c", script]); const resp = await execContainer(id, ["sh", "-c", script]);
if (resp.exitCode !== 0) { if (resp.exitCode !== 0) {
console.log(resp.stdout); console.log(resp.stdout);
console.log(resp.stderr); console.log(resp.stderr);
} }
expect(resp.exitCode).toBe(0); expect(resp.exitCode).toBe(0);
const content = await readFileContainer(id, "/root/.jupyter/jupyter_server_config.json"); const content = await readFileContainer(
id,
"/root/.jupyter/jupyter_server_config.json",
);
// Parse both JSON strings and compare objects to avoid key ordering issues // Parse both JSON strings and compare objects to avoid key ordering issues
const actualConfig = JSON.parse(content); const actualConfig = JSON.parse(content);
expect(actualConfig).toEqual(config); expect(actualConfig).toEqual(config);
@@ -145,7 +152,7 @@ describe("jupyterlab", async () => {
config: "{}", config: "{}",
}); });
const configScripts = state.resources.filter( const configScripts = state.resources.filter(
(res) => res.type === "coder_script" && res.name === "jupyterlab_config" (res) => res.type === "coder_script" && res.name === "jupyterlab_config",
); );
expect(configScripts.length).toBe(1); expect(configScripts.length).toBe(1);
}); });
@@ -155,7 +162,7 @@ describe("jupyterlab", async () => {
agent_id: "foo", agent_id: "foo",
}); });
const configScripts = state.resources.filter( const configScripts = state.resources.filter(
(res) => res.type === "coder_script" && res.name === "jupyterlab_config" (res) => res.type === "coder_script" && res.name === "jupyterlab_config",
); );
expect(configScripts.length).toBe(1); expect(configScripts.length).toBe(1);
}); });
+8 -8
View File
@@ -3,13 +3,13 @@ INSTALLER=""
check_available_installer() { check_available_installer() {
# check if pipx is installed # check if pipx is installed
echo "Checking for a supported installer" echo "Checking for a supported installer"
if command -v pipx >/dev/null 2>&1; then if command -v pipx > /dev/null 2>&1; then
echo "pipx is installed" echo "pipx is installed"
INSTALLER="pipx" INSTALLER="pipx"
return return
fi fi
# check if uv is installed # check if uv is installed
if command -v uv >/dev/null 2>&1; then if command -v uv > /dev/null 2>&1; then
echo "uv is installed" echo "uv is installed"
INSTALLER="uv" INSTALLER="uv"
return return
@@ -26,19 +26,19 @@ fi
BOLD='\033[0;1m' BOLD='\033[0;1m'
# check if jupyterlab is installed # check if jupyterlab is installed
if ! command -v jupyter-lab >/dev/null 2>&1; then if ! command -v jupyter-lab > /dev/null 2>&1; then
# install jupyterlab # install jupyterlab
check_available_installer check_available_installer
printf "$${BOLD}Installing jupyterlab!\n" printf "$${BOLD}Installing jupyterlab!\n"
case $INSTALLER in case $INSTALLER in
uv) uv)
uv pip install -q jupyterlab && uv pip install -q jupyterlab \
printf "%s\n" "🥳 jupyterlab has been installed" && printf "%s\n" "🥳 jupyterlab has been installed"
JUPYTER="$HOME/.venv/bin/jupyter-lab" JUPYTER="$HOME/.venv/bin/jupyter-lab"
;; ;;
pipx) pipx)
pipx install jupyterlab && pipx install jupyterlab \
printf "%s\n" "🥳 jupyterlab has been installed" && printf "%s\n" "🥳 jupyterlab has been installed"
JUPYTER="$HOME/.local/bin/jupyter-lab" JUPYTER="$HOME/.local/bin/jupyter-lab"
;; ;;
esac esac
@@ -55,4 +55,4 @@ $JUPYTER --no-browser \
--ServerApp.port="${PORT}" \ --ServerApp.port="${PORT}" \
--ServerApp.token='' \ --ServerApp.token='' \
--ServerApp.password='' \ --ServerApp.password='' \
>"${LOG_PATH}" 2>&1 & > "${LOG_PATH}" 2>&1 &
+52 -22
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<title>Path-Sharing Bounce Page</title> <title>Path-Sharing Bounce Page</title>
@@ -6,40 +6,64 @@
:root { :root {
color-scheme: light dark; color-scheme: light dark;
--dark: #121212; --dark: #121212;
--header-bg: rgba(127,127,127,0.2); --header-bg: rgba(127, 127, 127, 0.2);
--light: white; --light: white;
--rule-color: light-dark(rgba(0,0,0,0.8), rgba(255,255,255,0.8)); --rule-color: light-dark(rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0.8));
background-color: light-dark(var(--light), var(--dark)); background-color: light-dark(var(--light), var(--dark));
color: light-dark(var(--dark), var(--light)); color: light-dark(var(--dark), var(--light));
} }
body, h1, p { body,
h1,
p {
box-sizing: border-box; box-sizing: border-box;
margin:0; padding:0; margin: 0;
padding: 0;
} }
body{ body {
font-family:Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-family:
Inter,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Oxygen,
Ubuntu,
Cantarell,
"Open Sans",
"Helvetica Neue",
sans-serif;
} }
h1{ h1 {
width: 100%; width: 100%;
padding: 1rem; padding: 1rem;
letter-spacing: -1.5pt; letter-spacing: -1.5pt;
padding-bottom:10px; padding-bottom: 10px;
border-bottom: 1px solid var(--rule-color); border-bottom: 1px solid var(--rule-color);
background-color: var(--header-bg); background-color: var(--header-bg);
} }
p { p {
padding: 1rem; letter-spacing: -0.5pt;} padding: 1rem;
a.indent { display:inline-block; padding-top:0.5rem; padding-left: 2rem; font-size:0.8rem } letter-spacing: -0.5pt;
}
a.indent {
display: inline-block;
padding-top: 0.5rem;
padding-left: 2rem;
font-size: 0.8rem;
}
</style> </style>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
</head> </head>
<body> <body>
<h1>Path-Sharing Bounce Page</h1> <h1>Path-Sharing Bounce Page</h1>
<p> <p>
This application is being served via path sharing. This application is being served via path sharing. If you are not
If you are not redirected, <span id="help">check the redirected,
Javascript console in your browser's developer tools <span id="help"
for more information.</span> >check the Javascript console in your browser's developer tools for more
information.</span
>
</p> </p>
</body> </body>
<script language="javascript"> <script language="javascript">
@@ -61,21 +85,27 @@
return str.charAt(0) === char ? str.slice(1) : str; return str.charAt(0) === char ? str.slice(1) : str;
} }
function trimLastCharIf(str, char) { function trimLastCharIf(str, char) {
return str.endsWith("/") ? str.slice(0,str.length-1) : str; return str.endsWith("/") ? str.slice(0, str.length - 1) : str;
} }
const newloc = new URL(window.location); const newloc = new URL(window.location);
const h = document.getElementById("help") const h = document.getElementById("help");
// Building the websockify path must happen before we append the filename to newloc.pathname // Building the websockify path must happen before we append the filename to newloc.pathname
newloc.searchParams.append("path", newloc.searchParams.append(
trimLastCharIf(trimFirstCharIf(newloc.pathname,"/"),"/")+"/websockify"); "path",
newloc.searchParams.append("encrypted", newloc.protocol==="https:"? true : false); trimLastCharIf(trimFirstCharIf(newloc.pathname, "/"), "/") +
"/websockify",
);
newloc.searchParams.append(
"encrypted",
newloc.protocol === "https:" ? true : false,
);
newloc.pathname += "vnc.html" newloc.pathname += "vnc.html";
console.log(newloc); console.log(newloc);
h.innerHTML = `click <a id="link" href="${newloc.toString()}">here</a> to go to the application. h.innerHTML = `click <a id="link" href="${newloc.toString()}">here</a> to go to the application.
<br/><br/>The rewritten URL is:<br/><a id="link" class="indent" href="${newloc.toString()}">${newloc.toString()}</a>` <br/><br/>The rewritten URL is:<br/><a id="link" class="indent" href="${newloc.toString()}">${newloc.toString()}</a>`;
window.location = newloc.href; window.location = newloc.href;
</script> </script>
</html> </html>
+7 -4
View File
@@ -3,7 +3,10 @@
# Exit on error, undefined variables, and pipe failures # Exit on error, undefined variables, and pipe failures
set -euo pipefail set -euo pipefail
error() { printf "💀 ERROR: %s\n" "$@"; exit 1; } error() {
printf "💀 ERROR: %s\n" "$@"
exit 1
}
# Function to check if vncserver is already installed # Function to check if vncserver is already installed
check_installed() { check_installed() {
@@ -248,7 +251,7 @@ get_http_dir() {
echo $httpd_directory echo $httpd_directory
} }
fix_server_index_file(){ fix_server_index_file() {
local fname=$${FUNCNAME[0]} # gets current function name local fname=$${FUNCNAME[0]} # gets current function name
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
error "$fname requires exactly 1 parameter:\n\tpath to KasmVNC httpd_directory" error "$fname requires exactly 1 parameter:\n\tpath to KasmVNC httpd_directory"
@@ -259,7 +262,7 @@ fix_server_index_file(){
fi fi
pushd "$httpdir" > /dev/null pushd "$httpdir" > /dev/null
cat <<'EOH' > /tmp/path_vnc.html cat << 'EOH' > /tmp/path_vnc.html
${PATH_VNC_HTML} ${PATH_VNC_HTML}
EOH EOH
$SUDO mv /tmp/path_vnc.html . $SUDO mv /tmp/path_vnc.html .
@@ -271,7 +274,7 @@ EOH
popd > /dev/null popd > /dev/null
} }
patch_kasm_http_files(){ patch_kasm_http_files() {
homedir=$(get_http_dir) homedir=$(get_http_dir)
fix_server_index_file "$homedir" fix_server_index_file "$homedir"
} }
+7 -7
View File
@@ -9,11 +9,11 @@ CODER_OIDC_ACCESS_TOKEN=${CODER_OIDC_ACCESS_TOKEN}
fetch() { fetch() {
dest="$1" dest="$1"
url="$2" url="$2"
if command -v curl >/dev/null 2>&1; then if command -v curl > /dev/null 2>&1; then
curl -sSL --fail "$${url}" -o "$${dest}" curl -sSL --fail "$${url}" -o "$${dest}"
elif command -v wget >/dev/null 2>&1; then elif command -v wget > /dev/null 2>&1; then
wget -O "$${dest}" "$${url}" wget -O "$${dest}" "$${url}"
elif command -v busybox >/dev/null 2>&1; then elif command -v busybox > /dev/null 2>&1; then
busybox wget -O "$${dest}" "$${url}" busybox wget -O "$${dest}" "$${url}"
else else
printf "curl, wget, or busybox is not installed. Please install curl or wget in your image.\n" printf "curl, wget, or busybox is not installed. Please install curl or wget in your image.\n"
@@ -22,9 +22,9 @@ fetch() {
} }
unzip_safe() { unzip_safe() {
if command -v unzip >/dev/null 2>&1; then if command -v unzip > /dev/null 2>&1; then
command unzip "$@" command unzip "$@"
elif command -v busybox >/dev/null 2>&1; then elif command -v busybox > /dev/null 2>&1; then
busybox unzip "$@" busybox unzip "$@"
else else
printf "unzip or busybox is not installed. Please install unzip in your image.\n" printf "unzip or busybox is not installed. Please install unzip in your image.\n"
@@ -56,7 +56,7 @@ install() {
# Check if the vault CLI is installed and has the correct version # Check if the vault CLI is installed and has the correct version
installation_needed=1 installation_needed=1
if command -v vault >/dev/null 2>&1; then if command -v vault > /dev/null 2>&1; then
CURRENT_VERSION=$(vault version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') CURRENT_VERSION=$(vault version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
if [ "$${CURRENT_VERSION}" = "$${VAULT_CLI_VERSION}" ]; then if [ "$${CURRENT_VERSION}" = "$${VAULT_CLI_VERSION}" ]; then
printf "Vault version %s is already installed and up-to-date.\n\n" "$${CURRENT_VERSION}" printf "Vault version %s is already installed and up-to-date.\n\n" "$${CURRENT_VERSION}"
@@ -81,7 +81,7 @@ install() {
return 1 return 1
fi fi
rm vault.zip rm vault.zip
if sudo mv vault /usr/local/bin/vault 2>/dev/null; then if sudo mv vault /usr/local/bin/vault 2> /dev/null; then
printf "Vault installed successfully!\n\n" printf "Vault installed successfully!\n\n"
else else
mkdir -p ~/.local/bin mkdir -p ~/.local/bin
@@ -14,7 +14,7 @@ const defaultVariables = {
coder_app_slug: "vscode", coder_app_slug: "vscode",
coder_app_display_name: "VS Code Desktop", coder_app_display_name: "VS Code Desktop",
protocol: "vscode", protocol: "vscode",
} };
describe("vscode-desktop-core", async () => { describe("vscode-desktop-core", async () => {
await runTerraformInit(import.meta.dir); await runTerraformInit(import.meta.dir);
@@ -40,7 +40,7 @@ describe("vscode-desktop-core", async () => {
const state = await runTerraformApply(import.meta.dir, { const state = await runTerraformApply(import.meta.dir, {
folder: "/foo/bar", folder: "/foo/bar",
...defaultVariables ...defaultVariables,
}); });
expect(state.outputs.ide_uri.value).toBe( expect(state.outputs.ide_uri.value).toBe(
@@ -86,7 +86,7 @@ describe("vscode-desktop-core", async () => {
it("expect order to be set", async () => { it("expect order to be set", async () => {
const state = await runTerraformApply(import.meta.dir, { const state = await runTerraformApply(import.meta.dir, {
coder_app_order: "22", coder_app_order: "22",
...defaultVariables ...defaultVariables,
}); });
const coder_app = state.resources.find( const coder_app = state.resources.find(
+1 -1
View File
@@ -68,7 +68,7 @@ esac
# Detect the platform # Detect the platform
if [ -n "${PLATFORM}" ]; then if [ -n "${PLATFORM}" ]; then
DETECTED_PLATFORM="${PLATFORM}" DETECTED_PLATFORM="${PLATFORM}"
elif [ -f /etc/alpine-release ] || grep -qi 'ID=alpine' /etc/os-release 2>/dev/null || command -v apk > /dev/null 2>&1; then elif [ -f /etc/alpine-release ] || grep -qi 'ID=alpine' /etc/os-release 2> /dev/null || command -v apk > /dev/null 2>&1; then
DETECTED_PLATFORM="alpine" DETECTED_PLATFORM="alpine"
elif [ "$(uname -s)" = "Darwin" ]; then elif [ "$(uname -s)" = "Darwin" ]; then
DETECTED_PLATFORM="darwin" DETECTED_PLATFORM="darwin"
@@ -18,27 +18,33 @@ describe("aws-ami-snapshot", async () => {
}); });
it("missing variable: instance_id", async () => { it("missing variable: instance_id", async () => {
await expect(runTerraformApply(import.meta.dir, { await expect(
runTerraformApply(import.meta.dir, {
default_ami_id: "ami-12345678", default_ami_id: "ami-12345678",
template_name: "test-template", template_name: "test-template",
test_mode: true, test_mode: true,
})).rejects.toThrow(); }),
).rejects.toThrow();
}); });
it("missing variable: default_ami_id", async () => { it("missing variable: default_ami_id", async () => {
await expect(runTerraformApply(import.meta.dir, { await expect(
runTerraformApply(import.meta.dir, {
instance_id: "i-1234567890abcdef0", instance_id: "i-1234567890abcdef0",
template_name: "test-template", template_name: "test-template",
test_mode: true, test_mode: true,
})).rejects.toThrow(); }),
).rejects.toThrow();
}); });
it("missing variable: template_name", async () => { it("missing variable: template_name", async () => {
await expect(runTerraformApply(import.meta.dir, { await expect(
runTerraformApply(import.meta.dir, {
instance_id: "i-1234567890abcdef0", instance_id: "i-1234567890abcdef0",
default_ami_id: "ami-12345678", default_ami_id: "ami-12345678",
test_mode: true, test_mode: true,
})).rejects.toThrow(); }),
).rejects.toThrow();
}); });
it("supports optional variables", async () => { it("supports optional variables", async () => {