feat: update the goose module to support Tasks (#178)

Addresses https://github.com/coder/internal/issues/700. In addition to
the automated tests in the PR, I manually tested this module in
dev.coder.com.
This commit is contained in:
Hugo Dutka 2025-07-09 13:28:15 +02:00 committed by GitHub
parent d7fdc793c7
commit b74290051e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 449 additions and 287 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -10,6 +10,7 @@
"devDependencies": {
"@types/bun": "^1.2.18",
"bun-types": "^1.2.18",
"dedent": "^1.6.0",
"gray-matter": "^4.0.3",
"marked": "^16.0.0",
"prettier": "^3.6.2",

View File

@ -4,7 +4,7 @@ description: Run Goose in your workspace
icon: ../../../../.icons/goose.svg
maintainer_github: coder
verified: true
tags: [agent, goose, ai]
tags: [agent, goose, ai, tasks]
---
# Goose
@ -14,35 +14,26 @@ 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 = "1.3.0"
version = "2.0.0"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_goose = true
goose_version = "v1.0.16"
goose_version = "v1.0.31"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
agentapi_version = "latest"
}
```
## Prerequisites
- `screen` or `tmux` must be installed in your workspace to run Goose in the background
- You must add the [Coder Login](https://registry.coder.com/modules/coder-login) module to your template
The `codercom/oss-dogfood:latest` container image can be used for testing on container-based workspaces.
## Examples
Your workspace must have `screen` or `tmux` installed to use the background session functionality.
### Run in the background and report tasks (Experimental)
> This functionality is in early access as of Coder v2.21 and is still evolving.
> For now, we recommend testing it in a demo or staging environment,
> rather than deploying to production
>
> Learn more in [the Coder documentation](https://coder.com/docs/tutorials/ai-agents)
>
> Join our [Discord channel](https://discord.gg/coder) or
> [contact us](https://coder.com/contact) to get help or share feedback.
### Run in the background and report tasks
```tf
module "coder-login" {
@ -81,7 +72,6 @@ resource "coder_agent" "main" {
EOT
GOOSE_TASK_PROMPT = data.coder_parameter.ai_prompt.value
# An API key is required for experiment_auto_configure
# See https://block.github.io/goose/docs/getting-started/providers
ANTHROPIC_API_KEY = var.anthropic_api_key # or use a coder_parameter
}
@ -90,28 +80,15 @@ resource "coder_agent" "main" {
module "goose" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/goose/coder"
version = "1.3.0"
version = "2.0.0"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_goose = true
goose_version = "v1.0.16"
goose_version = "v1.0.31"
agentapi_version = "latest"
# Enable experimental features
experiment_report_tasks = true
# Run Goose in the background with screen (pick one: screen or tmux)
experiment_use_screen = true
# experiment_use_tmux = true # Alternative: use tmux instead of screen
# Optional: customize the session name (defaults to "goose")
# session_name = "goose-session"
# Avoid configuring Goose manually
experiment_auto_configure = true
# Required for experiment_auto_configure
experiment_goose_provider = "anthropic"
experiment_goose_model = "claude-3-5-sonnet-latest"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
}
```
@ -123,11 +100,11 @@ You can extend Goose's capabilities by adding custom extensions. For example, to
module "goose" {
# ... other configuration ...
experiment_pre_install_script = <<-EOT
pre_install_script = <<-EOT
npm i -g @wonderwhy-er/desktop-commander@latest
EOT
experiment_additional_extensions = <<-EOT
additional_extensions = <<-EOT
desktop-commander:
args: []
cmd: desktop-commander
@ -145,20 +122,6 @@ This will add the desktop-commander extension to Goose, allowing it to run comma
Note: The indentation in the heredoc is preserved, so you can write the YAML naturally.
## Run standalone
## Troubleshooting
Run Goose as a standalone app in your workspace. This will install Goose and run it directly without using screen or tmux, and without any task reporting to the Coder UI.
```tf
module "goose" {
source = "registry.coder.com/coder/goose/coder"
version = "1.3.0"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_goose = true
goose_version = "v1.0.16"
# Icon is not available in Coder v2.20 and below, so we'll use a custom icon URL
icon = "https://raw.githubusercontent.com/block/goose/refs/heads/main/ui/desktop/src/images/icon.svg"
}
```
The module will create log files in the workspace's `~/.goose-module` directory. If you run into any issues, look at them for more information.

View File

@ -0,0 +1,254 @@
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 "../agentapi/test-util";
import dedent from "dedent";
let cleanupFunctions: (() => Promise<void>)[] = [];
const registerCleanup = (cleanup: () => Promise<void>) => {
cleanupFunctions.push(cleanup);
};
// Cleanup logic depends on the fact that bun's built-in test runner
// runs tests sequentially.
// https://bun.sh/docs/test/discovery#execution-order
// Weird things would happen if tried to run tests in parallel.
// One test could clean up resources that another test was still using.
afterEach(async () => {
// reverse the cleanup functions so that they are run in the correct order
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;
skipGooseMock?: boolean;
moduleVariables?: Record<string, string>;
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_goose: props?.skipGooseMock ? "true" : "false",
install_agentapi: props?.skipAgentAPIMock ? "true" : "false",
goose_provider: "test-provider",
goose_model: "test-model",
...props?.moduleVariables,
},
registerCleanup,
projectDir,
skipAgentAPIMock: props?.skipAgentAPIMock,
agentapiMockScript: props?.agentapiMockScript,
});
if (!props?.skipGooseMock) {
await writeExecutable({
containerId: id,
filePath: "/usr/bin/goose",
content: await loadTestFile(import.meta.dir, "goose-mock.sh"),
});
}
return { id };
};
// increase the default timeout to 60 seconds
setDefaultTimeout(60 * 1000);
describe("goose", async () => {
beforeAll(async () => {
await runTerraformInit(import.meta.dir);
});
test("happy-path", async () => {
const { id } = await setup();
await execModuleScript(id);
await expectAgentAPIStarted(id);
});
test("install-version", async () => {
const { id } = await setup({
skipGooseMock: true,
moduleVariables: {
install_goose: "true",
goose_version: "v1.0.24",
},
});
await execModuleScript(id);
const resp = await execContainer(id, [
"bash",
"-c",
`"$HOME/.local/bin/goose" --version`,
]);
if (resp.exitCode !== 0) {
console.log(resp.stdout);
console.log(resp.stderr);
}
expect(resp.exitCode).toBe(0);
expect(resp.stdout).toContain("1.0.24");
});
test("install-stable", async () => {
const { id } = await setup({
skipGooseMock: true,
moduleVariables: {
install_goose: "true",
goose_version: "stable",
},
});
await execModuleScript(id);
const resp = await execContainer(id, [
"bash",
"-c",
`"$HOME/.local/bin/goose" --version`,
]);
if (resp.exitCode !== 0) {
console.log(resp.stdout);
console.log(resp.stderr);
}
expect(resp.exitCode).toBe(0);
});
test("config", async () => {
const expected =
dedent`
GOOSE_PROVIDER: anthropic
GOOSE_MODEL: claude-3-5-sonnet-latest
extensions:
coder:
args:
- exp
- mcp
- server
cmd: coder
description: Report ALL tasks and statuses (in progress, done, failed) you are working on.
enabled: true
envs:
CODER_MCP_APP_STATUS_SLUG: goose
CODER_MCP_AI_AGENTAPI_URL: http://localhost:3284
name: Coder
timeout: 3000
type: stdio
developer:
display_name: Developer
enabled: true
name: developer
timeout: 300
type: builtin
custom-stuff:
enabled: true
name: custom-stuff
timeout: 300
type: builtin
`.trim() + "\n";
const { id } = await setup({
moduleVariables: {
goose_provider: "anthropic",
goose_model: "claude-3-5-sonnet-latest",
additional_extensions: dedent`
custom-stuff:
enabled: true
name: custom-stuff
timeout: 300
type: builtin
`.trim(),
},
});
await execModuleScript(id);
const resp = await readFileContainer(
id,
"/home/coder/.config/goose/config.yaml",
);
expect(resp).toEqual(expected);
});
test("pre-post-install-scripts", async () => {
const { id } = await setup({
moduleVariables: {
pre_install_script: "#!/bin/bash\necho 'pre-install-script'",
post_install_script: "#!/bin/bash\necho 'post-install-script'",
},
});
await execModuleScript(id);
const preInstallLog = await readFileContainer(
id,
"/home/coder/.goose-module/pre_install.log",
);
expect(preInstallLog).toContain("pre-install-script");
const postInstallLog = await readFileContainer(
id,
"/home/coder/.goose-module/post_install.log",
);
expect(postInstallLog).toContain("post-install-script");
});
const promptFile = "/home/coder/.goose-module/prompt.txt";
const agentapiStartLog = "/home/coder/.goose-module/agentapi-start.log";
test("start-with-prompt", async () => {
const { id } = await setup({
agentapiMockScript: await loadTestFile(
import.meta.dir,
"agentapi-mock-print-args.js",
),
});
await execModuleScript(id, {
GOOSE_TASK_PROMPT: "custom-test-prompt",
});
const prompt = await readFileContainer(id, promptFile);
expect(prompt).toContain("custom-test-prompt");
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain(
"'goose run --interactive --instructions /home/coder/.goose-module/prompt.txt '",
);
});
test("start-without-prompt", async () => {
const { id } = await setup({
agentapiMockScript: await loadTestFile(
import.meta.dir,
"agentapi-mock-print-args.js",
),
});
await execModuleScript(id);
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain("'goose '");
const prompt = await execContainer(id, ["ls", "-l", promptFile]);
expect(prompt.exitCode).not.toBe(0);
expect(prompt.stderr).toContain("No such file or directory");
});
});

View File

@ -4,7 +4,7 @@ terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.5"
version = ">= 2.7"
}
}
}
@ -54,67 +54,48 @@ variable "goose_version" {
default = "stable"
}
variable "experiment_use_screen" {
variable "install_agentapi" {
type = bool
description = "Whether to use screen for running Goose in the background."
default = false
description = "Whether to install AgentAPI."
default = true
}
variable "experiment_use_tmux" {
type = bool
description = "Whether to use tmux instead of screen for running Goose in the background."
default = false
}
variable "session_name" {
variable "agentapi_version" {
type = string
description = "Name for the persistent session (screen or tmux)"
default = "goose"
description = "The version of AgentAPI to install."
default = "v0.2.3"
}
variable "experiment_report_tasks" {
type = bool
description = "Whether to enable task reporting."
default = false
}
variable "experiment_auto_configure" {
type = bool
description = "Whether to automatically configure Goose."
default = false
}
variable "experiment_goose_provider" {
variable "goose_provider" {
type = string
description = "The provider to use for Goose (e.g., anthropic)."
default = ""
}
variable "experiment_goose_model" {
variable "goose_model" {
type = string
description = "The model to use for Goose (e.g., claude-3-5-sonnet-latest)."
default = ""
}
variable "experiment_pre_install_script" {
variable "pre_install_script" {
type = string
description = "Custom script to run before installing Goose."
default = null
}
variable "experiment_post_install_script" {
variable "post_install_script" {
type = string
description = "Custom script to run after installing Goose."
default = null
}
variable "experiment_additional_extensions" {
variable "additional_extensions" {
type = string
description = "Additional extensions configuration in YAML format to append to the config."
default = null
}
locals {
app_slug = "goose"
base_extensions = <<-EOT
coder:
args:
@ -125,7 +106,8 @@ coder:
description: Report ALL tasks and statuses (in progress, done, failed) you are working on.
enabled: true
envs:
CODER_MCP_APP_STATUS_SLUG: goose
CODER_MCP_APP_STATUS_SLUG: ${local.app_slug}
CODER_MCP_AI_AGENTAPI_URL: http://localhost:3284
name: Coder
timeout: 3000
type: stdio
@ -139,204 +121,47 @@ EOT
# Add two spaces to each line of extensions to match YAML structure
formatted_base = " ${replace(trimspace(local.base_extensions), "\n", "\n ")}"
additional_extensions = var.experiment_additional_extensions != null ? "\n ${replace(trimspace(var.experiment_additional_extensions), "\n", "\n ")}" : ""
additional_extensions = var.additional_extensions != null ? "\n ${replace(trimspace(var.additional_extensions), "\n", "\n ")}" : ""
combined_extensions = <<-EOT
extensions:
${local.formatted_base}${local.additional_extensions}
EOT
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
install_script = file("${path.module}/scripts/install.sh")
start_script = file("${path.module}/scripts/start.sh")
module_dir_name = ".goose-module"
}
# Install and Initialize Goose
resource "coder_script" "goose" {
module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.0.0"
agent_id = var.agent_id
display_name = "Goose"
icon = var.icon
script = <<-EOT
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 = "Goose"
cli_app_slug = "${local.app_slug}-cli"
cli_app_display_name = "Goose CLI"
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 = local.start_script
install_script = <<-EOT
#!/bin/bash
set -e
set -o errexit
set -o pipefail
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
chmod +x /tmp/install.sh
# Run pre-install script if provided
if [ -n "${local.encoded_pre_install_script}" ]; then
echo "Running pre-install script..."
echo "${local.encoded_pre_install_script}" | base64 -d > /tmp/pre_install.sh
chmod +x /tmp/pre_install.sh
/tmp/pre_install.sh
fi
# Install Goose if enabled
if [ "${var.install_goose}" = "true" ]; then
if ! command_exists npm; then
echo "Error: npm is not installed. Please install Node.js and npm first."
exit 1
fi
echo "Installing Goose..."
RELEASE_TAG=v${var.goose_version} curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | CONFIGURE=false bash
fi
# Run post-install script if provided
if [ -n "${local.encoded_post_install_script}" ]; then
echo "Running post-install script..."
echo "${local.encoded_post_install_script}" | base64 -d > /tmp/post_install.sh
chmod +x /tmp/post_install.sh
/tmp/post_install.sh
fi
# Configure Goose if auto-configure is enabled
if [ "${var.experiment_auto_configure}" = "true" ]; then
echo "Configuring Goose..."
mkdir -p "$HOME/.config/goose"
cat > "$HOME/.config/goose/config.yaml" << EOL
GOOSE_PROVIDER: ${var.experiment_goose_provider}
GOOSE_MODEL: ${var.experiment_goose_model}
${trimspace(local.combined_extensions)}
EOL
fi
# Write system prompt to config
mkdir -p "$HOME/.config/goose"
echo "$GOOSE_SYSTEM_PROMPT" > "$HOME/.config/goose/.goosehints"
# Handle terminal multiplexer selection (tmux or screen)
if [ "${var.experiment_use_tmux}" = "true" ] && [ "${var.experiment_use_screen}" = "true" ]; then
echo "Error: Both experiment_use_tmux and experiment_use_screen cannot be true simultaneously."
echo "Please set only one of them to true."
exit 1
fi
# Determine goose command
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi
# Run with tmux if enabled
if [ "${var.experiment_use_tmux}" = "true" ]; then
echo "Running Goose in the background with tmux..."
# Check if tmux is installed
if ! command_exists tmux; then
echo "Error: tmux is not installed. Please install tmux manually."
exit 1
fi
touch "$HOME/.goose.log"
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# Configure tmux for shared sessions
if [ ! -f "$HOME/.tmux.conf" ]; then
echo "Creating ~/.tmux.conf with shared session settings..."
echo "set -g mouse on" > "$HOME/.tmux.conf"
fi
if ! grep -q "^set -g mouse on$" "$HOME/.tmux.conf"; then
echo "Adding 'set -g mouse on' to ~/.tmux.conf..."
echo "set -g mouse on" >> "$HOME/.tmux.conf"
fi
# Create a new tmux session in detached mode
tmux new-session -d -s ${var.session_name} -c ${var.folder} "\"$GOOSE_CMD\" run --text \"Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT\" --interactive | tee -a \"$HOME/.goose.log\"; exec bash"
elif [ "${var.experiment_use_screen}" = "true" ]; then
echo "Running Goose in the background..."
# Check if screen is installed
if ! command_exists screen; then
echo "Error: screen is not installed. Please install screen manually."
exit 1
fi
touch "$HOME/.goose.log"
# Ensure the screenrc exists
if [ ! -f "$HOME/.screenrc" ]; then
echo "Creating ~/.screenrc and adding multiuser settings..." | tee -a "$HOME/.goose.log"
echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc"
fi
if ! grep -q "^multiuser on$" "$HOME/.screenrc"; then
echo "Adding 'multiuser on' to ~/.screenrc..." | tee -a "$HOME/.goose.log"
echo "multiuser on" >> "$HOME/.screenrc"
fi
if ! grep -q "^acladd $(whoami)$" "$HOME/.screenrc"; then
echo "Adding 'acladd $(whoami)' to ~/.screenrc..." | tee -a "$HOME/.goose.log"
echo "acladd $(whoami)" >> "$HOME/.screenrc"
fi
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
screen -U -dmS ${var.session_name} bash -c "
cd ${var.folder}
\"$GOOSE_CMD\" run --text \"Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT\" --interactive | tee -a \"$HOME/.goose.log\"
/bin/bash
"
fi
ARG_PROVIDER='${var.goose_provider}' \
ARG_MODEL='${var.goose_model}' \
ARG_GOOSE_CONFIG="$(echo -n '${base64encode(local.combined_extensions)}' | base64 -d)" \
ARG_INSTALL='${var.install_goose}' \
ARG_GOOSE_VERSION='${var.goose_version}' \
/tmp/install.sh
EOT
run_on_start = true
}
resource "coder_app" "goose" {
slug = "goose"
display_name = "Goose"
agent_id = var.agent_id
command = <<-EOT
#!/bin/bash
set -e
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Determine goose command
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
if [ "${var.experiment_use_tmux}" = "true" ]; then
if tmux has-session -t ${var.session_name} 2>/dev/null; then
echo "Attaching to existing Goose tmux session." | tee -a "$HOME/.goose.log"
tmux attach-session -t ${var.session_name}
else
echo "Starting a new Goose tmux session." | tee -a "$HOME/.goose.log"
tmux new-session -s ${var.session_name} -c ${var.folder} "\"$GOOSE_CMD\" run --text \"Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT\" --interactive | tee -a \"$HOME/.goose.log\"; exec bash"
fi
elif [ "${var.experiment_use_screen}" = "true" ]; then
# Check if session exists first
if ! screen -list | grep -q "${var.session_name}"; then
echo "Error: No existing Goose session found. Please wait for the script to start it."
exit 1
fi
# Only attach to existing session
screen -xRR ${var.session_name}
else
cd ${var.folder}
"$GOOSE_CMD" run --text "Review goosehints. Your task: $GOOSE_TASK_PROMPT" --interactive
fi
EOT
icon = var.icon
order = var.order
group = var.group
}

View File

@ -0,0 +1,57 @@
#!/bin/bash
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
set -o nounset
echo "--------------------------------"
echo "provider: $ARG_PROVIDER"
echo "model: $ARG_MODEL"
echo "goose_config: $ARG_GOOSE_CONFIG"
echo "install: $ARG_INSTALL"
echo "goose_version: $ARG_GOOSE_VERSION"
echo "--------------------------------"
set +o nounset
if [ "${ARG_INSTALL}" = "true" ]; then
echo "Installing Goose..."
parsed_version="${ARG_GOOSE_VERSION}"
if [ "${ARG_GOOSE_VERSION}" = "stable" ]; then
parsed_version=""
fi
curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | GOOSE_VERSION="${parsed_version}" CONFIGURE=false bash
echo "Goose installed"
else
echo "Skipping Goose installation"
fi
if [ "${ARG_GOOSE_CONFIG}" != "" ]; then
echo "Configuring Goose..."
mkdir -p "$HOME/.config/goose"
echo "GOOSE_PROVIDER: $ARG_PROVIDER" >"$HOME/.config/goose/config.yaml"
echo "GOOSE_MODEL: $ARG_MODEL" >>"$HOME/.config/goose/config.yaml"
echo "$ARG_GOOSE_CONFIG" >>"$HOME/.config/goose/config.yaml"
else
echo "Skipping Goose configuration"
fi
if [ "${GOOSE_SYSTEM_PROMPT}" != "" ]; then
echo "Setting Goose system prompt..."
mkdir -p "$HOME/.config/goose"
echo "$GOOSE_SYSTEM_PROMPT" >"$HOME/.config/goose/.goosehints"
else
echo "Goose system prompt not set. use the GOOSE_SYSTEM_PROMPT environment variable to set it."
fi
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi

View File

@ -0,0 +1,35 @@
#!/bin/bash
set -o errexit
set -o pipefail
command_exists() {
command -v "$1" >/dev/null 2>&1
}
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi
# this must be kept up to date with main.tf
MODULE_DIR="$HOME/.goose-module"
mkdir -p "$MODULE_DIR"
if [ ! -z "$GOOSE_TASK_PROMPT" ]; then
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_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" >"$PROMPT_FILE"
GOOSE_ARGS=(run --interactive --instructions "$PROMPT_FILE")
else
echo "Starting without a prompt"
GOOSE_ARGS=()
fi
agentapi server --term-width 67 --term-height 1190 -- \
bash -c "$(printf '%q ' "$GOOSE_CMD" "${GOOSE_ARGS[@]}")"

View File

@ -0,0 +1,19 @@
#!/usr/bin/env node
const http = require("http");
const args = process.argv.slice(2);
console.log(args);
const port = 3284;
console.log(`starting server on port ${port}`);
http
.createServer(function (_request, response) {
response.writeHead(200);
response.end(
JSON.stringify({
status: "stable",
}),
);
})
.listen(port);

View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
while true; do
echo "$(date) - goose-mock"
sleep 15
done