|
| 1 | +#!/bin/bash |
| 2 | +# kelos_entrypoint.sh — Kelos agent image interface implementation for |
| 3 | +# Cursor CLI. |
| 4 | +# |
| 5 | +# Interface contract: |
| 6 | +# - First argument ($1): the task prompt |
| 7 | +# - CURSOR_API_KEY env var: API key for authentication |
| 8 | +# - KELOS_MODEL env var: model name (optional) |
| 9 | +# - KELOS_AGENTS_MD env var: user-level instructions (optional) |
| 10 | +# - KELOS_PLUGIN_DIR env var: plugin directory with skills/agents (optional) |
| 11 | +# - UID 61100: shared between git-clone init container and agent |
| 12 | +# - Working directory: /workspace/repo when a workspace is configured |
| 13 | + |
| 14 | +set -uo pipefail |
| 15 | + |
| 16 | +PROMPT="${1:?Prompt argument is required}" |
| 17 | + |
| 18 | +ARGS=( |
| 19 | + "-p" |
| 20 | + "--force" |
| 21 | + "--trust" |
| 22 | + "--sandbox" "disabled" |
| 23 | + "--output-format" "stream-json" |
| 24 | + "$PROMPT" |
| 25 | +) |
| 26 | + |
| 27 | +if [ -n "${KELOS_MODEL:-}" ]; then |
| 28 | + ARGS=("--model" "$KELOS_MODEL" "${ARGS[@]}") |
| 29 | +fi |
| 30 | + |
| 31 | +# Write user-level instructions (global scope read by Cursor CLI) |
| 32 | +if [ -n "${KELOS_AGENTS_MD:-}" ]; then |
| 33 | + mkdir -p ~/.cursor |
| 34 | + printf '%s' "$KELOS_AGENTS_MD" >~/.cursor/AGENTS.md |
| 35 | +fi |
| 36 | + |
| 37 | +# Install each plugin's skills and agents into Cursor's config directories. |
| 38 | +# Skills are placed into .cursor/skills/ relative to the working directory |
| 39 | +# so the CLI discovers them at runtime. Agents are installed as Cursor |
| 40 | +# rules under .cursor/rules/ in the working directory. |
| 41 | +if [ -n "${KELOS_PLUGIN_DIR:-}" ] && [ -d "${KELOS_PLUGIN_DIR}" ]; then |
| 42 | + for plugindir in "${KELOS_PLUGIN_DIR}"/*/; do |
| 43 | + [ -d "$plugindir" ] || continue |
| 44 | + pluginname=$(basename "$plugindir") |
| 45 | + # Copy skills into .cursor/skills/<plugin>-<skill>/SKILL.md |
| 46 | + if [ -d "${plugindir}skills" ]; then |
| 47 | + for skilldir in "${plugindir}skills"/*/; do |
| 48 | + [ -d "$skilldir" ] || continue |
| 49 | + skillname=$(basename "$skilldir") |
| 50 | + targetdir=".cursor/skills/${pluginname}-${skillname}" |
| 51 | + mkdir -p "$targetdir" |
| 52 | + if [ -f "${skilldir}SKILL.md" ]; then |
| 53 | + cp "${skilldir}SKILL.md" "$targetdir/SKILL.md" |
| 54 | + fi |
| 55 | + done |
| 56 | + fi |
| 57 | + # Copy agents into .cursor/rules/ as .mdc rule files |
| 58 | + if [ -d "${plugindir}agents" ]; then |
| 59 | + mkdir -p .cursor/rules |
| 60 | + for agentfile in "${plugindir}agents"/*.md; do |
| 61 | + [ -f "$agentfile" ] || continue |
| 62 | + agentname=$(basename "$agentfile" .md) |
| 63 | + cp "$agentfile" ".cursor/rules/${pluginname}-${agentname}.mdc" |
| 64 | + done |
| 65 | + fi |
| 66 | + done |
| 67 | +fi |
| 68 | + |
| 69 | +# Write MCP server configuration to user-scoped ~/.cursor/mcp.json. |
| 70 | +# The KELOS_MCP_SERVERS JSON format matches Cursor's native format directly. |
| 71 | +if [ -n "${KELOS_MCP_SERVERS:-}" ]; then |
| 72 | + mkdir -p ~/.cursor |
| 73 | + node -e ' |
| 74 | +const fs = require("fs"); |
| 75 | +const cfgPath = require("os").homedir() + "/.cursor/mcp.json"; |
| 76 | +let existing = {}; |
| 77 | +try { existing = JSON.parse(fs.readFileSync(cfgPath, "utf8")); } catch {} |
| 78 | +const mcp = JSON.parse(process.env.KELOS_MCP_SERVERS); |
| 79 | +existing.mcpServers = Object.assign(existing.mcpServers || {}, mcp.mcpServers || {}); |
| 80 | +fs.writeFileSync(cfgPath, JSON.stringify(existing, null, 2)); |
| 81 | +' |
| 82 | +fi |
| 83 | + |
| 84 | +agent "${ARGS[@]}" | tee /tmp/agent-output.jsonl |
| 85 | +AGENT_EXIT_CODE=${PIPESTATUS[0]} |
| 86 | + |
| 87 | +/kelos/kelos-capture |
| 88 | + |
| 89 | +exit $AGENT_EXIT_CODE |
0 commit comments