@agilemonster/mcp-server 0.0.0-stage → 1.0.1

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.
@@ -0,0 +1,27 @@
1
+ import { AgileMonsterClient } from './client.js';
2
+ import { Card } from './types.js';
3
+ export interface OrchestratorOptions {
4
+ watch?: boolean;
5
+ intervalMs?: number;
6
+ provider?: string;
7
+ boardId?: string;
8
+ }
9
+ export declare class AgileMonsterOrchestrator {
10
+ private client;
11
+ constructor(client?: AgileMonsterClient);
12
+ checkTasks(options?: {
13
+ provider?: string;
14
+ boardId?: string;
15
+ }): Promise<Card[]>;
16
+ printDashboard(): Promise<void>;
17
+ runDaemon(options?: OrchestratorOptions): Promise<void>;
18
+ initInteractive(options?: {
19
+ provider?: string;
20
+ ide?: string;
21
+ }): Promise<void>;
22
+ bootstrapInteractive(options?: {
23
+ provider?: string;
24
+ ide?: string;
25
+ }): Promise<void>;
26
+ configureIdes(apiKey: string, selectedIde?: string): void;
27
+ }
@@ -0,0 +1,306 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
3
+ import { AgileMonsterClient } from './client.js';
4
+ import { AGENT_GUIDELINES_MARKDOWN } from './guidelines.js';
5
+ export class AgileMonsterOrchestrator {
6
+ client;
7
+ constructor(client = new AgileMonsterClient()) {
8
+ this.client = client;
9
+ }
10
+ async checkTasks(options) {
11
+ const projectConfig = this.client.loadProjectConfig();
12
+ const provider = options?.provider || projectConfig?.provider || 'any';
13
+ const boardId = options?.boardId || projectConfig?.board_id;
14
+ const result = await this.client.listAssigned(provider, undefined, boardId);
15
+ return result.cards || [];
16
+ }
17
+ async printDashboard() {
18
+ console.log('\n======================================================');
19
+ console.log(' šŸ‘¾ AGILE MONSTER AGENT ORCHESTRATOR ');
20
+ console.log('======================================================\n');
21
+ const config = this.client.loadProjectConfig();
22
+ const cwdName = path.basename(process.cwd());
23
+ try {
24
+ const me = await this.client.me();
25
+ console.log(`šŸ‘¤ Connected as: ${me.email} (${me.first_name || ''} ${me.last_name || ''})`);
26
+ }
27
+ catch (e) {
28
+ console.error(`āŒ Authentication failed: ${e.message}`);
29
+ return;
30
+ }
31
+ if (config?.board_id) {
32
+ console.log(`šŸ“ Project bound to Board: ${config.board_id} (${config.board_name || cwdName})`);
33
+ console.log(`šŸ¤– Default Provider: ${config.provider || 'any'}`);
34
+ }
35
+ else {
36
+ console.log(`ā„¹ļø No .agilemonster.json found in current directory (${cwdName}).`);
37
+ console.log(' Run "agilemonster-orchestrator init" to bind this repo to a board.\n');
38
+ }
39
+ console.log('\nšŸ” Checking for assigned agent tasks...');
40
+ const tasks = await this.checkTasks();
41
+ if (tasks.length === 0) {
42
+ console.log('✨ No pending tasks assigned to agents for this project right now.');
43
+ console.log(' Assign a card to an AI agent in the Agile Monster board to get started!\n');
44
+ return;
45
+ }
46
+ console.log(`\nšŸ“‹ Found ${tasks.length} active agent task(s):\n`);
47
+ for (const t of tasks) {
48
+ const statusIcon = t.agent_status === 'queued'
49
+ ? 'ā³ [QUEUED]'
50
+ : t.agent_status === 'in_progress'
51
+ ? 'āš™ļø [IN PROGRESS]'
52
+ : t.agent_status === 'waiting_for_input'
53
+ ? 'ā“ [WAITING INPUT]'
54
+ : t.agent_status === 'review'
55
+ ? 'šŸ” [IN REVIEW]'
56
+ : `[${t.agent_status?.toUpperCase() || 'ASSIGNED'}]`;
57
+ console.log(`------------------------------------------------------`);
58
+ console.log(`${statusIcon} ${t.title}`);
59
+ console.log(` ID: ${t.id}`);
60
+ console.log(` Column: ${t.list_name || t.list_id}`);
61
+ console.log(` Board: ${t.board_name || t.board_id}`);
62
+ console.log(` Worker: ${t.agent_provider || 'any'}`);
63
+ if (t.description) {
64
+ const preview = t.description.slice(0, 120).replace(/\n/g, ' ');
65
+ console.log(` Details: ${preview}${t.description.length > 120 ? '...' : ''}`);
66
+ }
67
+ console.log(` Actions:`);
68
+ console.log(` • Claim: agilemonster-orchestrator claim ${t.id}`);
69
+ console.log(` • Review: agilemonster-orchestrator review ${t.id} "Summary..."`);
70
+ console.log(` • Question: agilemonster-orchestrator question ${t.id} "Question..."`);
71
+ }
72
+ console.log(`------------------------------------------------------\n`);
73
+ }
74
+ async runDaemon(options = {}) {
75
+ const interval = options.intervalMs || 15000;
76
+ console.log(`šŸš€ Starting Agile Monster Orchestrator daemon (polling every ${interval / 1000}s)...`);
77
+ console.log('Press Ctrl+C to stop.\n');
78
+ const seenTaskIds = new Set();
79
+ const poll = async () => {
80
+ try {
81
+ const tasks = await this.checkTasks(options);
82
+ for (const task of tasks) {
83
+ if (task.agent_status === 'queued' && !seenTaskIds.has(task.id)) {
84
+ seenTaskIds.add(task.id);
85
+ console.log(`\nšŸ”” [NEW TASK DETECTED] ${task.title}`);
86
+ console.log(` Card ID: ${task.id}`);
87
+ console.log(` Board: ${task.board_name || task.board_id}`);
88
+ console.log(` Worker: ${task.agent_provider || 'agent'}`);
89
+ if (task.description) {
90
+ console.log(` Description:\n${task.description}\n`);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ catch (err) {
96
+ console.error(`[Orchestrator Polling Error]: ${err.message}`);
97
+ }
98
+ };
99
+ await poll();
100
+ setInterval(poll, interval);
101
+ }
102
+ async initInteractive(options) {
103
+ console.log('\n======================================================');
104
+ console.log(' šŸ‘¾ AGILE MONSTER 1-CLICK AGENT SETUP ');
105
+ console.log('======================================================\n');
106
+ let apiKey = this.client.getApiKey();
107
+ if (!apiKey) {
108
+ console.log('šŸ”‘ No Agile Monster API key detected.');
109
+ console.log(' Generate an API key in: https://app.agilemonster.com/profile (API Keys tab)\n');
110
+ const readline = await import('node:readline/promises');
111
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
112
+ try {
113
+ const inputKey = await rl.question('šŸ‘‰ Paste your Personal API Key (am_live_...): ');
114
+ if (inputKey && inputKey.trim()) {
115
+ apiKey = inputKey.trim();
116
+ this.client.setApiKey(apiKey);
117
+ AgileMonsterClient.saveGlobalConfig({ api_key: apiKey });
118
+ console.log('āœ… API key saved to ~/.agilemonster/config.json (usable across all projects)!');
119
+ }
120
+ else {
121
+ console.error('āŒ API key is required to connect to Agile Monster.');
122
+ return;
123
+ }
124
+ }
125
+ finally {
126
+ rl.close();
127
+ }
128
+ }
129
+ console.log('\nšŸ” Discovering Agile Monster boards for this repository...');
130
+ const context = await this.client.getContext(path.basename(process.cwd()));
131
+ if (!context.available_boards || context.available_boards.length === 0) {
132
+ console.log('No boards found in your account. Please create a board first on https://app.agilemonster.com');
133
+ return;
134
+ }
135
+ const targetBoard = context.matched_board || context.available_boards[0];
136
+ const savedPath = this.client.saveProjectConfig({
137
+ workspace_id: targetBoard.workspace_id,
138
+ board_id: targetBoard.id,
139
+ board_name: targetBoard.name,
140
+ provider: 'antigravity',
141
+ review_list: 'In Review',
142
+ done_list: 'Done',
143
+ api_key: apiKey,
144
+ });
145
+ console.log(`āœ… Bound repository to board "${targetBoard.name}" (${targetBoard.id})`);
146
+ console.log(` Config written to: ${savedPath}`);
147
+ // Ensure AGENTS.md exists
148
+ const agentsPath = path.resolve(process.cwd(), 'AGENTS.md');
149
+ if (!fs.existsSync(agentsPath)) {
150
+ fs.writeFileSync(agentsPath, AGENT_GUIDELINES_MARKDOWN, 'utf-8');
151
+ console.log(`šŸ“„ Created AGENTS.md with autonomous agent operational guidelines.`);
152
+ }
153
+ else {
154
+ console.log(`šŸ“„ AGENTS.md already exists in current directory.`);
155
+ }
156
+ // Configure IDEs (Cursor, Claude Code, Windsurf, Antigravity, VS Code)
157
+ this.configureIdes(apiKey, options?.provider);
158
+ console.log('\nšŸŽ‰ Project successfully configured for AI Agents (Cursor, Claude Code, Antigravity, Windsurf)!');
159
+ }
160
+ async bootstrapInteractive(options) {
161
+ return this.initInteractive(options);
162
+ }
163
+ configureIdes(apiKey, selectedIde) {
164
+ const homedir = process.env.HOME || process.env.USERPROFILE || '';
165
+ const ide = (selectedIde || 'all').toLowerCase();
166
+ // 1. Cursor (.cursor/mcp.json)
167
+ if (ide === 'all' || ide === 'cursor') {
168
+ try {
169
+ const cursorDir = path.resolve(process.cwd(), '.cursor');
170
+ const cursorMcpPath = path.join(cursorDir, 'mcp.json');
171
+ if (!fs.existsSync(cursorDir))
172
+ fs.mkdirSync(cursorDir, { recursive: true });
173
+ let existing = { mcpServers: {} };
174
+ if (fs.existsSync(cursorMcpPath)) {
175
+ try {
176
+ existing = JSON.parse(fs.readFileSync(cursorMcpPath, 'utf8'));
177
+ }
178
+ catch { }
179
+ }
180
+ existing.mcpServers = existing.mcpServers || {};
181
+ existing.mcpServers.agilemonster = {
182
+ command: 'npx',
183
+ args: ['-y', '@agilemonster/mcp-server'],
184
+ env: {
185
+ AGILEMONSTER_API_KEY: apiKey,
186
+ AGILEMONSTER_API_URL: 'https://api.agilemonster.com',
187
+ },
188
+ };
189
+ fs.writeFileSync(cursorMcpPath, JSON.stringify(existing, null, 2), 'utf8');
190
+ console.log(`šŸ¤– Configured Cursor in: .cursor/mcp.json`);
191
+ }
192
+ catch (e) {
193
+ console.warn(`Could not write Cursor config: ${e.message}`);
194
+ }
195
+ }
196
+ // 2. Claude Code (.mcp.json)
197
+ if (ide === 'all' || ide === 'claude' || ide === 'claude_code') {
198
+ try {
199
+ const claudeMcpPath = path.resolve(process.cwd(), '.mcp.json');
200
+ let existing = { mcpServers: {} };
201
+ if (fs.existsSync(claudeMcpPath)) {
202
+ try {
203
+ existing = JSON.parse(fs.readFileSync(claudeMcpPath, 'utf8'));
204
+ }
205
+ catch { }
206
+ }
207
+ existing.mcpServers = existing.mcpServers || {};
208
+ existing.mcpServers.agilemonster = {
209
+ command: 'npx',
210
+ args: ['-y', '@agilemonster/mcp-server'],
211
+ env: {
212
+ AGILEMONSTER_API_KEY: apiKey,
213
+ AGILEMONSTER_API_URL: 'https://api.agilemonster.com',
214
+ },
215
+ };
216
+ fs.writeFileSync(claudeMcpPath, JSON.stringify(existing, null, 2), 'utf8');
217
+ console.log(`šŸ¤– Configured Claude Code in: .mcp.json`);
218
+ }
219
+ catch (e) {
220
+ console.warn(`Could not write Claude Code config: ${e.message}`);
221
+ }
222
+ }
223
+ // 3. Windsurf (~/.codeium/windsurf/mcp_config.json)
224
+ if ((ide === 'all' || ide === 'windsurf') && homedir) {
225
+ try {
226
+ const windsurfDir = path.join(homedir, '.codeium', 'windsurf');
227
+ const windsurfMcpPath = path.join(windsurfDir, 'mcp_config.json');
228
+ if (fs.existsSync(windsurfDir) || ide === 'windsurf') {
229
+ if (!fs.existsSync(windsurfDir))
230
+ fs.mkdirSync(windsurfDir, { recursive: true });
231
+ let existing = { mcpServers: {} };
232
+ if (fs.existsSync(windsurfMcpPath)) {
233
+ try {
234
+ existing = JSON.parse(fs.readFileSync(windsurfMcpPath, 'utf8'));
235
+ }
236
+ catch { }
237
+ }
238
+ existing.mcpServers = existing.mcpServers || {};
239
+ existing.mcpServers.agilemonster = {
240
+ command: 'npx',
241
+ args: ['-y', '@agilemonster/mcp-server'],
242
+ env: {
243
+ AGILEMONSTER_API_KEY: apiKey,
244
+ AGILEMONSTER_API_URL: 'https://api.agilemonster.com',
245
+ },
246
+ };
247
+ fs.writeFileSync(windsurfMcpPath, JSON.stringify(existing, null, 2), 'utf8');
248
+ console.log(`šŸ¤– Configured Windsurf in: ~/.codeium/windsurf/mcp_config.json`);
249
+ }
250
+ }
251
+ catch { }
252
+ }
253
+ // 4. Antigravity / Gemini (~/.gemini/antigravity/mcp/agilemonster.json)
254
+ if ((ide === 'all' || ide === 'antigravity' || ide === 'gemini') && homedir) {
255
+ try {
256
+ const antigravityDir = path.join(homedir, '.gemini', 'antigravity', 'mcp');
257
+ const antigravityMcpPath = path.join(antigravityDir, 'agilemonster.json');
258
+ if (fs.existsSync(antigravityDir) || ide === 'antigravity') {
259
+ if (!fs.existsSync(antigravityDir))
260
+ fs.mkdirSync(antigravityDir, { recursive: true });
261
+ const config = {
262
+ command: 'npx',
263
+ args: ['-y', '@agilemonster/mcp-server'],
264
+ env: {
265
+ AGILEMONSTER_API_KEY: apiKey,
266
+ AGILEMONSTER_API_URL: 'https://api.agilemonster.com',
267
+ },
268
+ };
269
+ fs.writeFileSync(antigravityMcpPath, JSON.stringify(config, null, 2), 'utf8');
270
+ console.log(`šŸ¤– Configured Antigravity in: ~/.gemini/antigravity/mcp/agilemonster.json`);
271
+ }
272
+ }
273
+ catch { }
274
+ }
275
+ // 5. VS Code (.vscode/mcp.json)
276
+ if (ide === 'all' || ide === 'vscode' || ide === 'codex') {
277
+ try {
278
+ const vscodeDir = path.resolve(process.cwd(), '.vscode');
279
+ const vscodeMcpPath = path.join(vscodeDir, 'mcp.json');
280
+ if (fs.existsSync(vscodeDir) || ide === 'vscode') {
281
+ if (!fs.existsSync(vscodeDir))
282
+ fs.mkdirSync(vscodeDir, { recursive: true });
283
+ let existing = { mcpServers: {} };
284
+ if (fs.existsSync(vscodeMcpPath)) {
285
+ try {
286
+ existing = JSON.parse(fs.readFileSync(vscodeMcpPath, 'utf8'));
287
+ }
288
+ catch { }
289
+ }
290
+ existing.mcpServers = existing.mcpServers || {};
291
+ existing.mcpServers.agilemonster = {
292
+ command: 'npx',
293
+ args: ['-y', '@agilemonster/mcp-server'],
294
+ env: {
295
+ AGILEMONSTER_API_KEY: apiKey,
296
+ AGILEMONSTER_API_URL: 'https://api.agilemonster.com',
297
+ },
298
+ };
299
+ fs.writeFileSync(vscodeMcpPath, JSON.stringify(existing, null, 2), 'utf8');
300
+ console.log(`šŸ¤– Configured VS Code in: .vscode/mcp.json`);
301
+ }
302
+ }
303
+ catch { }
304
+ }
305
+ }
306
+ }
@@ -0,0 +1,37 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { AgileMonsterClient } from './client.js';
3
+ export declare function createServer(client?: AgileMonsterClient): Server<{
4
+ method: string;
5
+ params?: {
6
+ [x: string]: unknown;
7
+ _meta?: {
8
+ [x: string]: unknown;
9
+ progressToken?: string | number | undefined;
10
+ "io.modelcontextprotocol/related-task"?: {
11
+ taskId: string;
12
+ } | undefined;
13
+ } | undefined;
14
+ } | undefined;
15
+ }, {
16
+ method: string;
17
+ params?: {
18
+ [x: string]: unknown;
19
+ _meta?: {
20
+ [x: string]: unknown;
21
+ progressToken?: string | number | undefined;
22
+ "io.modelcontextprotocol/related-task"?: {
23
+ taskId: string;
24
+ } | undefined;
25
+ } | undefined;
26
+ } | undefined;
27
+ }, {
28
+ [x: string]: unknown;
29
+ _meta?: {
30
+ [x: string]: unknown;
31
+ progressToken?: string | number | undefined;
32
+ "io.modelcontextprotocol/related-task"?: {
33
+ taskId: string;
34
+ } | undefined;
35
+ } | undefined;
36
+ }>;
37
+ export declare function runStdioServer(): Promise<void>;