@geekbeer/minion 2.16.5 → 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example CHANGED
@@ -15,8 +15,8 @@ API_TOKEN=
15
15
  # Minion ID (optional) - The minion's UUID assigned by HQ
16
16
  MINION_ID=
17
17
 
18
- # Agent port (optional, default: 3001)
19
- AGENT_PORT=3001
18
+ # Agent port (optional, default: 8080)
19
+ AGENT_PORT=8080
20
20
 
21
21
  # Heartbeat interval in seconds (optional, default: 30)
22
22
  HEARTBEAT_INTERVAL=30
package/README.md CHANGED
@@ -57,7 +57,7 @@ await reportIssue({
57
57
  | `HQ_URL` | Minion HQ server URL | - |
58
58
  | `API_TOKEN` | Authentication token | - |
59
59
  | `MINION_ID` | Minion UUID | - |
60
- | `AGENT_PORT` | Agent API listen port | `3001` |
60
+ | `AGENT_PORT` | Agent API listen port | `8080` |
61
61
  | `HEARTBEAT_INTERVAL` | Heartbeat interval (ms) | `30000` |
62
62
 
63
63
  ## License
package/api.js CHANGED
@@ -53,7 +53,7 @@ async function reportExecution(data) {
53
53
  /**
54
54
  * Report a single workflow step completion to HQ.
55
55
  * Called by the post-execution hook after a dispatched skill finishes.
56
- * @param {object} data - { workflow_execution_id, step_index, status }
56
+ * @param {object} data - { workflow_execution_id, step_index, status, output_summary? }
57
57
  */
58
58
  async function reportStepComplete(data) {
59
59
  return request('/step-complete', {
package/config.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * (no HQ communication).
11
11
  *
12
12
  * Other optional environment variables:
13
- * - AGENT_PORT: Port for the local agent server (default: 3001)
13
+ * - AGENT_PORT: Port for the local agent server (default: 8080)
14
14
  * - MINION_USER: System user running the agent (used to resolve home directory)
15
15
  */
16
16
 
@@ -44,10 +44,17 @@ const config = {
44
44
  MINION_ID: process.env.MINION_ID || '',
45
45
 
46
46
  // Server settings
47
- AGENT_PORT: parseInt(process.env.AGENT_PORT, 10) || 3001,
47
+ AGENT_PORT: parseInt(process.env.AGENT_PORT, 10) || 8080,
48
48
 
49
49
  // Resolved home directory (safe for supervisord environments)
50
50
  HOME_DIR: resolveHomeDir(),
51
+
52
+ // LLM command template (user-configured)
53
+ // Use {prompt} as placeholder for the prompt text.
54
+ // Examples:
55
+ // LLM_COMMAND="claude -p '{prompt}'"
56
+ // LLM_COMMAND="gemini-cli --prompt '{prompt}'"
57
+ LLM_COMMAND: process.env.LLM_COMMAND || '',
51
58
  }
52
59
 
53
60
  /**
@@ -68,4 +75,11 @@ function validate() {
68
75
  }
69
76
  }
70
77
 
71
- module.exports = { config, validate, isHqConfigured }
78
+ /**
79
+ * Check if LLM command is configured
80
+ */
81
+ function isLlmConfigured() {
82
+ return !!config.LLM_COMMAND
83
+ }
84
+
85
+ module.exports = { config, validate, isHqConfigured, isLlmConfigured }
@@ -5,7 +5,7 @@ HQのソースコードを読む必要はありません — 必要な情報は
5
5
 
6
6
  ---
7
7
 
8
- ## Agent API Endpoints (http://localhost:3001)
8
+ ## Agent API Endpoints (http://localhost:8080)
9
9
 
10
10
  Authentication: `Authorization: Bearer $API_TOKEN` header (except where noted).
11
11
 
@@ -87,11 +87,11 @@ curl -s -X POST "$HQ_URL/api/minion/workflows" \
87
87
 
88
88
  ```bash
89
89
  # HQからワークフローを取得 (不足スキルも自動fetch)
90
- curl -s -X POST "http://localhost:3001/api/workflows/fetch/<name>" \
90
+ curl -s -X POST "http://localhost:8080/api/workflows/fetch/<name>" \
91
91
  -H "Authorization: Bearer $API_TOKEN"
92
92
 
93
93
  # ローカルワークフローをHQにpush (スキルも自動push)
94
- curl -s -X POST "http://localhost:3001/api/workflows/push/<name>" \
94
+ curl -s -X POST "http://localhost:8080/api/workflows/push/<name>" \
95
95
  -H "Authorization: Bearer $API_TOKEN"
96
96
  ```
97
97
 
@@ -128,18 +128,18 @@ curl -s -X PUT "$HQ_URL/api/minion/me/project/<project-id>/context" \
128
128
 
129
129
  ```bash
130
130
  # 最近の実行一覧
131
- curl -s "http://localhost:3001/api/executions?limit=10" \
131
+ curl -s "http://localhost:8080/api/executions?limit=10" \
132
132
  -H "Authorization: Bearer $API_TOKEN"
133
133
 
134
134
  # 特定の実行ログ
135
- curl -s "http://localhost:3001/api/executions/<id>/log" \
135
+ curl -s "http://localhost:8080/api/executions/<id>/log" \
136
136
  -H "Authorization: Bearer $API_TOKEN"
137
137
  ```
138
138
 
139
139
  ### 実行結果の報告
140
140
 
141
141
  ```bash
142
- curl -s -X POST "http://localhost:3001/api/executions/<id>/outcome" \
142
+ curl -s -X POST "http://localhost:8080/api/executions/<id>/outcome" \
143
143
  -H "Content-Type: application/json" \
144
144
  -d '{
145
145
  "outcome": "success",
@@ -199,11 +199,11 @@ minion-cli skill fetch <name>
199
199
 
200
200
  ```bash
201
201
  # ローカルワークフロー一覧 (next_run を確認)
202
- curl -s "http://localhost:3001/api/workflows" \
202
+ curl -s "http://localhost:8080/api/workflows" \
203
203
  -H "Authorization: Bearer $API_TOKEN"
204
204
 
205
205
  # 手動トリガー
206
- curl -s -X POST "http://localhost:3001/api/workflows/trigger" \
206
+ curl -s -X POST "http://localhost:8080/api/workflows/trigger" \
207
207
  -H "Authorization: Bearer $API_TOKEN" \
208
208
  -H "Content-Type: application/json" \
209
209
  -d '{ "workflow_id": "<workflow-uuid>" }'
@@ -2,12 +2,13 @@
2
2
  * LLM Service authentication checker
3
3
  *
4
4
  * Detects whether supported LLM CLIs are authenticated and ready to use.
5
- * CLIs are pre-installed on all minions; this module only checks auth status.
5
+ * Also checks whether LLM_COMMAND is configured for workflow/routine execution.
6
6
  * Results are cached in memory for 60 seconds to avoid excessive filesystem checks.
7
7
  */
8
8
 
9
9
  const fs = require('fs')
10
10
  const path = require('path')
11
+ const { execSync } = require('child_process')
11
12
  const { config } = require('../config')
12
13
 
13
14
  const CACHE_TTL_MS = 60000
@@ -15,11 +16,28 @@ const CACHE_TTL_MS = 60000
15
16
  let cachedResult = null
16
17
  let cachedAt = 0
17
18
 
19
+ /**
20
+ * Build extended PATH that includes common Claude CLI installation locations
21
+ */
22
+ function getExtendedPath() {
23
+ const additionalPaths = [
24
+ path.join(config.HOME_DIR, '.local', 'bin'),
25
+ path.join(config.HOME_DIR, 'bin'),
26
+ path.join(config.HOME_DIR, '.npm-global', 'bin'),
27
+ path.join(config.HOME_DIR, '.claude', 'bin'),
28
+ '/usr/local/bin',
29
+ ]
30
+ return [...additionalPaths, process.env.PATH || '/usr/bin:/bin'].join(':')
31
+ }
32
+
18
33
  /**
19
34
  * Check Claude Code authentication.
20
- * Claude stores OAuth credentials in ~/.claude/.credentials.json
35
+ * First checks known credential file locations (fast path),
36
+ * then falls back to `claude auth whoami` CLI command for newer CLI versions
37
+ * that may store credentials differently.
21
38
  */
22
39
  function isClaudeAuthenticated() {
40
+ // Fast path: check known credential file locations
23
41
  const candidates = [
24
42
  path.join(config.HOME_DIR, '.claude', '.credentials.json'),
25
43
  path.join(config.HOME_DIR, '.claude', 'credentials.json'),
@@ -35,7 +53,24 @@ function isClaudeAuthenticated() {
35
53
  // Invalid JSON or read error — not authenticated
36
54
  }
37
55
  }
38
- return false
56
+
57
+ // Fallback: check via claude CLI command (handles newer credential storage)
58
+ try {
59
+ const claudePath = path.join(config.HOME_DIR, '.local', 'bin', 'claude')
60
+ const claudeBin = fs.existsSync(claudePath) ? claudePath : 'claude'
61
+ execSync(`${claudeBin} auth whoami`, {
62
+ encoding: 'utf-8',
63
+ timeout: 5000,
64
+ stdio: 'pipe',
65
+ env: {
66
+ HOME: config.HOME_DIR,
67
+ PATH: getExtendedPath(),
68
+ },
69
+ })
70
+ return true
71
+ } catch {
72
+ return false
73
+ }
39
74
  }
40
75
 
41
76
  /**
@@ -89,10 +124,18 @@ const SERVICE_DEFINITIONS = [
89
124
  { name: 'codex', display_name: 'Codex', check: isCodexAuthenticated },
90
125
  ]
91
126
 
127
+ /**
128
+ * Check if LLM_COMMAND is configured for workflow/routine execution.
129
+ */
130
+ function isLlmCommandConfigured() {
131
+ return !!config.LLM_COMMAND
132
+ }
133
+
92
134
  /**
93
135
  * Get authenticated LLM services (cached for 60s).
94
- * Returns all services with their authentication status.
95
- * @returns {{ name: string, display_name: string, authenticated: boolean }[]}
136
+ * Returns all services with their authentication status,
137
+ * plus whether LLM_COMMAND is configured.
138
+ * @returns {{ services: { name: string, display_name: string, authenticated: boolean }[], llm_command_configured: boolean }}
96
139
  */
97
140
  function getLlmServices() {
98
141
  const now = Date.now()
@@ -117,4 +160,4 @@ function clearLlmCache() {
117
160
  cachedAt = 0
118
161
  }
119
162
 
120
- module.exports = { getLlmServices, clearLlmCache }
163
+ module.exports = { getLlmServices, clearLlmCache, isLlmCommandConfigured }
package/minion-cli.sh CHANGED
@@ -86,7 +86,7 @@ svc_control() {
86
86
  esac
87
87
  }
88
88
 
89
- AGENT_URL="${MINION_AGENT_URL:-http://localhost:3001}"
89
+ AGENT_URL="${MINION_AGENT_URL:-http://localhost:8080}"
90
90
 
91
91
  # Auto-load .env so that API_TOKEN etc. are available in interactive shells
92
92
  ENV_FILE="/opt/minion-agent/.env"
@@ -279,11 +279,12 @@ do_setup() {
279
279
  ENV_CONTENT+="MINION_ID=${MINION_ID}\n"
280
280
  fi
281
281
 
282
- ENV_CONTENT+="AGENT_PORT=3001\n"
282
+ ENV_CONTENT+="AGENT_PORT=8080\n"
283
283
  ENV_CONTENT+="HEARTBEAT_INTERVAL=30\n"
284
284
  ENV_CONTENT+="MINION_USER=${TARGET_USER}\n"
285
285
 
286
286
  echo -e "$ENV_CONTENT" | $SUDO tee /opt/minion-agent/.env > /dev/null
287
+ $SUDO chown "${TARGET_USER}:${TARGET_USER}" /opt/minion-agent/.env
287
288
  echo " -> /opt/minion-agent/.env generated"
288
289
 
289
290
  # Step 5: Configure sudoers for agent user
@@ -581,7 +582,7 @@ SUPEOF
581
582
  local SUCCESS=false
582
583
 
583
584
  for i in $(seq 1 $RETRIES); do
584
- if curl -sf http://localhost:3001/api/health > /dev/null 2>&1; then
585
+ if curl -sf http://localhost:8080/api/health > /dev/null 2>&1; then
585
586
  SUCCESS=true
586
587
  break
587
588
  fi
@@ -649,10 +650,12 @@ SUPEOF
649
650
  exit 1
650
651
  fi
651
652
 
652
- # Install cloudflared if not present
653
+ # Install cloudflared if not present (architecture-aware)
653
654
  if ! command -v cloudflared &>/dev/null; then
654
655
  echo " Installing cloudflared..."
655
- curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb \
656
+ local CF_ARCH
657
+ CF_ARCH=$(dpkg --print-architecture 2>/dev/null || echo "amd64")
658
+ curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${CF_ARCH}.deb" \
656
659
  -o /tmp/cloudflared.deb
657
660
  $SUDO dpkg -i /tmp/cloudflared.deb
658
661
  rm -f /tmp/cloudflared.deb
@@ -688,10 +691,36 @@ SUPEOF
688
691
  echo "$CONFIG_YML" | $SUDO tee /etc/cloudflared/config.yml > /dev/null
689
692
  echo " -> /etc/cloudflared/config.yml saved"
690
693
 
691
- # Install and start cloudflared service
692
- $SUDO cloudflared service install 2>/dev/null || true
693
- $SUDO systemctl enable cloudflared 2>/dev/null || true
694
- $SUDO systemctl start cloudflared 2>/dev/null || true
694
+ # Install and start cloudflared service (process-manager aware)
695
+ case "$PROC_MGR" in
696
+ systemd)
697
+ $SUDO cloudflared service install 2>/dev/null || true
698
+ $SUDO systemctl enable cloudflared 2>/dev/null || true
699
+ $SUDO systemctl start cloudflared 2>/dev/null || true
700
+ ;;
701
+ supervisord)
702
+ # Create supervisord config for cloudflared
703
+ $SUDO tee /etc/supervisor/conf.d/cloudflared.conf > /dev/null <<CFEOF
704
+ [program:cloudflared]
705
+ command=/usr/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
706
+ autorestart=true
707
+ priority=150
708
+ startsecs=5
709
+ stdout_logfile=/var/log/supervisor/cloudflared.log
710
+ stderr_logfile=/var/log/supervisor/cloudflared.log
711
+ CFEOF
712
+ # Reload supervisord if running
713
+ if $SUDO supervisorctl status &>/dev/null; then
714
+ $SUDO supervisorctl reread
715
+ $SUDO supervisorctl update
716
+ fi
717
+ ;;
718
+ *)
719
+ echo " WARNING: No supported process manager for cloudflared"
720
+ echo " You may need to start cloudflared manually:"
721
+ echo " cloudflared tunnel --config /etc/cloudflared/config.yml run"
722
+ ;;
723
+ esac
695
724
  echo " -> cloudflared tunnel configured and started"
696
725
  fi
697
726
  fi
@@ -701,10 +730,12 @@ SUPEOF
701
730
  echo ""
702
731
  echo "Notifying HQ of setup completion..."
703
732
  local NOTIFY_RESPONSE
733
+ local HOSTNAME_VAL
734
+ HOSTNAME_VAL=$(hostname 2>/dev/null || echo "")
704
735
  NOTIFY_RESPONSE=$(curl -sfL -X POST "${HQ_URL}/api/minion/setup-complete" \
705
736
  -H "Content-Type: application/json" \
706
737
  -H "Authorization: Bearer ${API_TOKEN}" \
707
- -d "{}" 2>&1) || true
738
+ -d "{\"internal_ip_address\":\"${HOSTNAME_VAL}\"}" 2>&1) || true
708
739
 
709
740
  if echo "$NOTIFY_RESPONSE" | grep -q '"success":true' 2>/dev/null; then
710
741
  echo " -> HQ notified successfully"
@@ -854,6 +885,6 @@ case "${1:-}" in
854
885
  echo "Status values: online, offline, busy"
855
886
  echo ""
856
887
  echo "Environment:"
857
- echo " MINION_AGENT_URL Agent URL (default: http://localhost:3001)"
888
+ echo " MINION_AGENT_URL Agent URL (default: http://localhost:8080)"
858
889
  ;;
859
890
  esac
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekbeer/minion",
3
- "version": "2.16.5",
3
+ "version": "2.23.0",
4
4
  "description": "AI Agent runtime for Minion - manages status and skill deployment on VPS",
5
5
  "main": "server.js",
6
6
  "bin": {
package/roles/pm.md CHANGED
@@ -25,7 +25,7 @@
25
25
  ポイント:
26
26
  - HQの責務は「executionレコードを作る(指示書発行)」だけ
27
27
  - 各ミニオンは自分の担当ステップだけをポーリングして実行
28
- - ミニオンエージェント(Port 3001)が軽量HTTPポーリングを行い、pending検知時のみClaude Codeを起動
28
+ - ミニオンエージェント(Port 8080)が軽量HTTPポーリングを行い、pending検知時のみClaude Codeを起動
29
29
 
30
30
  ## Workflow 管理
31
31