|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -e |
| 3 | + |
| 4 | +lastmessage="" |
| 5 | +laststatus="" |
| 6 | + |
| 7 | +# json-stringify returns a json string for updating the status. |
| 8 | +# $1: status slug |
| 9 | +# $2: status |
| 10 | +# $3: message |
| 11 | +# $4: uri |
| 12 | +function json-stringify() { |
| 13 | + node -e "process.stdout.write(JSON.stringify({ |
| 14 | + app_slug: process.argv[1], |
| 15 | + state: process.argv[2], |
| 16 | + message: process.argv[3].substring(0, 160), |
| 17 | + uri: process.argv[4], |
| 18 | + }))" "$@" |
| 19 | +} |
| 20 | + |
| 21 | +# json-parse returns the specified key from the provided json. |
| 22 | +# $1: the key |
| 23 | +# $2: the json |
| 24 | +function json-parse() { |
| 25 | + node -e "process.stdout.write(JSON.parse(process.argv[2])[process.argv[1]])" "$@" |
| 26 | +} |
| 27 | + |
| 28 | +# run queries for the status then relays it to coderd. |
| 29 | +# $1: workspace agent uri |
| 30 | +# $2: workspace token |
| 31 | +# $3: llm agent api uri |
| 32 | +# $4: status slug |
| 33 | +function run() { |
| 34 | + local agenturi=$1 ; shift |
| 35 | + local token=$1 ; shift |
| 36 | + local agentapiuri=$1 ; shift |
| 37 | + local slug=$1 ; shift |
| 38 | + local resp |
| 39 | + # TODO: this only returns 'stable' or 'running'. |
| 40 | + # 1. We need a message. |
| 41 | + # 2. We need 'working', 'complete', or 'failure' for the status. |
| 42 | + # 3. Not sure yet what the URI is but maybe we need that. |
| 43 | + # Do we add a new endpoint or modify this one? |
| 44 | + local status |
| 45 | + local message |
| 46 | + local uri="" |
| 47 | + if ! resp=$(curl --fail-with-body --silent --show-error --location \ |
| 48 | + "$agentapiuri/status" 2>&1) ; then |
| 49 | + message=$(echo "$resp" | xargs) |
| 50 | + status=failure |
| 51 | + elif ! status=$(json-parse "status" "$resp" 2>&1) ; then |
| 52 | + message=$(echo "$status" | xargs) |
| 53 | + status=failure |
| 54 | + elif [[ $status == stable ]] ; then |
| 55 | + message=complete |
| 56 | + status=complete |
| 57 | + else |
| 58 | + message=working |
| 59 | + status=working |
| 60 | + fi |
| 61 | + if [[ $message != $lastmessage ]] || [[ $status != $laststatus ]] ; then |
| 62 | + local data |
| 63 | + if ! data=$(json-stringify "$slug" "$status" "$message" "$uri" 2>&1) ; then |
| 64 | + >&2 echo "Failed to update status" |
| 65 | + >&2 echo "$data" |
| 66 | + elif ! resp=$(curl --request PATCH \ |
| 67 | + --fail-with-body --silent --show-error --location \ |
| 68 | + --data "$data" \ |
| 69 | + --header "Content-Type: application/json" \ |
| 70 | + --header "Coder-Session-Token: $token" \ |
| 71 | + "$agenturi/api/v2/workspaceagents/me/app-status" 2>&1) ; then |
| 72 | + >&2 echo "Failed to update status" |
| 73 | + >&2 echo "$resp" |
| 74 | + >&2 echo "message: $message" |
| 75 | + >&2 echo "status: $status" |
| 76 | + else |
| 77 | + lastmessage=$message |
| 78 | + laststatus=$status |
| 79 | + fi |
| 80 | + fi |
| 81 | +} |
| 82 | + |
| 83 | +# loop runs the status updater every $1 seconds. |
| 84 | +# $1: interval in seconds |
| 85 | +# $2: workspace agent uri |
| 86 | +# $3: workspace agent token |
| 87 | +# $4: llm agent api uri |
| 88 | +# $5: status slug |
| 89 | +function loop() { |
| 90 | + local interval=$1 ; shift |
| 91 | + local agenturi=$1 ; shift |
| 92 | + local token=$1 ; shift |
| 93 | + local agentapiuri=$1 ; shift |
| 94 | + local slug=$1 ; shift |
| 95 | + while sleep "$interval" ; do |
| 96 | + run "$agenturi" "$token" "$agentapiuri" "$slug" |
| 97 | + done |
| 98 | +} |
| 99 | + |
| 100 | +# configure checks for required vars then starts polling in the background. |
| 101 | +# $1: interval in seconds |
| 102 | +function configure() { |
| 103 | + local interval=$1 ; shift |
| 104 | + echo "Configuring task reporting via agent polling..." |
| 105 | + # Node will be used to handle JSON. Since the module already requires npm, |
| 106 | + # this should not be an extra requirement. |
| 107 | + if ! command -v "node" >/dev/null 2>&1 ; then |
| 108 | + >&2 echo "Node must be installed" |
| 109 | + exit 1 |
| 110 | + fi |
| 111 | + local agenturi=${CODER_AGENT_URL-} |
| 112 | + if [[ -z $agenturi ]] ; then |
| 113 | + >&2 echo "CODER_AGENT_URL must be set" |
| 114 | + exit 1 |
| 115 | + fi |
| 116 | + local token=${CODER_AGENT_TOKEN-} |
| 117 | + if [[ -z $token ]] ; then |
| 118 | + if [[ -z ${CODER_AGENT_TOKEN_FILE-} ]] ; then |
| 119 | + >&2 echo "Either CODER_AGENT_TOKEN or CODER_AGENT_TOKEN_FILE must be set" |
| 120 | + exit 1 |
| 121 | + elif [[ -f $CODER_AGENT_TOKEN_FILE ]] ; then |
| 122 | + if ! token=$(<"$CODER_AGENT_TOKEN_FILE") ; then |
| 123 | + >&2 echo "$CODER_AGENT_TOKEN_FILE could not be read" |
| 124 | + exit 1 |
| 125 | + fi |
| 126 | + else |
| 127 | + >&2 echo "$CODER_AGENT_TOKEN_FILE does not exist or could not be accessed" |
| 128 | + exit 1 |
| 129 | + fi |
| 130 | + fi |
| 131 | + local slug=${CODER_MCP_APP_STATUS_SLUG-} |
| 132 | + if [[ -z $slug ]] ; then |
| 133 | + >&2 echo "$CODER_MCP_APP_STATUS_SLUG must be set" |
| 134 | + exit 1 |
| 135 | + fi |
| 136 | + local agentapiuri=${CODER_AGENT_API_URL-} |
| 137 | + if [[ -z $agentapiuri ]] ; then |
| 138 | + agentapiuri="http://localhost:3284" |
| 139 | + fi |
| 140 | + echo "Configured a $interval second poll" |
| 141 | + loop "$interval" "$agenturi" "$token" "$agentapiuri" "$slug" & |
| 142 | +} |
| 143 | + |
| 144 | +# main configures polling if enabled. |
| 145 | +# $1: interval in seconds |
| 146 | +function main() { |
| 147 | + local interval=$1 ; shift |
| 148 | + if [[ -z "$interval" ]] ; then |
| 149 | + echo "Will not poll since interval is undefined or blank" |
| 150 | + elif [[ "$interval" == "0" ]] ; then |
| 151 | + echo "Will not poll since interval is zero" |
| 152 | + else |
| 153 | + configure "$interval" |
| 154 | + fi |
| 155 | +} |
| 156 | + |
| 157 | +main "${INTERVAL}" |
0 commit comments