@agilemonster/mcp-server 1.0.16 → 1.0.22
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/README.md +27 -1
- package/bin/mcp.js +0 -0
- package/bin/orchestrator.js +0 -0
- package/bin/worker.js +0 -0
- package/dist/client.d.ts +21 -4
- package/dist/client.js +119 -101
- package/dist/deploy-memory.d.ts +122 -0
- package/dist/deploy-memory.js +192 -0
- package/dist/deploy-profile.d.ts +151 -0
- package/dist/deploy-profile.js +993 -0
- package/dist/deploy-runner.d.ts +144 -0
- package/dist/deploy-runner.js +1108 -0
- package/dist/guidelines.d.ts +1 -1
- package/dist/guidelines.js +6 -0
- package/dist/ide-config.d.ts +44 -0
- package/dist/ide-config.js +250 -0
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.js +18 -165
- package/dist/redact.d.ts +15 -0
- package/dist/redact.js +58 -0
- package/dist/runtime.d.ts +64 -0
- package/dist/runtime.js +293 -0
- package/dist/server.d.ts +16 -3
- package/dist/server.js +1427 -547
- package/dist/types.d.ts +29 -0
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ This generates:
|
|
|
74
74
|
|
|
75
75
|
## 🛠️ Available MCP Tools
|
|
76
76
|
|
|
77
|
-
Agents have access to
|
|
77
|
+
Agents have access to these purpose-built lifecycle tools:
|
|
78
78
|
|
|
79
79
|
| Tool | Purpose |
|
|
80
80
|
| :--- | :--- |
|
|
@@ -86,6 +86,32 @@ Agents have access to 8 purpose-built lifecycle tools:
|
|
|
86
86
|
| `agilemonster_add_progress` | Logs implementation progress notes to task comments. |
|
|
87
87
|
| `agilemonster_submit_for_review` | Marks work complete, moves card to Review column, reassigns to human member for confirmation, and posts test instructions. |
|
|
88
88
|
| `agilemonster_create_followup_tasks` | Creates follow-up cards (e.g. "Deploy to Test", "Deploy to Production", "Write integration tests"). |
|
|
89
|
+
| `agilemonster_get_deploy_profile` | How this project deploys: route, exact command, confidence, the evidence behind it, alternatives, and recent outcomes. |
|
|
90
|
+
| `agilemonster_record_deployment` | Records how a deployment went (or pins the route the user stated) so every later task deploys the same proven way. |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🚀 How deployment is decided (and remembered)
|
|
95
|
+
|
|
96
|
+
Cards started from the Agile Monster web app run in the background without your IDE's context, so the
|
|
97
|
+
server works out how a project ships from evidence and from what worked before:
|
|
98
|
+
|
|
99
|
+
1. **Explicit** — `.agilemonster/deploy.json` in the repo (`{"method": "docker_compose", "command": "...", "live_url": "..."}`), or a route pinned with `agilemonster_record_deployment({ pin: true })` / a card reply.
|
|
100
|
+
2. **Learned** — the last deployment that was verified on this machine.
|
|
101
|
+
3. **Evidence, ranked** — a deploy workflow that really fires on a push to the checked-out branch (path filters and `workflow_run` chains included) › a deploy script › a cloud CLI config › the Docker Compose stack that is running from this folder (reused with its exact project name and files) › a compose file › a plain `git push`.
|
|
102
|
+
|
|
103
|
+
What the runner guarantees:
|
|
104
|
+
|
|
105
|
+
- **Commits only the files it changed** — never `git add -A`; local files holding your API key are filtered and added to `.git/info/exclude`.
|
|
106
|
+
- **Verifies before claiming "Deployed"** — deploy workflow run for that commit, container state and health, script exit code, and a smoke check of a URL you provided. A guessed URL can never fail a deploy.
|
|
107
|
+
- **Asks once, then remembers** — an unconfirmed deploy script, cloud CLI or manually-dispatched workflow is not run on a guess. Reply on the card with `deploy: <command or method>` to confirm; `retry` re-runs only the deployment, not the code change.
|
|
108
|
+
- **Heals what it can** — starts Docker Desktop/OrbStack if it is installed but stopped, rebases and re-pushes when the remote moved ahead, retries network errors, and falls back to the next route when the chosen one plainly does not apply.
|
|
109
|
+
- **Never reports a slow pipeline as failed** — a CI run that outlives the wait is marked pending and re-checked on later pulses; the outcome is posted on the card.
|
|
110
|
+
|
|
111
|
+
State lives outside your repositories: `~/.agilemonster/projects/` (per-project deployment history) and
|
|
112
|
+
`~/.agilemonster/logs/daemon.jsonl` (structured daemon log).
|
|
113
|
+
|
|
114
|
+
Card reply syntax: `retry` · `deploy: github_actions` · `deploy: docker_compose` · `deploy: manual` · `deploy: ./deploy/deploy.sh` · `live url: https://example.com`
|
|
89
115
|
|
|
90
116
|
---
|
|
91
117
|
|
package/bin/mcp.js
CHANGED
|
File without changes
|
package/bin/orchestrator.js
CHANGED
|
File without changes
|
package/bin/worker.js
CHANGED
|
File without changes
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AgileMonsterProjectConfig, AutonomousStepResponse, Board, BoardAgentConfig, Card, ContextResponse, DiscoveredProject, PulseResponse } from './types.js';
|
|
2
|
-
export declare const MCP_SERVER_VERSION = "1.0.
|
|
1
|
+
import { AgileMonsterProjectConfig, AutonomousStepResponse, CardComment, DeployReport, Board, BoardAgentConfig, Card, ContextResponse, DiscoveredProject, PulseResponse } from './types.js';
|
|
2
|
+
export declare const MCP_SERVER_VERSION = "1.0.22";
|
|
3
3
|
export declare class AgileMonsterClient {
|
|
4
4
|
private apiKey;
|
|
5
5
|
private baseUrl;
|
|
@@ -40,7 +40,13 @@ export declare class AgileMonsterClient {
|
|
|
40
40
|
default_model?: string | null;
|
|
41
41
|
models: Record<string, string> | string[];
|
|
42
42
|
}>;
|
|
43
|
+
installedAgents?: string[];
|
|
43
44
|
}): Promise<PulseResponse>;
|
|
45
|
+
/**
|
|
46
|
+
* Cross-platform detection of AI coding agents installed on this computer.
|
|
47
|
+
* Checks for Cursor, Claude Code, Antigravity, Codex, Hermes, Windsurf, Aider.
|
|
48
|
+
*/
|
|
49
|
+
static detectInstalledAgents(): string[];
|
|
44
50
|
/**
|
|
45
51
|
* Discover live models installed/configured across the developer's local AI coding agents
|
|
46
52
|
* (Codex, Cursor, Claude Code, Hermes, Antigravity) so the Agile Monster app & website
|
|
@@ -51,13 +57,18 @@ export declare class AgileMonsterClient {
|
|
|
51
57
|
models: Record<string, string>;
|
|
52
58
|
}>;
|
|
53
59
|
/**
|
|
54
|
-
*
|
|
60
|
+
* Describe how a project folder builds and deploys, for the server's project/board bindings.
|
|
61
|
+
* Backed by the evidence-ranked resolver (running containers, real workflow triggers, deploy scripts,
|
|
62
|
+
* project docs) plus this machine's deployment memory, so what the web app shows matches what will run.
|
|
55
63
|
*/
|
|
56
|
-
static inspectProjectProfile(fullPath: string,
|
|
64
|
+
static inspectProjectProfile(fullPath: string, _name?: string): {
|
|
57
65
|
build_command: string | null;
|
|
58
66
|
deploy_method: string | null;
|
|
59
67
|
deploy_command: string | null;
|
|
60
68
|
live_url: string | null;
|
|
69
|
+
deploy_source: string;
|
|
70
|
+
deploy_confidence: string;
|
|
71
|
+
deploy_evidence: string;
|
|
61
72
|
};
|
|
62
73
|
/**
|
|
63
74
|
* Scan the developer's local workspace roots (sibling folders in parent dev dir, ~/dev, ~/Projects, etc.)
|
|
@@ -88,6 +99,12 @@ export declare class AgileMonsterClient {
|
|
|
88
99
|
}>): Promise<{
|
|
89
100
|
tasks: Card[];
|
|
90
101
|
}>;
|
|
102
|
+
listComments(cardId: string): Promise<CardComment[]>;
|
|
103
|
+
/**
|
|
104
|
+
* Tell the server how a deployment went so the board binding learns the verified route (or the failure).
|
|
105
|
+
* Older backends do not have this endpoint; that must never break a deployment.
|
|
106
|
+
*/
|
|
107
|
+
reportDeployment(report: DeployReport): Promise<boolean>;
|
|
91
108
|
autonomousStep(payload: {
|
|
92
109
|
card_id: string;
|
|
93
110
|
action: 'select_files' | 'generate_edits';
|
package/dist/client.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
|
-
|
|
4
|
+
import { resolveDeployProfile } from './deploy-profile.js';
|
|
5
|
+
import { loadMemory } from './deploy-memory.js';
|
|
6
|
+
import { stripRemoteCredentials } from './redact.js';
|
|
7
|
+
export const MCP_SERVER_VERSION = '1.0.22';
|
|
5
8
|
export class AgileMonsterClient {
|
|
6
9
|
apiKey = '';
|
|
7
10
|
baseUrl;
|
|
@@ -85,7 +88,7 @@ export class AgileMonsterClient {
|
|
|
85
88
|
catch {
|
|
86
89
|
// Ignore reading error
|
|
87
90
|
}
|
|
88
|
-
this
|
|
91
|
+
// Not cached: bootstrap may write the file while this server is running, and the tools must then see it
|
|
89
92
|
return null;
|
|
90
93
|
}
|
|
91
94
|
saveProjectConfig(config, dir) {
|
|
@@ -155,7 +158,7 @@ export class AgileMonsterClient {
|
|
|
155
158
|
if (boardId)
|
|
156
159
|
params.set('board_id', boardId);
|
|
157
160
|
if (gitRemote)
|
|
158
|
-
params.set('git_remote', gitRemote);
|
|
161
|
+
params.set('git_remote', stripRemoteCredentials(gitRemote));
|
|
159
162
|
if (detectedIdes && detectedIdes.length > 0) {
|
|
160
163
|
params.set('detected_ides', detectedIdes.join(','));
|
|
161
164
|
}
|
|
@@ -180,13 +183,14 @@ export class AgileMonsterClient {
|
|
|
180
183
|
agents,
|
|
181
184
|
project_name: projectName,
|
|
182
185
|
project_path: projectPath,
|
|
183
|
-
git_remote: gitRemote,
|
|
186
|
+
git_remote: gitRemote ? stripRemoteCredentials(gitRemote) : gitRemote,
|
|
184
187
|
mcp_version: MCP_SERVER_VERSION,
|
|
185
188
|
connected: true,
|
|
186
189
|
}),
|
|
187
190
|
});
|
|
188
191
|
}
|
|
189
192
|
async pulse(options) {
|
|
193
|
+
const installed = options.installedAgents || AgileMonsterClient.detectInstalledAgents();
|
|
190
194
|
return this.request('/api/agent/pulse', {
|
|
191
195
|
method: 'POST',
|
|
192
196
|
body: JSON.stringify({
|
|
@@ -197,9 +201,73 @@ export class AgileMonsterClient {
|
|
|
197
201
|
mcp_version: MCP_SERVER_VERSION,
|
|
198
202
|
discovered_projects: options.discoveredProjects,
|
|
199
203
|
discovered_models: options.discoveredModels,
|
|
204
|
+
installed_agents: installed,
|
|
200
205
|
}),
|
|
201
206
|
});
|
|
202
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Cross-platform detection of AI coding agents installed on this computer.
|
|
210
|
+
* Checks for Cursor, Claude Code, Antigravity, Codex, Hermes, Windsurf, Aider.
|
|
211
|
+
*/
|
|
212
|
+
static detectInstalledAgents() {
|
|
213
|
+
const homedir = process.env.HOME || process.env.USERPROFILE || '';
|
|
214
|
+
const detected = new Set();
|
|
215
|
+
const exists = (...p) => {
|
|
216
|
+
try {
|
|
217
|
+
const full = path.join(...p);
|
|
218
|
+
return fs.existsSync(full);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
// 1. Antigravity
|
|
225
|
+
if (exists(homedir, '.gemini') ||
|
|
226
|
+
exists(homedir, '.antigravity') ||
|
|
227
|
+
Boolean(process.env.ANTIGRAVITY_APP_DATA_DIR) ||
|
|
228
|
+
Boolean(process.env.GEMINI_CLI)) {
|
|
229
|
+
detected.add('antigravity');
|
|
230
|
+
}
|
|
231
|
+
// 2. Cursor
|
|
232
|
+
if (exists(homedir, '.cursor') ||
|
|
233
|
+
exists(homedir, 'Library', 'Application Support', 'Cursor') ||
|
|
234
|
+
exists(process.env.APPDATA || '', 'Cursor') ||
|
|
235
|
+
exists(homedir, '.config', 'Cursor') ||
|
|
236
|
+
exists(process.cwd(), '.cursor')) {
|
|
237
|
+
detected.add('cursor');
|
|
238
|
+
}
|
|
239
|
+
// 3. Claude Code
|
|
240
|
+
if (exists(homedir, '.claude') ||
|
|
241
|
+
exists(homedir, '.claude.json') ||
|
|
242
|
+
exists(homedir, '.config', 'claude') ||
|
|
243
|
+
exists(process.cwd(), '.mcp.json')) {
|
|
244
|
+
detected.add('claude_code');
|
|
245
|
+
}
|
|
246
|
+
// 4. Codex
|
|
247
|
+
if (exists(homedir, '.codex') ||
|
|
248
|
+
exists(process.cwd(), '.codex')) {
|
|
249
|
+
detected.add('codex');
|
|
250
|
+
}
|
|
251
|
+
// 5. Hermes
|
|
252
|
+
if (exists(homedir, '.hermes') ||
|
|
253
|
+
exists(homedir, '.local', 'bin', 'hermes')) {
|
|
254
|
+
detected.add('hermes');
|
|
255
|
+
}
|
|
256
|
+
// 6. Windsurf
|
|
257
|
+
if (exists(homedir, '.codeium', 'windsurf') ||
|
|
258
|
+
exists(homedir, '.windsurf') ||
|
|
259
|
+
exists(homedir, 'Library', 'Application Support', 'Windsurf') ||
|
|
260
|
+
exists(process.env.APPDATA || '', 'Windsurf') ||
|
|
261
|
+
exists(homedir, '.config', 'Windsurf')) {
|
|
262
|
+
detected.add('windsurf');
|
|
263
|
+
}
|
|
264
|
+
// 7. Aider
|
|
265
|
+
if (exists(homedir, '.aider') ||
|
|
266
|
+
exists(homedir, '.aider.conf.yml')) {
|
|
267
|
+
detected.add('aider');
|
|
268
|
+
}
|
|
269
|
+
return Array.from(detected);
|
|
270
|
+
}
|
|
203
271
|
/**
|
|
204
272
|
* Discover live models installed/configured across the developer's local AI coding agents
|
|
205
273
|
* (Codex, Cursor, Claude Code, Hermes, Antigravity) so the Agile Monster app & website
|
|
@@ -328,103 +396,35 @@ export class AgileMonsterClient {
|
|
|
328
396
|
return result;
|
|
329
397
|
}
|
|
330
398
|
/**
|
|
331
|
-
*
|
|
399
|
+
* Describe how a project folder builds and deploys, for the server's project/board bindings.
|
|
400
|
+
* Backed by the evidence-ranked resolver (running containers, real workflow triggers, deploy scripts,
|
|
401
|
+
* project docs) plus this machine's deployment memory, so what the web app shows matches what will run.
|
|
332
402
|
*/
|
|
333
|
-
static inspectProjectProfile(fullPath,
|
|
334
|
-
let buildCmd = null;
|
|
335
|
-
let deployMethod = null;
|
|
336
|
-
let deployCmd = null;
|
|
337
|
-
let liveUrl = null;
|
|
338
|
-
// 1. Detect Build Command
|
|
403
|
+
static inspectProjectProfile(fullPath, _name) {
|
|
339
404
|
try {
|
|
340
|
-
const
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const pkg = JSON.parse(fs.readFileSync(rootPkg, 'utf8'));
|
|
352
|
-
if (pkg?.scripts?.build) {
|
|
353
|
-
buildCmd = fs.existsSync(path.join(fullPath, 'pnpm-lock.yaml'))
|
|
354
|
-
? 'pnpm run build'
|
|
355
|
-
: 'npm run build';
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
else if (fs.existsSync(path.join(fullPath, 'frontend-flutter', 'pubspec.yaml'))) {
|
|
359
|
-
buildCmd = 'cd frontend-flutter && flutter analyze';
|
|
360
|
-
}
|
|
361
|
-
else if (fs.existsSync(path.join(fullPath, 'pubspec.yaml'))) {
|
|
362
|
-
buildCmd = 'flutter analyze';
|
|
363
|
-
}
|
|
405
|
+
const profile = resolveDeployProfile(fullPath, { memory: loadMemory(fullPath) });
|
|
406
|
+
const source = profile.source === 'explicit' ? 'user' : profile.source === 'learned' || profile.source === 'verified' ? 'verified' : 'auto';
|
|
407
|
+
return {
|
|
408
|
+
build_command: profile.buildCommand,
|
|
409
|
+
deploy_method: profile.method === 'none' ? null : profile.method,
|
|
410
|
+
deploy_command: profile.command,
|
|
411
|
+
live_url: profile.liveUrl,
|
|
412
|
+
deploy_source: source,
|
|
413
|
+
deploy_confidence: profile.confidence,
|
|
414
|
+
deploy_evidence: profile.evidence.slice(0, 3).join(' · ').slice(0, 480),
|
|
415
|
+
};
|
|
364
416
|
}
|
|
365
|
-
catch {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
: './deploy/deploy.sh';
|
|
376
|
-
}
|
|
377
|
-
else if (fs.existsSync(scriptsDeploySh)) {
|
|
378
|
-
deployMethod = 'deploy_script';
|
|
379
|
-
deployCmd = './scripts/deploy.sh';
|
|
380
|
-
}
|
|
381
|
-
else if (fs.existsSync(path.join(fullPath, '.github', 'workflows'))) {
|
|
382
|
-
deployMethod = 'github_actions';
|
|
383
|
-
deployCmd = 'git push origin HEAD (GitHub Actions CI/CD)';
|
|
384
|
-
}
|
|
385
|
-
else if (fs.existsSync(path.join(fullPath, 'docker-compose.yml'))) {
|
|
386
|
-
deployMethod = 'docker_compose';
|
|
387
|
-
deployCmd = 'docker compose up -d --build';
|
|
388
|
-
}
|
|
389
|
-
else if (fs.existsSync(path.join(fullPath, '.git'))) {
|
|
390
|
-
deployMethod = 'git_push';
|
|
391
|
-
deployCmd = 'git push origin HEAD';
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
catch { }
|
|
395
|
-
// 3. Detect Live URL
|
|
396
|
-
try {
|
|
397
|
-
for (const docFile of ['CLAUDE.md', 'AGENTS.md', 'README.md', '.env']) {
|
|
398
|
-
const docPath = path.join(fullPath, docFile);
|
|
399
|
-
if (fs.existsSync(docPath)) {
|
|
400
|
-
const text = fs.readFileSync(docPath, 'utf8').slice(0, 6000);
|
|
401
|
-
const urlMatch = text.match(/https:\/\/(?:www\.)?([a-z0-9-]+\.(?:com|ai|io|app|dev|org|net))\b/i);
|
|
402
|
-
if (urlMatch && !/github\.com|openai\.com|anthropic\.com|googleapis\.com|npmjs\.com|localhost/i.test(urlMatch[0])) {
|
|
403
|
-
liveUrl = urlMatch[0];
|
|
404
|
-
break;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
if (!liveUrl) {
|
|
409
|
-
const clean = name.toLowerCase().replace(/^nieuw\.games[-_]*/i, '');
|
|
410
|
-
if (/^[a-z0-9-]+\.(com|ai|io|app|dev|org|net)$/i.test(clean)) {
|
|
411
|
-
liveUrl = `https://${clean}`;
|
|
412
|
-
}
|
|
413
|
-
else if (clean === 'meerlink') {
|
|
414
|
-
liveUrl = 'https://meerlink.com';
|
|
415
|
-
}
|
|
416
|
-
else if (clean === 'werkinghard' || clean === 'workinghard') {
|
|
417
|
-
liveUrl = 'https://werkinghard.com';
|
|
418
|
-
}
|
|
419
|
-
}
|
|
417
|
+
catch {
|
|
418
|
+
return {
|
|
419
|
+
build_command: null,
|
|
420
|
+
deploy_method: null,
|
|
421
|
+
deploy_command: null,
|
|
422
|
+
live_url: null,
|
|
423
|
+
deploy_source: 'auto',
|
|
424
|
+
deploy_confidence: 'low',
|
|
425
|
+
deploy_evidence: '',
|
|
426
|
+
};
|
|
420
427
|
}
|
|
421
|
-
catch { }
|
|
422
|
-
return {
|
|
423
|
-
build_command: buildCmd,
|
|
424
|
-
deploy_method: deployMethod,
|
|
425
|
-
deploy_command: deployCmd,
|
|
426
|
-
live_url: liveUrl,
|
|
427
|
-
};
|
|
428
428
|
}
|
|
429
429
|
/**
|
|
430
430
|
* Scan the developer's local workspace roots (sibling folders in parent dev dir, ~/dev, ~/Projects, etc.)
|
|
@@ -496,12 +496,10 @@ export class AgileMonsterClient {
|
|
|
496
496
|
if (fs.existsSync(path.join(fullPath, '.git'))) {
|
|
497
497
|
try {
|
|
498
498
|
gitRemote =
|
|
499
|
-
execSync('git config --get remote.origin.url', {
|
|
499
|
+
stripRemoteCredentials(execSync('git config --get remote.origin.url', {
|
|
500
500
|
cwd: fullPath,
|
|
501
501
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
502
|
-
})
|
|
503
|
-
.toString()
|
|
504
|
-
.trim() || null;
|
|
502
|
+
}).toString()) || null;
|
|
505
503
|
}
|
|
506
504
|
catch { }
|
|
507
505
|
}
|
|
@@ -608,6 +606,26 @@ export class AgileMonsterClient {
|
|
|
608
606
|
body: JSON.stringify({ provider, tasks }),
|
|
609
607
|
});
|
|
610
608
|
}
|
|
609
|
+
async listComments(cardId) {
|
|
610
|
+
const res = await this.request(`/api/cards/${cardId}/comments`);
|
|
611
|
+
return Array.isArray(res) ? res : res?.comments || [];
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Tell the server how a deployment went so the board binding learns the verified route (or the failure).
|
|
615
|
+
* Older backends do not have this endpoint; that must never break a deployment.
|
|
616
|
+
*/
|
|
617
|
+
async reportDeployment(report) {
|
|
618
|
+
try {
|
|
619
|
+
await this.request('/api/agent/deploy-report', {
|
|
620
|
+
method: 'POST',
|
|
621
|
+
body: JSON.stringify({ ...report, mcp_version: MCP_SERVER_VERSION }),
|
|
622
|
+
});
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
625
|
+
catch {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
611
629
|
async autonomousStep(payload) {
|
|
612
630
|
return this.request('/api/agent/autonomous-step', {
|
|
613
631
|
method: 'POST',
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine-local deployment memory, one file per project folder.
|
|
3
|
+
*
|
|
4
|
+
* This is the feedback loop that was missing: every deployment attempt (from the daemon or reported
|
|
5
|
+
* by an IDE agent) is recorded here, so the next card starts from "what worked last time" instead of
|
|
6
|
+
* re-guessing — and a method that keeps failing because it does not apply gets demoted instead of retried.
|
|
7
|
+
*
|
|
8
|
+
* Lives in ~/.agilemonster/projects/ (never inside the repository, so it can never be committed).
|
|
9
|
+
*/
|
|
10
|
+
export interface DeployAttempt {
|
|
11
|
+
at: string;
|
|
12
|
+
card_id?: string | null;
|
|
13
|
+
method: string;
|
|
14
|
+
command?: string | null;
|
|
15
|
+
ok: boolean;
|
|
16
|
+
pending?: boolean;
|
|
17
|
+
kind?: string | null;
|
|
18
|
+
error?: string | null;
|
|
19
|
+
commit?: string | null;
|
|
20
|
+
duration_ms?: number;
|
|
21
|
+
reported_by?: string | null;
|
|
22
|
+
}
|
|
23
|
+
export interface MethodFailures {
|
|
24
|
+
count: number;
|
|
25
|
+
last_kind: string | null;
|
|
26
|
+
last_error: string | null;
|
|
27
|
+
last_at: string;
|
|
28
|
+
/** The failure says the method does not apply here (as opposed to a real deploy breaking). */
|
|
29
|
+
wrong_method: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** A deployment whose CI run had not finished when the daemon stopped waiting; re-checked on later pulses. */
|
|
32
|
+
export interface PendingVerification {
|
|
33
|
+
card_id: string;
|
|
34
|
+
card_title: string;
|
|
35
|
+
provider: string;
|
|
36
|
+
sha: string;
|
|
37
|
+
branch: string;
|
|
38
|
+
workflow_names: string[];
|
|
39
|
+
started_at: string;
|
|
40
|
+
run_url?: string | null;
|
|
41
|
+
}
|
|
42
|
+
/** What the agent changed for a card whose deployment has not succeeded (or not run) yet. */
|
|
43
|
+
export interface CardDeployState {
|
|
44
|
+
stage: 'deploy_failed' | 'awaiting_approval';
|
|
45
|
+
files: string[];
|
|
46
|
+
summary: string;
|
|
47
|
+
verification_steps: string;
|
|
48
|
+
diff: string;
|
|
49
|
+
commit: string | null;
|
|
50
|
+
at: string;
|
|
51
|
+
attempts: number;
|
|
52
|
+
last_error?: string | null;
|
|
53
|
+
/** Set when the agent asked "may I deploy with X?": a plain "yes"/"retry" then confirms X. */
|
|
54
|
+
pending_confirmation?: {
|
|
55
|
+
method: string;
|
|
56
|
+
command: string | null;
|
|
57
|
+
} | null;
|
|
58
|
+
}
|
|
59
|
+
export interface ProjectMemory {
|
|
60
|
+
project_path: string;
|
|
61
|
+
updated_at: string;
|
|
62
|
+
explicit?: {
|
|
63
|
+
method: string;
|
|
64
|
+
command?: string | null;
|
|
65
|
+
live_url?: string | null;
|
|
66
|
+
notes?: string | null;
|
|
67
|
+
set_by?: string | null;
|
|
68
|
+
set_at: string;
|
|
69
|
+
} | null;
|
|
70
|
+
last_success?: {
|
|
71
|
+
method: string;
|
|
72
|
+
command?: string | null;
|
|
73
|
+
live_url?: string | null;
|
|
74
|
+
at: string;
|
|
75
|
+
commit?: string | null;
|
|
76
|
+
card_id?: string | null;
|
|
77
|
+
} | null;
|
|
78
|
+
failures: Record<string, MethodFailures>;
|
|
79
|
+
history: DeployAttempt[];
|
|
80
|
+
pending: PendingVerification[];
|
|
81
|
+
cards: Record<string, CardDeployState>;
|
|
82
|
+
/**
|
|
83
|
+
* Cards this machine already shipped (kept apart from the rolling history, so approving a card long after
|
|
84
|
+
* its review-time deployment never looks like "not deployed yet" and triggers a second one).
|
|
85
|
+
*/
|
|
86
|
+
deployed_cards: Record<string, {
|
|
87
|
+
at: string;
|
|
88
|
+
commit: string | null;
|
|
89
|
+
method: string;
|
|
90
|
+
verified: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
}
|
|
93
|
+
export declare function memoryFileFor(projectPath: string): string;
|
|
94
|
+
/**
|
|
95
|
+
* Recover "how the last deployment worked" from the activity log earlier daemon versions wrote into the
|
|
96
|
+
* project (`.agilemonster/ACTIVITY.md`), so projects that already deployed successfully keep their route
|
|
97
|
+
* instead of starting from a fresh guess.
|
|
98
|
+
*/
|
|
99
|
+
export declare function parseLastDeploymentFromActivityLog(logText: string): {
|
|
100
|
+
method: string;
|
|
101
|
+
command: null;
|
|
102
|
+
} | null;
|
|
103
|
+
export declare function loadMemory(projectPath: string): ProjectMemory;
|
|
104
|
+
export declare function saveMemory(memory: ProjectMemory): void;
|
|
105
|
+
/** Record the outcome of an attempt and update what the project "knows" about its own deployment. */
|
|
106
|
+
export declare function recordAttempt(projectPath: string, attempt: Omit<DeployAttempt, 'at'> & {
|
|
107
|
+
live_url?: string | null;
|
|
108
|
+
wrong_method?: boolean;
|
|
109
|
+
/** The change went out but nothing could confirm the deployment (no CI run found, `gh` unavailable). */
|
|
110
|
+
unverified?: boolean;
|
|
111
|
+
}): ProjectMemory;
|
|
112
|
+
export declare function setExplicitProfile(projectPath: string, explicit: {
|
|
113
|
+
method: string;
|
|
114
|
+
command?: string | null;
|
|
115
|
+
live_url?: string | null;
|
|
116
|
+
notes?: string | null;
|
|
117
|
+
set_by?: string | null;
|
|
118
|
+
}): ProjectMemory;
|
|
119
|
+
export declare function setCardState(projectPath: string, cardId: string, state: CardDeployState | null): void;
|
|
120
|
+
export declare function getCardState(projectPath: string, cardId: string): CardDeployState | null;
|
|
121
|
+
export declare function addPendingVerification(projectPath: string, pending: PendingVerification): void;
|
|
122
|
+
export declare function removePendingVerification(projectPath: string, cardId: string): void;
|